bupaR is an open-source, integrated suite of R-packages designed for handling & analysis of business process data.

library(bupaR) # Core package of framework. Includes dplyr functions for event log objects. implements an S3-objects class for event data

library(edeaR) # Exploratory & Descriptive Event-Data Analyses 
#The process metrics are based on Lean Six Sigma literature and can be analyzed and visualized at different levels of granularity. Additionally, edeaR contains an extensive collection of event data specific filters

library(eventdataR) # Contains Sepsis & patients dataset
#eventdataR is a data-package which provide easy access to event logs for testing and experiments. Currently, both artificial event data, e.g. patients, as well as real-life event data, such as the sepsis dataset.

library(processmapR) # Process Data Specific Visualizations
#The provided visualizations are highly customizable and can be used to give insights to different aspects of the process

library(processanimateR) #Extension of processmapR, allows for animation of process

library(petrinetR) # Building, Visualizing, Exporting, Replaying Petri Nets
#Petri Nets can be visualized, adjusted and one can perform manual token replay and parse transition sequences.
#######what is a petri net?

library(processmonitR) #Provides a limited set of process dashboards which can be used in a permanent, real-time fashion and for interactive analysis

library(heuristicsmineR) # Algorithm that actos on Directly-Follows Graph. Enables noise visibility and common constructs

# Basic Packages
library(dplyr)            ##pipes
library(tidyr)            ##tidy data, partcularly the crossing() function
library(lubridate)        ##date time manipulation

Event Logs

What is an Event Log

  • If we are able to collect the proper data points, creating an eventlog object is as easy as creating a dataframe.
  • Below is a standard data frame object
#Build a Data Frame
t=Sys.time()
data <- data.frame(case = rep("A",5),
                   activity_id = c("A","B","C","D","E"),
                   activity_instance_id = 1:5,
                   lifecycle_id = rep("complete",5),
                   timestamp = c(t,t+1000,t+2000,t+3000,t+4000),
                   resource = rep("resource 1", 5))
data
##   case activity_id activity_instance_id lifecycle_id           timestamp
## 1    A           A                    1     complete 2020-06-06 15:07:07
## 2    A           B                    2     complete 2020-06-06 15:23:47
## 3    A           C                    3     complete 2020-06-06 15:40:27
## 4    A           D                    4     complete 2020-06-06 15:57:07
## 5    A           E                    5     complete 2020-06-06 16:13:47
##     resource
## 1 resource 1
## 2 resource 1
## 3 resource 1
## 4 resource 1
## 5 resource 1
  • The conversion to an event log from a data frame is seamless with the right data points
#How to create an Event Log
first_log <- eventlog(data,case_id = "case",
                       activity_id = "activity_id",
                       activity_instance_id = "activity_instance_id",
                       lifecycle_id = "lifecycle_id",
                       timestamp = "timestamp",
                       resource_id = "resource")
first_log
## Log of 5 events consisting of:
## 1 trace 
## 1 case 
## 5 instances of 5 activities 
## 1 resource 
## Events occurred from 2020-06-06 15:07:07 until 2020-06-06 16:13:47 
##  
## Variables were mapped as follows:
## Case identifier:     case 
## Activity identifier:     activity_id 
## Resource identifier:     resource 
## Activity instance identifier:    activity_instance_id 
## Timestamp:           timestamp 
## Lifecycle transition:        lifecycle_id 
## 
## # A tibble: 5 x 7
##   case  activity_id activity_instan~ lifecycle_id timestamp           resource
##   <chr> <fct>       <chr>            <fct>        <dttm>              <fct>   
## 1 A     A           1                complete     2020-06-06 15:07:07 resourc~
## 2 A     B           2                complete     2020-06-06 15:23:47 resourc~
## 3 A     C           3                complete     2020-06-06 15:40:27 resourc~
## 4 A     D           4                complete     2020-06-06 15:57:07 resourc~
## 5 A     E           5                complete     2020-06-06 16:13:47 resourc~
## # ... with 1 more variable: .order <int>

Process Analysis

Process Analysis

  • The Patients data set is artificial data outlining the journey of a patient through the emergency department of a hospital. A summary of the data shows there are 500 cases in the sample data set. Below is a summary of the data
#Summary of Data
summary(patients)
## Number of events:  5442
## Number of cases:  500
## Number of traces:  7
## Number of distinct activities:  7
## Average trace length:  10.884
## 
## Start eventlog:  2017-01-02 11:41:53
## End eventlog:  2018-05-05 07:16:02
##                   handling      patient          employee  handling_id       
##  Blood test           : 474   Length:5442        r1:1000   Length:5442       
##  Check-out            : 984   Class :character   r2:1000   Class :character  
##  Discuss Results      : 990   Mode  :character   r3: 474   Mode  :character  
##  MRI SCAN             : 472                      r4: 472                     
##  Registration         :1000                      r5: 522                     
##  Triage and Assessment:1000                      r6: 990                     
##  X-Ray                : 522                      r7: 984                     
##  registration_type      time                         .order    
##  complete:2721     Min.   :2017-01-02 11:41:53   Min.   :   1  
##  start   :2721     1st Qu.:2017-05-06 17:15:18   1st Qu.:1361  
##                    Median :2017-09-08 04:16:50   Median :2722  
##                    Mean   :2017-09-02 20:52:34   Mean   :2722  
##                    3rd Qu.:2017-12-22 15:44:11   3rd Qu.:4082  
##                    Max.   :2018-05-05 07:16:02   Max.   :5442  
## 
  • We can also break down the data into an isolated patient. Here we took a slice of the patient 1 and can see their journey
slice(patients, 1)
## Log of 12 events consisting of:
## 1 trace 
## 1 case 
## 6 instances of 6 activities 
## 6 resources 
## Events occurred from 2017-01-02 11:41:53 until 2017-01-09 19:45:45 
##  
## Variables were mapped as follows:
## Case identifier:     patient 
## Activity identifier:     handling 
## Resource identifier:     employee 
## Activity instance identifier:    handling_id 
## Timestamp:           time 
## Lifecycle transition:        registration_type 
## 
## # A tibble: 12 x 7
##    handling patient employee handling_id registration_ty~ time               
##    <fct>    <chr>   <fct>    <chr>       <fct>            <dttm>             
##  1 Registr~ 1       r1       1           start            2017-01-02 11:41:53
##  2 Triage ~ 1       r2       501         start            2017-01-02 12:40:20
##  3 Blood t~ 1       r3       1001        start            2017-01-05 08:59:04
##  4 MRI SCAN 1       r4       1238        start            2017-01-05 21:37:12
##  5 Discuss~ 1       r6       1735        start            2017-01-07 07:57:49
##  6 Check-o~ 1       r7       2230        start            2017-01-09 17:09:43
##  7 Registr~ 1       r1       1           complete         2017-01-02 12:40:20
##  8 Triage ~ 1       r2       501         complete         2017-01-02 22:32:25
##  9 Blood t~ 1       r3       1001        complete         2017-01-05 14:34:27
## 10 MRI SCAN 1       r4       1238        complete         2017-01-06 01:54:23
## 11 Discuss~ 1       r6       1735        complete         2017-01-07 10:18:08
## 12 Check-o~ 1       r7       2230        complete         2017-01-09 19:45:45
## # ... with 1 more variable: .order <int>

Activity Analysis

  • How many distinct activities are there?
n_activities(patients)
## [1] 7
  • What are the names of the activities?
activity_labels(patients)
## [1] Registration          Triage and Assessment Blood test           
## [4] MRI SCAN              X-Ray                 Discuss Results      
## [7] Check-out            
## 7 Levels: Blood test Check-out Discuss Results MRI SCAN ... X-Ray
  • list of total patient activities
activities(patients)
## # A tibble: 7 x 3
##   handling              absolute_frequency relative_frequency
##   <fct>                              <int>              <dbl>
## 1 Registration                         500             0.184 
## 2 Triage and Assessment                500             0.184 
## 3 Discuss Results                      495             0.182 
## 4 Check-out                            492             0.181 
## 5 X-Ray                                261             0.0959
## 6 Blood test                           237             0.0871
## 7 MRI SCAN                             236             0.0867
  • Activity Presence and relative value
activity_presence(patients)
## # A tibble: 7 x 3
##   handling              absolute relative
##   <fct>                    <int>    <dbl>
## 1 Registration               500    1    
## 2 Triage and Assessment      500    1    
## 3 Discuss Results            495    0.99 
## 4 Check-out                  492    0.984
## 5 X-Ray                      261    0.522
## 6 Blood test                 237    0.474
## 7 MRI SCAN                   236    0.472
  • The eventlog objects also naturally integrate with graphical packages making plotting data easy
end_act_patients <- end_activities(patients, level = "activity")
plot(end_act_patients)

Time Analysis

Time Analysis

Idle Time

  • The idle time is the time that there is no activity in a case or for a resource.
    • It can only be calculated when there are both start and end timestamps available for activity instances.
    • It can be computed at the levels trace, resource, case and log, and using different time units.Below is a measure of idle time by resource
patients %>%
    idle_time("resource", units = "days") %>%
    plot()

Processing Time

  • The processing time can be computed at the levels log, trace, case, activity and resource-activity. It can only be calculated when there are both start and end timestamps available for activity instances. Below is a boxplot of activity processing time.
patients %>% 
    processing_time("activity") %>%
    plot

Throughput Time

  • The throughput time is the time form the very first event to the last event of a case. The levels at which it can be computed are log, trace, or case. Below is an measure of throughput time per event
patients %>%
    throughput_time("log") %>%
    plot()

Organizational Analysis

Organizational Analysis

Resource Frequency

  • The resource frequency metric allows the computation of the number/frequency of resources at the levels of log, case, activity, resource, and resource-activity.
patients %>%
    resource_frequency("resource") %>% plot

Resource Involvement

  • Resource involvement refers to the notion of the number of cases in which a resource is involved.
    • It can be computed at levels case, resource, and resource-activity.
    • In this example, R2 & R1 are involved in all cases.
patients %>%
    resource_involvement("resource") %>% plot

Resource Specialization

  • The resource specalization metric shows whether resources are specialized in certain activities or not.
    • It can be calculated at the levels log, case, resource and activity.
    • Here, because each resource is performing exactly 1 activity everyone is 100% specialized
patients %>%
    resource_specialisation("resource") %>% plot

Traces

Trace Exploration

  • View Alternate Traces
traces(patients)
## # A tibble: 7 x 3
##   trace                                      absolute_frequen~ relative_frequen~
##   <chr>                                                  <int>             <dbl>
## 1 Registration,Triage and Assessment,X-Ray,~               258             0.516
## 2 Registration,Triage and Assessment,Blood ~               234             0.468
## 3 Registration,Triage and Assessment,Blood ~                 2             0.004
## 4 Registration,Triage and Assessment,X-Ray                   2             0.004
## 5 Registration,Triage and Assessment                         2             0.004
## 6 Registration,Triage and Assessment,X-Ray,~                 1             0.002
## 7 Registration,Triage and Assessment,Blood ~                 1             0.002
  • Number of Different Total Traces
n_traces(patients)
## [1] 7
  • Trace Visualization displays each trace and its associated frequency
trace_explorer(patients, coverage = 1)

Trace Coverage

  • The trace coverage metric shows the relationship between the number of different activity sequences (i.e. traces) and the number of cases they cover.
    • In the patients log, there are only 7 different traces, and 2 of them cover nearly 100% of the event log.
patients %>%
    trace_coverage("trace") %>%
    plot()

Trace Length

The trace length metric describes the length of traces, i.e. the number of activity instances for each case. It can be computed at the levels case, trace and log.

patients %>%
    trace_length("log") %>%
    plot

Process Variants

  • Explore traces with 10% coverage
trace_explorer(sepsis, coverage = .10)

  • Calculate the average trace length
trace_length(sepsis)
##       min        q1    median      mean        q3       max    st_dev       iqr 
##   3.00000   9.00000  13.00000  14.48952  16.00000 185.00000  11.47594   7.00000
  • Plot of Activity Presence
sepsis %>% 
  activity_presence() %>% 
  plot()

Structural Analysis - Variance

Activity Presence

  • Activity presence shows in what percentage of cases an activity is present. It has no level-argument.
patients %>% activity_presence() %>%
    plot

Activity Frequency

  • The frequency of activities can be calculated using the activity_frequency function, at the levels log, trace and activity.
patients %>%
    activity_frequency("activity")
## # A tibble: 7 x 3
##   handling              absolute relative
##   <fct>                    <int>    <dbl>
## 1 Registration               500   0.184 
## 2 Triage and Assessment      500   0.184 
## 3 Discuss Results            495   0.182 
## 4 Check-out                  492   0.181 
## 5 X-Ray                      261   0.0959
## 6 Blood test                 237   0.0871
## 7 MRI SCAN                   236   0.0867

Start Activities

  • The start of cases can be described using the start_activities function. Available levels are activity, case, log, resource and resource activity.
    • This shows that in this event log, all cases are started with the Registration by resource r1
patients %>%
    start_activities("resource-activity")
## # A tibble: 1 x 5
##   employee handling     absolute relative cum_sum
##   <fct>    <fct>           <int>    <dbl>   <dbl>
## 1 r1       Registration      500        1       1

End Activities

  • Conversely, the end_activities functions describes the end of cases, using the same levels: log, case, activity, resource and resource-activity.
    • In contract to the start of cases, the end of cases seems to differ more frequently, although it is mostly the Check-Out activity.
patients %>%
    end_activities("resource-activity")
## # A tibble: 5 x 5
##   employee handling              absolute relative cum_sum
##   <fct>    <fct>                    <int>    <dbl>   <dbl>
## 1 r7       Check-out                  492    0.984   0.984
## 2 r6       Discuss Results              3    0.006   0.99 
## 3 r2       Triage and Assessment        2    0.004   0.994
## 4 r5       X-Ray                        2    0.004   0.998
## 5 r3       Blood test                   1    0.002   1

Structural Analysis - Rework

  • The Patients Data example has 1 activity per resource per track so it will not show rework. We can leverage the Sepsis dataset for rework examples.

  • Redo repetitions are activity executions of the same activity type that are executed not immediately following each other and by a different resource than the first activity occurrence of this activity type.

Rework with Sepsis Dataset

  • Number of repetitions per resource
    • In this instance(resource), the absolute and relative metric refer to number of times each resource appears in a repetition
n_reps_per_resource <- number_of_repetitions(sepsis, level = "resource")
plot(n_reps_per_resource)

  • Number of repetitions per activity
    • In this instance(activity), we see the absolute and relative number of both repeat and redo repetitions
n_reps_per_activity <- number_of_repetitions(sepsis, level = "activity")
plot(n_reps_per_activity)

  • Number of repetitions per event log
n_reps_per_eventlog <- number_of_repetitions(sepsis, level = "log")
plot(n_reps_per_eventlog)

Process Maps

Process Maps

  • bupaR has built in functionality for generation, visualization and interpretation of process maps.

  • Basic Process Map

# Draw process map
process_map(patients)
  • Basic Animated Process Map on each patients journey (in months)
animate_process(patients)

Process Map Insights

  • Process Map by employee (in days)
animate_process(patients, mode = "relative", jitter = 10, legend = "color",
  mapping = token_aes(color = token_scale("employee", 
    scale = "ordinal", 
    range = RColorBrewer::brewer.pal(7, "Paired"))))
  • By Employee (in months)
animate_process(patients, 
                legend = "color", 
                mapping = token_aes(color = token_scale("employee", 
                                                        scale = "ordinal", 
                                                        range = RColorBrewer::brewer.pal(8, "Paired"))))
  • Case by Time
    • This will change the color of the token at 0, 2, 4, 8, and 16 days.
#convert numeric value into days
my_flags <- data.frame(value = c(0,2,4,8,16)) %>% 
            mutate(day = days(value)) 

#The crossing() function joins the cases of ‘patients’ to ‘my_flags’ and creates all possible combinations.
my_timeflags <- patients %>% 
                cases %>%
                crossing(my_flags) %>% ##similar to a SQL outer join
                mutate(time = start_timestamp + day) %>% 
                filter(time <= complete_timestamp) %>% 
                select("case" = patient,time,value) ##must be case, time, value

patients %>%
  animate_process(mode ="absolute",
                  jitter=10,
                  legend = "color", 
                  mapping = token_aes(
                    color = token_scale(my_timeflags
                                        , scale = "ordinal"
                                        , domain = my_flags$value
                                        , range = rev(RColorBrewer::brewer.pal(5,"Spectral"))
                    )))
  • By Volume
    • Note: This uses the built in “traffic_fines” data set
animate_process(sample_n(traffic_fines, 1000) %>% filter_trace_frequency(percentage = 0.95),
                mode = "relative",
                legend = "color", 
                mapping = token_aes(color = token_scale("amount", 
                                                        scale = "linear", 
                                                        range = c("yellow","red"))))
  • By Time (Transition from Blue to Red indicates passing time)
animate_process(patients, 
                mapping = token_aes(color = token_scale("time", 
                                                        scale = "time", 
                                                        range = c("blue","red"))))

Process Rules & Aggregates

  • The first rule checks the starting activity, while the second rule checks whether CRP and LacticAcid occur together.
library(processcheckR)
sepsis %>%
  # check if cases starts with "ER Registration"
  check_rule(starts("ER Registration"), label = "r1") %>%
  # check if activities "CRP" and "LacticAcid" occur together
  check_rule(and("CRP","LacticAcid"), label = "r2") %>%
  group_by(r1, r2) %>%
  n_cases() 
## # A tibble: 4 x 3
## # Groups:   r1 [2]
##   r1    r2    n_cases
##   <lgl> <lgl>   <int>
## 1 FALSE FALSE      10
## 2 FALSE TRUE       45
## 3 TRUE  FALSE     137
## 4 TRUE  TRUE      858

Filtering

  • Instead of adding logical values for each rule, you can also immediately filter the cases which adhere to one or more rules, using the filter_rules
sepsis %>%
  filter_rules(
    r1 = starts("ER Registration"),
    r2 = and("CRP","LacticAcid")) %>%
  n_cases() 
## [1] 858

Contains

  • How many cases have three or more occurences of Leucocytes?
sepsis %>% 
    check_rule(contains("Leucocytes", n = 3)) %>%
    group_by(contains_Leucocytes_3) %>%
    n_cases()
## # A tibble: 2 x 2
##   contains_Leucocytes_3 n_cases
##   <lgl>                   <int>
## 1 FALSE                     590
## 2 TRUE                      460

Contains Exactly

  • How many cases have exactly four more occurences of Leucocytes?
sepsis %>% 
    check_rule(contains_exactly("Leucocytes", n = 4), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE     960
## 2 TRUE       90

Contains Between

  • How many cases have between 0 and 10 occurences of Leucocytes?
sepsis %>% 
    check_rule(contains_between("Leucocytes", min = 0, max = 10), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE      38
## 2 TRUE     1012

Starts

  • How many cases start with “ER Registration”
sepsis %>% 
    check_rule(starts("ER Registration"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE      55
## 2 TRUE      995

Ends

  • How many cases end with “Release A”
sepsis %>% 
    check_rule(ends("Release A"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE     657
## 2 TRUE      393

Succession

*How many cases is “ER Sepsis Triage” succeeded by “CRP”

sepsis %>% 
    check_rule(succession("ER Sepsis Triage","CRP"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 1 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE    1050

Response

  • How many cases is “ER Sepsis Triage” followed by “CRP”, if “ER Sespis Triage” occurs.
sepsis %>% 
    check_rule(response("ER Sepsis Triage","CRP"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE    1049
## 2 TRUE        1

Precendence

  • How many cases is “CRP” preceded “ER Sepsis Triage”, if “CPR” occurs.
sepsis %>% 
    check_rule(precedence("ER Sepsis Triage","CRP"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE    1007
## 2 TRUE       43

Responded Existence

*(cases where if activity a occurs, activity b also occurs (but not vice versa)) How many cases contain both “CRP” and “ER Sepsis Triage”, if “CPR” occur

sepsis %>% 
    check_rule(responded_existence("CRP", "ER Sepsis Triage"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE       1
## 2 TRUE     1049

AND

  • How many cases contain both “CRP” and “ER Sepsis Triage”.
sepsis %>% 
    check_rule(and("CRP", "ER Sepsis Triage"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE      44
## 2 TRUE     1006

XOR

  • How many cases contain “CRP” OR “ER Sepsis Triage”.
sepsis %>% 
    check_rule(xor("CRP", "ER Sepsis Triage"), label = "r1") %>%
    group_by(r1) %>%
    n_cases()
## # A tibble: 2 x 2
##   r1    n_cases
##   <lgl>   <int>
## 1 FALSE    1006
## 2 TRUE       44

Process Discovery

bupaR supports the following discovery algorithms: Alpha Miner, Inductive Miner and Heuristics Miner

Alpha Miner - WIP

  • An algorithm designed for process mining and reconstructing causality from a set sequence of events
#library(pm4py) # Process mining library from Python which acts as a bridge between PM4Py and bupaR 


#use only complete timestamp
#patients_completes <- patients %>% filter_lifecycle("complete")

#discovery_alpha(patients_completes) -> PN
#PN %>% str

#PN$petrinet %>% render_PN()
#discovery_alpha(patients_completes, variant = variant_alpha_plus()) -> PN

#PN$petrinet %>% render_PN()

Inductive Miner - WIP

  • A Business Process discovery tool which generates a process model, compares the model to event log data and visualizes enhancements such as performance mesaures, queue lengths, and animations.
#use only complete timestamp
#patients_completes <- patients %>% filter_lifecycle("complete")

#discovery_inductive(patients_completes, variant = variant_inductive_only_dfg()) -> PN
#PN %>% str

#PN$petrinet %>% render_PN()

Heuristics Miner

  • Heuristics Miner is an algorithm which acts on the Directly-Follows Graph. This allows visibility into noice and to find common constructs (i.e. dependecy between two activities - XOR/AND). The output here is a Heuristics Net which is an object that contains the objects and relationships between them. This algorithm is best used for either real-life data without too many different events or for generation of a petri net.

  • Dependency graph / matrix

dependency_matrix(patients) %>% render_dependency_matrix()
  • Patients precedence matrix
m <- precedence_matrix_absolute(patients)
as.matrix(m)
##                        consequent
## antecedent              Blood test Check-out Discuss Results End MRI SCAN
##   Blood test                     0         0               0   1      236
##   Check-out                      0         0               0 492        0
##   Discuss Results                0       492               0   3        0
##   End                            0         0               0   0        0
##   MRI SCAN                       0         0             236   0        0
##   Registration                   0         0               0   0        0
##   Start                          0         0               0   0        0
##   Triage and Assessment        237         0               0   2        0
##   X-Ray                          0         0             259   2        0
##                        consequent
## antecedent              Registration Start Triage and Assessment X-Ray
##   Blood test                       0     0                     0     0
##   Check-out                        0     0                     0     0
##   Discuss Results                  0     0                     0     0
##   End                              0     0                     0     0
##   MRI SCAN                         0     0                     0     0
##   Registration                     0     0                   500     0
##   Start                          500     0                     0     0
##   Triage and Assessment            0     0                     0   261
##   X-Ray                            0     0                     0     0
  • Convert to Petri net
cn <- causal_net(patients, threshold = .7)
pn <- as.petrinet(cn)
render_PN(pn)

test

animate_process(patients,
   mapping = token_aes(shape = "image",
    size = token_scale(10),
    image = token_scale("https://upload.wikimedia.org/wikipedia/en/5/5f/Pacman.gif")))

Citing/References

The bupaR package is deveopled by volunteers and academic researchers. Shout out to:Janssenswillen, G., Depaire, B., Swennen, M., Jans, M., & Vanhoof, K. (2019). bupaR: Enabling reproducible business process analysis. Knowledge-Based Systems, 163, 927-930.

###########Use purrr to apply to all packages - WIP
citation("processmapR")
## 
## To cite package 'processmapR' in publications use:
## 
##   Gert Janssenswillen (2020). processmapR: Construct Process Maps Using
##   Event Data. R package version 0.3.4.
##   https://CRAN.R-project.org/package=processmapR
## 
## A BibTeX entry for LaTeX users is
## 
##   @Manual{,
##     title = {processmapR: Construct Process Maps Using Event Data},
##     author = {Gert Janssenswillen},
##     year = {2020},
##     note = {R package version 0.3.4},
##     url = {https://CRAN.R-project.org/package=processmapR},
##   }