Es ist sehr einfach, ein Diagramm aus den Prozessprotokollen zu erstellen. Analysten verfügen derzeit über eine ausreichende Vielfalt an beruflichen Entwicklungen wie Celonis, Disco, PM4PY, ProM usw., um das Studium von Prozessen zu erleichtern. Es ist viel schwieriger, Abweichungen in den Diagrammen zu finden, um daraus korrekte Schlussfolgerungen zu ziehen.
Was ist, wenn einige berufliche Entwicklungen, die sich bewährt haben und von besonderem Interesse sind, aus dem einen oder anderen Grund nicht verfügbar sind oder Sie mehr Rechenfreiheit bei der Arbeit mit Grafiken wünschen? Wie schwierig ist es, selbst einen Bergmann zu schreiben und einige der notwendigen Funktionen für die Arbeit mit Grafiken zu implementieren? Wir werden dies in der Praxis unter Verwendung der Standard-Python-Bibliotheken tun, die Berechnungen implementieren und mit ihrer Hilfe Antworten auf detaillierte Fragen geben, die die Prozessverantwortlichen interessieren könnten.
Ich möchte sofort reservieren, dass die im Artikel angegebene Lösung keine industrielle Implementierung ist. Dies ist ein Versuch, mit Hilfe von einfachem Code, der eindeutig funktioniert und daher die Anpassung erleichtert, selbst mit Protokollen zu arbeiten. Diese Lösung sollte nicht für Big Data verwendet werden. Dies erfordert eine erhebliche Verfeinerung, z. B. mithilfe von Vektorberechnungen oder durch Änderung des Ansatzes zum Sammeln und Aggregieren von Informationen über Ereignisse.
Bevor Sie ein Diagramm erstellen, müssen Sie Berechnungen durchführen. Die eigentliche Berechnung des Graphen wird der zuvor erwähnte Bergmann sein. Um die Berechnung durchzuführen, ist es notwendig, Wissen über die Ereignisse - die Eckpunkte des Diagramms und die Verbindungen zwischen ihnen - zu sammeln und sie beispielsweise in Nachschlagewerken aufzuschreiben. Referenzen werden mit dem Berechnungsverfahren ( Code auf Github) gefüllt). Die ausgefüllten Referenzen werden als Parameter an das Verfahren zum Zeichnen von Diagrammen übergeben (siehe den Code über den obigen Link). Diese Prozedur formatiert die Daten wie folgt:
digraph f {"Permit SUBMITTED by EMPLOYEE (6255)" -> "Permit APPROVED by ADMINISTRATION (4839)" [label=4829 color=black penwidth=4.723857205400346]
"Permit SUBMITTED by EMPLOYEE (6255)" -> "Permit REJECTED by ADMINISTRATION (83)" [label=83 color=pink2 penwidth=2.9590780923760738]
"Permit SUBMITTED by EMPLOYEE (6255)" -> "Permit REJECTED by EMPLOYEE (231)" [label=2 color=pink2 penwidth=1.3410299956639813]
…
start [color=blue shape=diamond]
end [color=blue shape=diamond]}
und übergibt es zum Rendern an die Graphviz-Grafik-Engine.
Beginnen wir mit dem Erstellen und Untersuchen von Diagrammen mit dem implementierten Miner. Wir werden die Verfahren zum Lesen und Sortieren von Daten, Berechnen und Zeichnen von Diagrammen wie in den folgenden Beispielen wiederholen. Die Ereignisprotokolle stammen beispielsweise aus internationalen Erklärungen des BPIC2020-Wettbewerbs. Link zum Wettbewerb.
Wir lesen die Daten aus dem Protokoll, sortieren sie nach Datum und Uhrzeit. Das .xes-Format wurde zuvor in .xlsx konvertiert.
df_full = pd.read_excel('InternationalDeclarations.xlsx')
df_full = df_full[['id-trace','concept:name','time:timestamp']]
df_full.columns = ['case:concept:name', 'concept:name', 'time:timestamp']
df_full['time:timestamp'] = pd.to_datetime(df_full['time:timestamp'])
df_full = df_full.sort_values(['case:concept:name','time:timestamp'], ascending=[True,True])
df_full = df_full.reset_index(drop=True)
Berechnen wir den Graphen.
dict_tuple_full = calc(df_full)
Zeichnen wir die Grafik.
draw(dict_tuple_full,'InternationalDeclarations_full')
Nach Abschluss der Prozeduren erhalten wir das Prozessdiagramm:
Da das resultierende Diagramm nicht lesbar ist, vereinfachen wir es.
Es gibt verschiedene Ansätze, um die Lesbarkeit zu verbessern oder das Diagramm zu vereinfachen:
- Verwenden Sie die Filterung nach Gewichten von Scheitelpunkten oder Verknüpfungen.
- Lärm loswerden;
- Gruppenereignisse nach Namensähnlichkeit.
Nehmen wir Ansatz 3.
Erstellen wir ein Wörterbuch zum Kombinieren von Ereignissen:
_dict = {'Permit SUBMITTED by EMPLOYEE': 'Permit SUBMITTED',
'Permit APPROVED by ADMINISTRATION': 'Permit APPROVED',
'Permit APPROVED by BUDGET OWNER': 'Permit APPROVED',
'Permit APPROVED by PRE_APPROVER': 'Permit APPROVED',
'Permit APPROVED by SUPERVISOR': 'Permit APPROVED',
'Permit FINAL_APPROVED by DIRECTOR': 'Permit FINAL_APPROVED',
'Permit FINAL_APPROVED by SUPERVISOR': 'Permit FINAL_APPROVED',
'Start trip': 'Start trip',
'End trip': 'End trip',
'Permit REJECTED by ADMINISTRATION': 'Permit REJECTED',
'Permit REJECTED by BUDGET OWNER': 'Permit REJECTED',
'Permit REJECTED by DIRECTOR': 'Permit REJECTED',
'Permit REJECTED by EMPLOYEE': 'Permit REJECTED',
'Permit REJECTED by MISSING': 'Permit REJECTED',
'Permit REJECTED by PRE_APPROVER': 'Permit REJECTED',
'Permit REJECTED by SUPERVISOR': 'Permit REJECTED',
'Declaration SUBMITTED by EMPLOYEE': 'Declaration SUBMITTED',
'Declaration SAVED by EMPLOYEE': 'Declaration SAVED',
'Declaration APPROVED by ADMINISTRATION': 'Declaration APPROVED',
'Declaration APPROVED by BUDGET OWNER': 'Declaration APPROVED',
'Declaration APPROVED by PRE_APPROVER': 'Declaration APPROVED',
'Declaration APPROVED by SUPERVISOR': 'Declaration APPROVED',
'Declaration FINAL_APPROVED by DIRECTOR': 'Declaration FINAL_APPROVED',
'Declaration FINAL_APPROVED by SUPERVISOR': 'Declaration FINAL_APPROVED',
'Declaration REJECTED by ADMINISTRATION': 'Declaration REJECTED',
'Declaration REJECTED by BUDGET OWNER': 'Declaration REJECTED',
'Declaration REJECTED by DIRECTOR': 'Declaration REJECTED',
'Declaration REJECTED by EMPLOYEE': 'Declaration REJECTED',
'Declaration REJECTED by MISSING': 'Declaration REJECTED',
'Declaration REJECTED by PRE_APPROVER': 'Declaration REJECTED',
'Declaration REJECTED by SUPERVISOR': 'Declaration REJECTED',
'Request Payment': 'Request Payment',
'Payment Handled': 'Payment Handled',
'Send Reminder': 'Send Reminder'}
Lassen Sie uns die Ereignisse gruppieren und das Prozessdiagramm erneut zeichnen.
df_full_gr = df_full.copy()
df_full_gr['concept:name'] = df_full_gr['concept:name'].map(_dict)
dict_tuple_full_gr = calc(df_full_gr)
draw(dict_tuple_full_gr,'InternationalDeclarations_full_gr'
Nach dem Gruppieren von Ereignissen nach Ähnlichkeit des Namens hat sich die Lesbarkeit des Diagramms verbessert. Versuchen wir, Antworten auf Fragen zu finden. Link zur Liste der Fragen. Wie vielen Erklärungen ging beispielsweise keine vorab genehmigte Genehmigung voraus?
Um die gestellte Frage zu beantworten, filtern wir das Diagramm nach Ereignissen von Interesse und zeichnen das Prozessdiagramm erneut.
df_full_gr_f = df_full_gr[df_full_gr['concept:name'].isin(['Permit SUBMITTED',
'Permit APPROVED',
'Permit FINAL_APPROVED',
'Declaration FINAL_APPROVED',
'Declaration APPROVED'])]
df_full_gr_f = df_full_gr_f.reset_index(drop=True)
dict_tuple_full_gr_f = calc(df_full_gr_f)
draw(dict_tuple_full_gr_f,'InternationalDeclarations_full_gr_isin')
Mit Hilfe des resultierenden Diagramms können wir leicht eine Antwort auf die gestellte Frage geben - 116 und 312 Erklärungen gingen keine vorab genehmigte Genehmigung voraus.
Sie können für die Verbindungen 116 und 312 zusätzlich "fehlschlagen" (Filtern nach "Fall: Konzept: Name", Teilnahme an der gewünschten Verbindung) und sicherstellen, dass keine Ereignisse im Zusammenhang mit Berechtigungen in den Diagrammen auftreten.
Lassen Sie uns für die Kommunikation 116 "scheitern":
df_116 = df_full_gr_f[df_full_gr_f['case:concept:name'].isin(d_case_start2['Declaration FINAL_APPROVED'])]
df_116 = df_116.reset_index(drop=True)
dict_tuple_116 = calc(df_116)
draw(dict_tuple_116,'InternationalDeclarations_full_gr_isin_116')
Lassen Sie uns für Verbindung 312 "scheitern":
df_312 = df_full_gr_f[df_full_gr_f['case:concept:name'].isin(d_case_start2['Declaration APPROVED'])]
df_312 = df_312.reset_index(drop=True)
dict_tuple_312 = calc(df_312)
draw(dict_tuple_312,'InternationalDeclarations_full_gr_isin_312')
Da in den empfangenen Diagrammen keine Ereignisse im Zusammenhang mit Berechtigungen vorhanden sind, wird die Richtigkeit der Antworten 116 und 312 bestätigt.
Wie Sie sehen, ist das Schreiben eines Miners und das Implementieren der erforderlichen Funktionen zum Arbeiten mit Diagrammen keine schwierige Aufgabe, die die integrierten Funktionen von Python und Graphviz als Grafik-Engine erfolgreich bewältigt haben.