How to Collect Results

Once a simulation has been run, results can be collected. Results take the form of a data record. Certain events in a simulation’s run cause data records to be created that describe those events. Those results are:

In order to collect all data records, we use the get_all_records() method of the Simulation object.

For example, in an M/M/3 queue:

>>> import ciw
>>> N = ciw.create_network(
...     arrival_distributions=[ciw.dists.Exponential(rate=1)],
...     service_distributions=[ciw.dists.Exponential(rate=2)],
...     number_of_servers=[1]
... )
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(100)

To collect a list of all data records:

>>> recs = Q.get_all_records()

This gives a list of DataRecord objects, which are named tuples with a number of fields with useful information about the event in question:

>>> r = recs[14]
>>> r
Record(id_number=15, customer_class='Customer', original_customer_class='Customer', node=1, arrival_date=16.58266..., waiting_time=0.0, service_start_date=16.58266..., service_time=1.69969..., service_end_date=18.28236..., time_blocked=0.0, exit_date=18.28236..., destination=-1, queue_size_at_arrival=0, queue_size_at_departure=1, server_id=1, record_type='service')

These data records have a number of useful fields, set out in detail here. Importantly, fields can be accessed as attributes:

>>> r.service_start_date
16.58266884119802

And so relevant data can be gathered using list comprehension:

>>> waiting_times = [r.waiting_time for r in recs]
>>> sum(waiting_times) / len(waiting_times)
0.3989747...

For easier manipulation, use in conjuction with Pandas is recommended, allowing for easier filtering, grouping, and summary statistics calculations. Lists of data records convert to Pandas data frames smoothly:

>>> import pandas as pd
>>> recs_pd = pd.DataFrame(recs)
>>> recs_pd  
A Pandas data frame of Ciw data records.

Types of Records

One particular field of note is the record_type field, which indicates which of the five events caused that data record to be created.

  • Services: gives record_type="service"

  • Pre-empted services gives record_type="interrupted service"

  • Baulking customers gives record_type="baulk"

  • Reneging customers gives record_type="renege"

  • Rejected customers gives record_type="rejection"

It is only by understanding the record types that we can understand the other data record fields. More information is given on the relevant Guide pages for each feature.

When a simulation can produce multiple types of data record, it is sometimes useful to be able to only collect data records of a give type or types. we can do this with the optional keyword argument only, which takes a list of the record types we are interested in:

>>> lost_customer_recs = Q.get_all_records(only=["rejection", "baulk", "renege"])
>>> service_recs = Q.get_all_records(only=["service"])