About

Einführung in das Business Prototyping Toolkit

Die Schlüsselkomponenten des Business Prototyping Toolkit und die Erstellung von System Dynamics Modellen, agentenbasierten Modellen und hybriden Modellen anhand eines einfachen Beispiels.
  • Oliver Grasl
    Oliver Grasl
    17.08.2021
Eine Vorstellung der Komponenten des Business Prototyping Toolkits und Veranschaulichung der Erstellung von System Dynamics Modellen, agentenbasierten Modellen und hybriden Modellen anhand eines einfachen Beispiels
Das Business Prototyping Toolkit (BPTK) ist ein computational Modellierungs-Framework, mit dem Sie Simulationsmodelle unter Verwendung von System Dynamics (SD) und/oder agentenbasierte Modelling (ABM) erstellen und Simulationsszenarien mühelos managen können.
Der Rahmen wird für die Erstellung von Modellen von Märkten, Geschäftsmodellen, Organisationen und ganzen Geschäftsökosystemen verwendet. Es kann sowohl für kleine, explorative Modelle (wie hier dargestellt) als auch für große Modelle mit Hunderttausenden von Gleichungen verwendet werden.
Das Leitprinzip des Frameworks besteht darin, dem Modellierer die Möglichkeit zu geben, sich auf die Erstellung von Simulationsmodellen zu konzentrieren, indem eine nahtlose Schnittstelle für das Management von Modelleinstellungen und Szenarien sowie für die Darstellung von Simulationsergebnissen bereitgestellt wird. Es verfolgt einen "minimalistischen" Ansatz und bietet nur die notwendigen Modellierungs- und Simulationsfunktionen. Für alles andere werden Standard-Open-Source-Pakete verwendet. Insbesondere wird auf Umgebungen wie Jupyter zurückgegriffen, um die Darstellung und interaktive Dashboards zu ermöglichen.
  • Alle Darstellungen werden mit Matplotlib vorgenommen.
  • Die Simulationsergebnisse werden als Pandas DataFrames zurückgegeben.
  • Numerik über NumPy und SciPy.
Modelleinstellungen und Szenarien werden in JSON-Dateien gespeichert. Diese Einstellungen werden bei der Initialisierung automatisch vom Framework geladen, ebenso wie die Modellklassen selbst. Dies macht die interaktive Modellierung, Codierung und Prüfung sehr einfach, insbesondere bei Verwendung der Jupyter-Notebook-Umgebung.
Neben einer Jupyter-Notebook-Version dieses Notebooks online und fortgeschrittenen Tutorials und Beispielen auf GitHub finden Sie auch eine umfangreiche Dokumentation online.

Wichtige Komponenten des Business Prototyping Toolkit

Das Toolkit ist seit 2018 verfügbar und bietet mittlerweile Modellierung in Python für agentenbasierte Modellierung (ABM), systemdynamische Modellierung (SD) und hybride Modellierung mit SD und ABM.
Es gibt auch Unterstützung für den Import von XMILE-Modellen, die mit externen Modellierungsumgebungen erstellt wurden, wie z.B. isee systems Stella Architect oder iThink Modellierungsumgebungen.
Sobald Sie ein Modell haben, können Sie verschiedene Simulationsszenarien definieren und managen, die Ergebnisse dieser Szenarien darstellen und interaktive Dashboards erstellen.
Das Framework bietet auch einen einfachen REST API Server, mit dem Sie Modelle mithilfe von Webtechnologie leicht bereitstellen und abfragen können. Sie können dann die BPTK Widget Bibliothek verwenden, um Web-Dashboards zu erstellen.
Meetup: Building Web-based Simulations using BPTK Image 1
Sie können ein Beispiel-Dashboard zur Darstellung verschiedener COVID-Szenarien online ansehen. Die Repositories für das Dashboard und die Simulation sind auf GitHub verfügbar.

Beispielmodell: Simulation der Kundenakquise anhand des Bass-Diffusionsmodells

Um die verschiedenen Möglichkeiten der Erstellung von Simulationsmodellen mit BPTK zu veranschaulichen, werden wir ein einfaches Modell der Kundenakquisition, das sogenannte Bass-Diffusionsmodell, verwenden. Es beschreibt den Prozess, wie neue Produkte oder Dienstleistungen von den Verbrauchern angenommen werden.
Wir werden das Modell unter Verwendung der System Dynamics DSL, der agentenbasierten Modellierung, eines hybriden ABM- und SD-DSL-Modells und eines XMILE erstellen.
Die Grundstruktur des Modells ist in dem folgenden Kausalschleifendiagramm dargestellt:
Introduction to BPTK Blog Post Image 2 DE

Aufbau des Kundenakquisitionsmodells mit SD DSL

Auf der Grundlage des Kausalschleifendiagramms werden wir ein Bestands- und Flussmodell mit den folgenden Beständen, Flüssen, Konvertern und Konstanten implementieren:
Introduction to Business Prototyping Toolkit Blog post Graph 3

Aufbau des Modells

Die Einrichtung des Modells mit der SD DSL ist recht einfach. Zunächst wird eine Modellklasse instanziiert, die als Container für die Modellelemente dient. Dadurch wird sichergestellt, dass Sie mehrere Modelle parallel ausführen können.
from BPTK_Py import Model
from BPTK_Py import sd_functions as sd
model = Model(starttime=1.0,stoptime=60.0, dt=1.0, name="Customer Acquisition SDDSL")
# stocks
customers = model.stock("customers")
potential_customers = model.stock("potential_customers")
#flows
customer_acquisition=model.flow("customer_acquisition")
#converters
acquisition_through_advertising = model.converter("acquisition_through_advertising")
acquisition_through_word_of_mouth = model.converter("acquisition_through_word_of_mouth")
consumers_reached_through_advertising = model.converter("consumers_reached_through_advertising")
consumers_reached_through_word_of_mouth= model.converter("consumers_reached_through_word_of_mouth")
market_saturation = model.converter("market_saturation")
#constants
initial_customers = model.constant("initial_customers") 
initial_potential_customers = model.constant("initial_potential_customers") 
advertising_success = model.constant("advertising_success")
consumers_reached_per_euro = model.constant("consumers_reached_per_ruro")
advertising_budget = model.constant("advertising_budget")
word_of_mouth_success = model.constant("word_of_mouth_success")
contact_rate = model.constant("contact_rate")
Nachdem wir nun alle Modellelemente definiert haben, müssen wir die eigentlichen Gleichungen definieren. Das Schöne daran ist, dass wir diese Gleichungen direkt mit den Modellelementen schreiben können.
#equations
customers.equation = customer_acquisition
potential_customers.equation = -customer_acquisition
customer_acquisition.equation=sd.min(potential_customers,acquisition_through_advertising+acquisition_through_word_of_mouth)
acquisition_through_advertising.equation = advertising_success*consumers_reached_through_advertising
consumers_reached_through_advertising.equation = consumers_reached_per_euro*advertising_budget*(1-market_saturation)
market_saturation.equation = customers/(customers+potential_customers)
acquisition_through_word_of_mouth.equation = word_of_mouth_success*consumers_reached_through_word_of_mouth
consumers_reached_through_word_of_mouth.equation=contact_rate*customers*(1-market_saturation)
Wir müssen auch die Bestände initialisieren und die Konstanten festlegen.
#initialize model
customers.initial_value=initial_customers
potential_customers.initial_value=initial_potential_customers
initial_customers.equation = 0.0
initial_potential_customers.equation = 60000.0
advertising_success.equation = 0.1
consumers_reached_per_euro.equation = 100.0
advertising_budget.equation = 100.0
word_of_mouth_success.equation = 0.01
contact_rate.equation = 10.0
Das Modell ist nun vollständig und wir können das Verhalten der Modellelemente im Laufe der Zeit direkt aufzeichnen:
customers.plot()
Introduction to The Business Prototyping Toolkit Graph 4
Natürlich können Sie auch auf den zugrunde liegenden Pandas-Datenrahmen zugreifen:
customers.plot(return_df=True)[1:10]
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
    .dataframe tbody tr th {
        vertical-align: top;
    }
    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>customers</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1.0</th>
      <td>0.000000</td>
    </tr>
    <tr>
      <th>2.0</th>
      <td>1000.000000</td>
    </tr>
    <tr>
      <th>3.0</th>
      <td>2081.666667</td>
    </tr>
    <tr>
      <th>4.0</th>
      <td>3247.916662</td>
    </tr>
    <tr>
      <th>5.0</th>
      <td>4500.994779</td>
    </tr>
    <tr>
      <th>6.0</th>
      <td>5842.312754</td>
    </tr>
    <tr>
      <th>7.0</th>
      <td>7272.284453</td>
    </tr>
    <tr>
      <th>8.0</th>
      <td>8790.164623</td>
    </tr>
    <tr>
      <th>9.0</th>
      <td>10393.900018</td>
    </tr>
    <tr>
      <th>10.0</th>
      <td>12080.003090</td>
    </tr>
  </tbody>
</table>
</div>
Zu Debugging-Zwecken kann es nützlich sein, einen Blick auf die internat-Darstellung der Modellgleichungen zu werfen - diese sind als Python-Lambda-Funktionen gespeichert.
customers.function_string
  
"lambda model, t : ( (model.memoize('initial_customers',t))
if
(t <= model.starttime) else (model.memoize('customers',t-model.dt))+ model.dt*(model.memoize('customer_acquisition',t-model.dt)) )"
customer_acquisition.function_string
    "lambda model, t : max( 0,min( model.memoize('potential_customers',t), model.memoize('acquisition_through_advertising',t)+model.memoize('acquisition_through_word_of_mouth',t)))"

Einrichten von Szenarien

Szenarien sind lediglich bestimmte Einstellungen für die Konstanten und grafischen Funktionen in Ihrem Modell, und Szenario-Manager sind eine einfache Möglichkeit, Szenarien zu gruppieren.
Sie können Szenarien direkt in Python erstellen (was wir hier tun werden), aber der einfachste Weg, sie zu pflegen, ist, sie in separaten JSON-Dateien aufzubewahren - Sie können so viele Szenario-Manager und Szenarien in einer Datei definieren, wie Sie möchten, und so viele Dateien verwenden, wie Sie möchten.
Jeder Szenario-Manager verweist auf das Modell, auf das er sich bezieht. Sie können also mehrere Simulationsmodelle in einem Notizbuch ausführen.
Alle Szenariodefinitionsdateien werden im Ordner
scenarios/
aufbewahrt. Das BPTK_Py-Framework durchsucht diesen Ordner automatisch und lädt die Szenarien - einschließlich der zugrunde liegenden Simulationsmodelle - in den Speicher.
scenario_manager={
    "sddsl_customer_acquisition":{
        "model":model,
        "base_constants":{
            "initial_customers" : 0.0,
            "initial_potential_customers" : 60000.0,
            "advertising_success": 0.1,
            "consumers_reached_per_euro" : 100.0,
            "advertising_budget" : 100.0,
            "word_of_mouth_success": 0.01,
            "contact_rate" : 10.0
        }
    }
}
Um die Szenarien zu managen, müssen Sie die Klasse bptk instanziieren - diese Klasse speichert die Szenario-Manager und Szenarien und bietet viele praktische Funktionen zum Darstellen von Daten, Exportieren von Modellergebnissen oder Importieren von Daten.
import BPTK_Py
bptk = BPTK_Py.bptk()
bptk.register_scenario_manager(scenario_manager)
Ein praktisches Merkmal von Szenarien ist, dass Sie nur Variablen definieren müssen, die sich ändern - im Wesentlichen übernimmt der Szenario-Manager zunächst die im Modell selbst festgelegten Konstanten und überschreibt sie dann mit den Einstellungen aus dem Szenario.
bptk.register_scenarios(
    
    scenario_manager="sddsl_customer_acquisition",
    scenarios=
    {
        "base":{
            
        },
        "low_word_of_mouth":{
            "constants":{
                "word_of_mouth_success":0.001
            }
        },
       
"high_word_of_mouth":{
            "constants":{
                "word_of_mouth_success":0.1
            }
        },
        "interactive_scenario":{}
        
    }
    
)
bptk.plot_scenarios(
    scenario_managers=["sddsl_customer_acquisition"],
    scenarios=["base","low_word_of_mouth","high_word_of_mouth"],
    equations=["customers"],
    series_names={
        "sddsl_customer_acquisition_base_customers":"Base",
        "sddsl_customer_acquisition_low_word_of_mouth_customers":"Low Word of Mouth",
        "sddsl_customer_acquisition_high_word_of_mouth_customers":"High Word of Mouth",
    }
)
Introduction to The Business Prototyping Toolkit Blog Post Graph 5
bptk.get_scenario_names([],format="dict") {'xmile_customer_acquisition': ['base',       'low_word_of_mouth',       'high_word_of_mouth'],      'sddsl_customer_acquisition': ['base',       'low_word_of_mouth',       'high_word_of_mouth',       'interactive_scenario']}

Aufbau einer interaktiven UI

Es ist einfach, interaktive Dashboards in Jupyter mit IPywidgets zu erstellen - alles, was Sie von BPTK brauchen, ist die Fähigkeit, Graphen zu zeichnen.
%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import ipywidgets as widgets
customerTab = widgets.Output()
customerAcquisitionTab = widgets.Output()
scenariosTab = widgets.Output()
tabs = widgets.Tab(children = [customerTab, customerAcquisitionTab,scenariosTab])
tabs.set_title(0, 'Customers')
tabs.set_title(1, 'Customer Acquisition')
tabs.set_title(2, 'Scenarios')
display(tabs)
@interact(word_of_mouth_success=widgets.FloatSlider(
    value=0.01,
    min=0.001,
    max=0.1,
    step=0.001,
    continuous_update=False,
    description='Word Of Mouth Success'
))
def dashboardWithTabs(word_of_mouth_success):
    scenario= bptk.get_scenario("sddsl_customer_acquisition","interactive_scenario")
    
    scenario.constants["word_of_mouth_success"]=word_of_mouth_success
    bptk.reset_scenario_cache(scenario_manager="sddsl_customer_acquisition",
                                                             scenario="interactive_scenario")
with customerTab:
# turn of pyplot's interactive mode to ensure the plot is not created directly
        plt.ioff()
        # clear the widgets output ... otherwise we will end up with a long list of plots, one for each change of settings
        customerTab.clear_output()
        # create the plot, but don't show it yet
        bptk.plot_scenarios(
            scenario_managers=["sddsl_customer_acquisition"],
            scenarios=["interactive_scenario"],
            equations=['customers'],
            title="Customers",
            freq="M",
            x_label="Time",
            y_label="No. of Customers"
            )
        # show the plot
        plt.show()
        # turn interactive mode on again
        plt.ion()
    with customerAcquisitionTab:
        plt.ioff()
        customerAcquisitionTab.clear_output()
        bptk.plot_scenarios(
            scenario_managers=["sddsl_customer_acquisition"],
            scenarios=["interactive_scenario"],
            equations=['customer_acquisition'],
            title="Customer Acquisition",
            freq="M",
            x_label="Time",
            y_label="No. of Customers"
            )
        plt.show()
        plt.ion()
    
    with scenariosTab:
        plt.ioff()
        scenariosTab.clear_output()
        bptk.plot_scenarios(
            scenario_managers=["sddsl_customer_acquisition"],
            scenarios=["base","low_word_of_mouth","high_word_of_mouth","interactive_scenario"],
            equations=["customers"],
            series_names={
                "sddsl_customer_acquisition_base_customers":"Base",
                "sddsl_customer_acquisition_interactive_scenario_customers":"Interactive",
                "sddsl_customer_acquisition_low_word_of_mouth_customers":"Low Word of Mouth",
                "sddsl_customer_acquisition_high_word_of_mouth_customers":"High Word of Mouth",
        }),
        plt.show()
        plt.ion()
Tab(children=(Output(), Output(), Output()), _titles={'0': 'Customers', '1': 'Customer Acquisition', '2': 'Sce...
    interactive(children=(FloatSlider(value=0.01, continuous_update=False, description='Word Of Mouth Success', ma...
Introduction to the business prototyping toolkit screenshot
HINWEIS: Vor allem bei größeren Modellen ist es viel besser, das Modell und die Szenariendefinitionen in getrennten Dateien zu halten, was natürlich auch möglich ist. In der Online-Dokumentation und dem ausführlichen Tutorial finden Sie Illustrationen, wie dies gemacht werden kann.

Kundenakquise durch agentenbasierte Modellierung

Das Grundkonzept von agentenbasierten Modellen ist recht einfach: Sie bevölkern eine Umgebung (das Modell) mit einer Reihe von Agenten. Die Agenten und die Umgebung haben jeweils eine Reihe von Eigenschaften und jeder Agent muss sich immer in einem bestimmten Zustand befinden.
Agenten können Aktionen durchführen und untereinander und mit der Umgebung interagieren, indem sie sich gegenseitig Ereignisse senden - die Agenten reagieren auf diese Ereignisse, indem sie ihre Eigenschaften aktualisieren und/oder ihren Zustand ändern.
Introduction to The Business Prototyping Toolkit Blog post Graph 6
Um einen Agenten mit Python und dem BPTK-Framework zu erstellen, müssen Sie also nur Folgendes tun:
  • die relevanten Agenten zu identifizieren
  • die Eigenschaften der Agenten definieren
  • für jeden Agenten ist ein Initialisierungsprogramm zu implementieren, das den Anfangszustand des Agenten festlegt
  • die Handler für jede Art von Ereignis definieren, auf die Ihr Agent reagieren soll
  • eine Aktionsmethode zu definieren, die beschreibt, was der Agent in jedem Zeitschritt tut, z. B. interne Aufgaben ausführen und Ereignisse an andere Agenten senden
Die Definition des Modells ist noch einfacher:
  • Definition der Umgebungseigenschaften und ggf. deren Aktualisierung
  • Dem Modell mitteilen, welche Arten von Agenten es gibt
  • Um die Simulation zu konfigurieren, müssen wir dann nur noch die Anfangswerte der Eigenschaften festlegen und die ersten Agenten instanziieren. Jede einzigartige Konfiguration eines Modells wird als Szenario bezeichnet. Das BPTK-Framework hilft Ihnen, verschiedene Szenarien zu managen und die Ergebnisse einfach zu vergleichen.
Die Konfiguration von agentenbasierten Modellen erfolgt am besten über eine in JSON definierte Konfigurationsdatei.
Die agentenbasierte Modellierung ist ein sehr leistungsfähiger Ansatz, und Sie können mit ABM Modelle erstellen, die Sie mit SD nicht erstellen können. Diese Leistung hat jedoch ihren Preis: Da jeder Agent als individuelle Einheit modelliert wird, sind agentenbasierte Modelle recht langsam.

Das Modell einrichten

Für das Modell der Kundenakquise brauchen wir eigentlich nur zwei Agenten: das Unternehmen, das Werbeereignisse sendet, und die Verbraucher, die diese Ereignisse empfangen. Wenn ein Verbraucher zum Kunden wird, beginnt er, Mundpropaganda-Ereignisse zu senden.
Dies wird in der folgenden Graphik veranschaulicht:
Introduction to The Business Prototyping Toolkit Blog post Graph 7
Beachten Sie, dass das Werbebudget und die Kontaktrate Eigenschaften der jeweiligen Agenten sind - dies ist ein kleiner Einblick in die Möglichkeiten der agentenbasierten Modellierung, denn wir könnten problemlos individuelle Kontaktraten für die Verbraucher festlegen oder mehrere Unternehmen haben, die für konkurrierende Produkte werben. All diese Aspekte können nicht einfach mit System Dynamics modelliert werden.
from BPTK_Py import Model
from BPTK_Py import sd_functions as sd
from BPTK_Py import Agent
from BPTK_Py import Model
from BPTK_Py import Event
from BPTK_Py import DataCollector
from BPTK_Py import SimultaneousScheduler
Das Einrichten von Agenten ist eigentlich ganz einfach - Sie müssen lediglich Handler für die Ereignisse registrieren und die Methode
`act`
definieren.
class Consumer(Agent):
    def initialize(self):
        self.agent_type = "consumer"
        self.state = "potential"
       self.register_event_handler(["potential"],"advertising_event",self.handle_advertising_event)
       self.register_event_handler(["potential"],"word_of_mouth_event",self.handle_word_of_mouth_event)
        
    def handle_advertising_event(self,event):
        if self.is_event_relevant(self.model.advertising_success):
            self.state="customer"
    
    def handle_word_of_mouth_event(self, event):
        if self.is_event_relevant(self.model.word_of_mouth_success):
            self.state="customer"
                
    def act(self,time,round_no,step_no):
        # consumers who are customers generate word of mouth events
        if self.state == "customer":
            self.model.random_events(
                "consumer",
self.contact_rate,
                lambda agent_id: Event("word_of_mouth_event", self.id, agent_id)
            )
Beachten Sie, dass der unten definierte Unternehmensagent auf die Eigenschaften
`advertising_budget`
und
`consumers_reacher_per _euro`
zugreift. Diese Eigenschaften werden in den Szenarien definiert und können dann "auf magische Weise" entweder als Agenteneigenschaften oder als Modelleigenschaften aufgerufen werden.
class Company(Agent):
    def initialize(self):
            self.agent_type="company"
            self.state = "active"
    
    def act(self,time,round_no,step_no):
        self.model.random_events(
            "consumer",
            self.advertising_budget*self.model.consumers_reached_per_euro,
            lambda agent_id: Event("advertising_event",self.id, agent_id)
        )
Das Modell selbst benötigt eine Möglichkeit, Agenten zu instanziieren - dafür registrieren Sie Agentenfabriken, die einen Agenten eines bestimmten Typs zurückgeben. In ihrer einfachsten Form ist eine Agentenfabrik einfach eine Lambda-Funktion.
class CustomerAcquisitionAbm(Model):
    def instantiate_model(self):
        self.register_agent_factory("consumer", lambda agent_id,model,properties: Consumer(agent_id, model,properties))
        self.register_agent_factory("company", lambda agent_id,model, properties: Company(agent_id, model, properties))
customer_acquisition_abm=CustomerAcquisitionAbm(1,60,dt=1,name="Customer Acquisition Agent-based Model",scheduler=SimultaneousScheduler(),data_collector=DataCollector())
customer_acquisition_abm.instantiate_model()
customer_acquisition_abm_config =  {
             "runspecs": {
                  "starttime": 1,
                  "stoptime":60,
                  "dt": 1.0
            },
            "properties":
            {
                "word_of_mouth_success":
                {
                    "type":"Double",
                    "value":0.01
                },
                "advertising_success":
                {
                    "type":"Double",
                    "value":0.1
                },
                "consumers_reached_per_euro":
                {
                    "type":"Integer",
                    "value":100
                }
                
            },
            "agents":
            [
                {
                    "name":"company",
                    "count":1,
                    "properties":{
                         "advertising_budget":
                        {
                            "type":"Integer",
                            "value":100
                        }
                    }
                },
                {
                    "name":"consumer",
                    "count":60000,
                    "properties":{
                        "contact_rate":
                        {
                        "type":"Integer",
                        "value":10
                        }
                    }
                        
                }
            ]
        }
customer_acquisition_abm.configure(customer_acquisition_abm_config)
HINWEIS: Die Ausführung des agentenbasierten Modells nimmt etwas Zeit in Anspruch, ca. 3 Minuten auf meinem Rechner.
customer_acquisition_abm.run()
[customer_acquisition_abm.statistics().get(1.0*key) for key in range(1,5)]
    [{'company': {'active': {'count': 1,
        'advertising_budget': {'total': 100,
         'max': 100,
         'min': 100,
         'mean': 100.0}}},
      'consumer': {'potential': {'count': 60000,
        'contact_rate': {'total': 600000, 'max': 10, 'min': 10, 'mean': 10.0}}}},
     {'company': {'active': {'count': 1,
        'advertising_budget': {'total': 100,
         'max': 100,
         'min': 100,
         'mean': 100.0}}},
      'consumer': {'potential': {'count': 58982,
        'contact_rate': {'total': 589820, 'max': 10, 'min': 10, 'mean': 10.0}},
       'customer': {'count': 1018,
        'contact_rate': {'total': 10180, 'max': 10, 'min': 10, 'mean': 10.0}}}},
     {'company': {'active': {'count': 1,
        'advertising_budget': {'total': 100,
         'max': 100,
         'min': 100,
         'mean': 100.0}}},
      'consumer': {'potential': {'count': 57881,
        'contact_rate': {'total': 578810, 'max': 10, 'min': 10, 'mean': 10.0}},
       'customer': {'count': 2119,
        'contact_rate': {'total': 21190, 'max': 10, 'min': 10, 'mean': 10.0}}}},
     {'company': {'active': {'count': 1,
        'advertising_budget': {'total': 100,
         'max': 100,
         'min': 100,
         'mean': 100.0}}},
      'consumer': {'potential': {'count': 56717,
        'contact_rate': {'total': 567170, 'max': 10, 'min': 10, 'mean': 10.0}},
       'customer': {'count': 3283,
        'contact_rate': {'total': 32830, 'max': 10, 'min': 10, 'mean': 10.0}}}}]

Einrichten von Szenarien

Der Szenariomechanismus funktioniert für SD DSL, agentenbasierte und hybride Modelle genau gleich. Damit ist sichergestellt, dass Sie verschiedene Modelle laden und die Ergebnisse vergleichen können!
import BPTK_Py
bptk = BPTK_Py.bptk()
customer_acquisition_abm.reset()
abm_scenario_manager={
    "abm_customer_acquisition":{
        "name":"abm_customer_acquisition",
        "type":"abm",
        "model":customer_acquisition_abm,
        "scenarios":{
            "base":
        {
             "runspecs": {
                  "starttime": 1,
                  "stoptime":60,
                  "dt": 1.0
            },
            "properties":
            {
                "word_of_mouth_success":
                {
                    "type":"Double",
                    "value":0.01
                },
                "advertising_success":
                {
                    "type":"Double",
                    "value":0.1
                },
                "consumers_reached_per_euro":
                {
                    "type":"Integer",
                    "value":100
                }
                
            },
            "agents":
            [
                {
                    "name":"company",
                    "count":1,
                    "properties":{
                         "advertising_budget":
                        {
                            "type":"Integer",
                            "value":100
                        }
                    }
                },
                {
                    "name":"consumer",
                    "count":60000,
                    "properties":{
                         "contact_rate":
                         {
                            "type":"Integer",
                            "value":10
                        }
                        
                    }
                }
            ]
        }
        }
    }
    
    
}
bptk.register_scenario_manager(abm_scenario_manager)
bptk.plot_scenarios(
    scenario_managers=["abm_customer_acquisition"],
    scenarios=["base"],
    agents=["consumer"],
    agent_states=["customer"],
    progress_bar=True
)
Output()
Introduction to The Business Prototyping Toolkit Blog post Graph 8
HINWEIS: Vor allem bei größeren Modellen ist es viel besser, das Modell und die Szenariodefinitionen in getrennten Dateien zu speichern, was natürlich auch möglich ist. In der Online-Dokumentation und in einem ausführlichen Tutorial wird gezeigt, wie dies gemacht werden kann.

Das Beste aus beiden Welten: Hybride ABM- und SD-Modelle

Hybride Modelle sind agentenbasierte Modelle, die ein System Dynamics el "enthalten". Die Agenten können die Elemente des SD-Modells aufrufen. Die Elemente des SD-Modells können auch Eigenschaften des agentenbasierten Modells über benutzerdefinierte SD-Funktionen aufrufen.

Einrichten vom Modell

from BPTK_Py import Model
from BPTK_Py import sd_functions as sd
from BPTK_Py import Agent
from BPTK_Py import Model
from BPTK_Py import Event
from BPTK_Py import DataCollector
from BPTK_Py import SimultaneousScheduler
class Customer(Agent):
    def initialize(self):
        self.agent_type = "customer"
        self.state = "active"
Der folgende Code veranschaulicht, wie man ein System Dynamics Modell als Python-Klasse einrichtet.
class CustomerAcquisitionSD():
    def __init__(self,model):
        self.model = model
        
        # stocks
        self.customers = model.stock("customers")
        
        #flows
        self.customer_acquisition=model.flow("customer_acquisition")
        
        #converters
        self.acquisition_through_advertising = model.converter("acquisition_through_advertising")
        self.acquisition_through_word_of_mouth = model.converter("acquisition_through_word_of_mouth")
        self.consumers_reached_through_advertising = model.converter("consumers_reached_through_advertising")
        self.consumers_reached_through_word_of_mouth= model.converter("consumers_reached_through_word_of_mouth")
        self.market_saturation = model.converter("market_saturation")
        
        #constants
        self.initial_customers = model.constant("initial_customers") 
        self.target_market= model.constant("target_market")
        self.advertising_success = model.constant("advertising_success")
        self.consumers_reached_per_euro = model.constant("consumers_reached_per_ruro")
        self.advertising_budget = model.constant("advertising_budget")
        self.word_of_mouth_success = model.constant("word_of_mouth_success")
        self.contact_rate = model.constant("contact_rate")
        
        #equations
        self.customers.equation = self.customer_acquisition
       self.customer_acquisition.equation=self.acquisition_through_advertising+self.acquisition_through_word_of_mouth
        self.acquisition_through_advertising.equation = self.advertising_success*self.consumers_reached_through_advertising
        self.consumers_reached_through_advertising.equation = self.consumers_reached_per_euro*self.advertising_budget*(1-self.market_saturation)
        self.market_saturation.equation = self.customers/self.target_market
        self.acquisition_through_word_of_mouth.equation = self.word_of_mouth_success*self.consumers_reached_through_word_of_mouth
       self.consumers_reached_through_word_of_mouth.equation=self.contact_rate*self.customers*(1-self.market_saturation)
#initialize model
        self.customers.initial_value=self.initial_customers
        self.initial_customers.equation = 0.0
        self.target_market.equation = 60000.0
        self.advertising_success.equation = 0.1
        self.consumers_reached_per_euro.equation = 1.0
        self.advertising_budget.equation = 100.0
        self.word_of_mouth_success.equation = 0.01
        self.contact_rate.equation = 1.0
        
class CustomerAcquisitionHybrid(Model):
    def instantiate_model(self):
        super().instantiate_model()
        # register agent factories
        self.register_agent_factory("customer", lambda agent_id,model,properties: Customer(agent_id, model,properties))
        
        # set up the sd model - keep it in its own class so we can use the SD DSL
         
        self.sd_model = CustomerAcquisitionSD(self)
      
    def configure(self,config):
        super().configure(config)
        
        ## the config sets the model properties, which we need to set the initial values of the sd model
        self.sd_model.target_market.equation = self.target_market
        self.sd_model.advertising_success.equation = self.advertising_success
        self.sd_model.consumers_reached_per_euro.equation = self.consumers_reached_per_euro
        self.sd_model.advertising_budget.equation = self.advertising_budget
        self.sd_model.word_of_mouth_success.equation = self.word_of_mouth_success
        self.sd_model.contact_rate.equation = self.contact_rate
        
        
    def begin_round(self, time, sim_round, step):
        # at the beginning of each round we check to see how many customers we should have according to the
        # SD model and then create the right number of agents.
        
        required_num_customers = int(self.evaluate_equation("customers",time))
        current_num_customers = self.agent_count("customer")
        agents_needed = required_num_customers-current_num_customers
        self.create_agents({"name":"customer","count":agents_needed})           
        
customer_acquisition_hybrid=CustomerAcquisitionHybrid(1,60,dt=1,name="Customer Acquisition Hybrid",scheduler=SimultaneousScheduler(),data_collector=DataCollector())
customer_acquisition_hybrid.instantiate_model()
customer_acquisition_hybrid_config =  {
             "runspecs": {
                  "starttime": 1,
                  "stoptime":60,
                  "dt": 1.0
            },
            "properties":
            {
                 "word_of_mouth_success":
                {
                    "type":"Double",
                    "value":0.01
                },
                "advertising_success":
                {
                    "type":"Double",
                    "value":0.1
                },
                "consumers_reached_per_euro":
                {
                    "type":"Double",
                    "value":100.0
                },
                "advertising_budget":
                {
                    "type":"Double",
                    "value":100.0
                },
                "contact_rate":
                {
                    "type":"Double",
                    "value":10.0
                },
                "target_market":
                {
                    "type":"Double",
                    "value":60000.0
                }
                
            },
            "agents":
            [
                {
                    "name":"customer",
                    "count":0
                }
            ]
        }
customer_acquisition_hybrid.configure(customer_acquisition_hybrid_config)
customer_acquisition_hybrid.run()
[customer_acquisition_hybrid.statistics().get(1.0*key) for key in range(2,10)]
    [{'customer': {'active': {'count': 1000}}},
     {'customer': {'active': {'count': 2081}}},
     {'customer': {'active': {'count': 3247}}},
     {'customer': {'active': {'count': 4500}}},
     {'customer': {'active': {'count': 5842}}},
     {'customer': {'active': {'count': 7272}}},
     {'customer': {'active': {'count': 8790}}},
     {'customer': {'active': {'count': 10393}}}]

Einrichten von Szenarien

import BPTK_Py
bptk = BPTK_Py.bptk()
customer_acquisition_hybrid.reset()
hybrid_scenario_manager={
    "hybrid_customer_acquisition":{
        "name":"hybrid_customer_acquisition",
        "type":"abm",
        "model":customer_acquisition_hybrid,
        "scenarios":{
            "base":
           {
             "runspecs": {
                  "starttime": 1,
                  "stoptime":60,
                  "dt": 1.0
            },
            "properties":
            {
                 "word_of_mouth_success":
                {
                    "type":"Double",
                    "value":0.01
                },
                "advertising_success":
                {
                    "type":"Double",
                    "value":0.1
                },
                "consumers_reached_per_euro":
                {
                    "type":"Double",
                    "value":100.0
                },
                "advertising_budget":
                {
                    "type":"Double",
                    "value":100.0
                },
                "contact_rate":
                {
                    "type":"Double",
                    "value":10.0
                },
                "target_market":
                {
                    "type":"Double",
                    "value":60000.0
                }
                
            },
            "agents":
            [
                {
                    "name":"customer",
                    "count":0
                }
                
            ]
        }
        }
    }   
}
bptk.register_scenario_manager(hybrid_scenario_manager)
bptk.plot_scenarios(
    scenario_managers=["hybrid_customer_acquisition"],
    scenarios=["base"],
    agents=["customer"],
    agent_states=["active"],
    progress_bar=True
)
Output()
Introduction to The Business Prototyping Toolkit Blog post Graph 9
HINWEIS: Vor allem bei größeren Modellen ist es viel besser, das Modell und die Szenariodefinitionen in getrennten Dateien zu speichern, was natürlich auch möglich ist. In der Online-Dokumentation und in einem ausführlichen Tutorial wird gezeigt, wie dies gemacht werden kann.

XMILE-Modell

Viele Modellierer ziehen es vor, Modelle mit visuellen Modellierungsumgebungen und nicht direkt im Code zu erstellen. Eine solche Umgebung ist Stella Architect. Mit Stella Architect können Sie System Dynamics Modelle visuell erstellen. Sie können sie dann mit BPTK in Python importieren und mit ihnen arbeiten, wie mit jedem anderen Modell auch.
Das Framework überträgt das XMILE-Modell automatisch neu, wenn Änderungen in der visuellen Modellierungsumgebung vorgenommen werden. Sie können also in Stella Architect modellieren und in Jupyter mit Szenarien experimentieren.
Transpilierte Modelle arbeiten eigenständig, so dass Sie sie unabhängig von der Modellierungsumgebung überall ausführen können.

Einrichten von Modell

So sieht unser Kundenakquisitionsmodell in Stella Architect aus:
Introduction to The Business Prototyping Toolkit Graph 10

Einrichten von Szenarien

Um mit XMILE-Modellen zu arbeiten, müssen wir lediglich eine Szenariodatei im Ordner scenarios einrichten.
Die Szenariodatei teilt dem Framework mit, wo das XMILE-Modell zu finden ist und welche Szenarien eingerichtet werden sollen.
In unserem Fall sieht die Datei wie folgt aus - der einzige Unterschied zur SD DSL-Szenariodefinition ist die Einbeziehung der XMILE-Quelle.
{
    "xmile_customer_acquisition":
    {
        "source":"simulation_models/customer_acquisition_xmile.stmx",
        "model":"simulation_models/customer_acquisition_xmile",
        "scenarios":
        {
          "base": { },
          
        "low_word_of_mouth":{
            "constants":{
                "wordOfMouthSuccess":0.001
            }
        },
        "high_word_of_mouth":{
            "constants":{
                "wordOfMouthSuccess":0.1
            }
        }
        }
    }
}
Sobald wir bptk instanziieren, sucht das Framework automatisch im Ordner scenarios nach Szenarien und lädt diese.
import BPTK_Py
bptk = BPTK_Py.bptk()
Wir wollen alle Szenarien und Gleichungen auflisten, die der Rahmen findet.
bptk.list_equations(scenario_managers=["xmile_customer_acquisition"],scenarios=[])
Available Equations:
    
Scenario Manager: xmile_customer_acquisition
    Scenario: base
    --------------------------
    stock:               customers
    flow:                customerAcquisition
    converter:      acquisitionThroughAdvertising
    converter:      acquisitionThroughWordOfMouth
    converter:      advertisingBudget
    converter:      advertisingSuccess
    converter:      consumersReachedPerEuro
    converter:      consumersReachedThroughAdvertising
    converter:      consumersReachedThroughWordOfMouth
    converter:      contactRate
    converter:      initialCustomers
    converter:      marketSaturation
    converter:      targetMarket
    converter:      wordOfMouthSuccess
     
    Scenario: low_word_of_mouth
    --------------------------
    stock:               customers
    flow:                customerAcquisition
    converter:      acquisitionThroughAdvertising
    converter:      acquisitionThroughWordOfMouth
    converter:      advertisingBudget
    converter:      advertisingSuccess
    converter:      consumersReachedPerEuro
    converter:      consumersReachedThroughAdvertising
    converter:      consumersReachedThroughWordOfMouth
    converter:      contactRate
    converter:      initialCustomers
    converter:      marketSaturation
    converter:      targetMarket
    converter:      wordOfMouthSuccess
     
    Scenario: high_word_of_mouth
    --------------------------
    stock:               customers
    flow:                customerAcquisition
    converter:      acquisitionThroughAdvertising
    converter:      acquisitionThroughWordOfMouth
    converter:      advertisingBudget
    converter:      advertisingSuccess
    converter:      consumersReachedPerEuro
    converter:      consumersReachedThroughAdvertising
    converter:      consumersReachedThroughWordOfMouth
    converter:      contactRate
    converter:      initialCustomers
    converter:      marketSaturation
    converter:      targetMarket
    converter:      wordOfMouthSuccess
Wir stellen die Szenarien direkt dar:
bptk.plot_scenarios(
    scenario_managers=["xmile_customer_acquisition"],
    scenarios=["base","high_word_of_mouth","low_word_of_mouth"],
    equations=["customers"],
    series_names={
                "xmile_customer_acquisition_base_customers":"Base",
                "xmile_customer_acquisition_low_word_of_mouth_customers":"Low Word of Mouth",
                "xmile_customer_acquisition_high_word_of_mouth_customers":"High Word of Mouth",
        }
)
Introduction to The Business Prototyping Toolkit Blog Post Graph 11
HINWEIS: Sobald die XMILE-Datei in ein Python-Modell umgewandelt wurde, ist das Framework unabhängig von der XMILE-Datei. Die gesamte Simulation wird in Python durchgeführt. Die Software, die zur Erstellung der XMILE-Datei verwendet wurde, wird vom BPTK-Framework nicht benötigt.

Weitere Beispiele

Wenn Sie mehr über das BPTK-Framework erfahren möchten, finden Sie online eine ausführliche Dokumentation sowie ein detailliertes Tutorial auf GitHub.
Sie können auch fortgeschrittenere Beispiele auf GitHub finden:
  • Covid Simulation. Jupyter-Notebooks und Dashboards zur Veranschaulichung des SIR-Modells.
  • Covid Simulation Dashboard. Ein webbasiertes Simulations-Dashboard für die COVID-Simulation, das mit unserer BPTK-Widgets-Bibliothek für Javascript erstellt wurde. Sehen Sie sich eine Live-Version des Dashboards online an.
  • Beer Distribution Game. Eingehende Analyse des Bierspiels unter Verwendung von System Dynamics und agentenbasierter Simulation. Enthält eine Illustration, wie BPTK in Verbindung mit Reinforcement Learning eingesetzt werden kann, um Agenten zu trainieren, das Bierspiel autonom zu spielen.

Kontaktieren Sie uns

Bitte lassen Sie uns wissen, wenn Sie Hilfe bei den ersten Schritten benötigen, wenn Sie einen Fehler finden oder wichtige Funktionen vermissen.
Ein guter Ort, um mit uns in Kontakt zu treten, ist unsere Business Prototyping Toolkit Meetup, die sich monatlich online trifft. Hier können Sie BPTK in Aktion sehen, Fragen stellen und neue Funktionen vorschlagen.
Sie können uns auch per E-Mail unter support@transentis.com erreichen.