liveBook · Manning

Simulation

As explained in Outlier Detection in Python

A simulation is a computational representation of a process or environment that generates observations under specified rules and conditions.

A simulation creates synthetic data one record at a time. Each record represents an action or state at a point in time, and later records depend on the world established by earlier ones. This makes simulation useful when independently generated rows would miss the order and context that make data plausible. section 11.4

Consider a business that buys and sells goods while maintaining inventory. A purchase of an item that has not been selling, or a sale of an item not in stock, may be unusual because of what happened before it—not because the transaction looks unusual on its own. Separate purchasing and sales agents can act on the current state, while an outlier-producing process introduces rare, different behavior. section 11.4

To construct and use this kind of test data:

  • Model the state and ordinary agents, then generate transactions in time order so each action can affect what happens next. section 11.4
  • Add a distinct process for behavior you want to detect, such as a purchaser whose transactions form an escalating pattern even if individual purchases are not drastically larger. section 11.4 section 12.1
  • Generate multiple plausible datasets and test whether a detector reliably finds the known behavior; random variation helps reveal what can and cannot be detected. section 12.1
Listing 11.6 Simulation representing one company for 1 year
class Purchacer:
    def consider_purchase(self):                               #1
        global inventory
        global transactions
        if (current_datetime.hour < 9) or \
        (current_datetime.hour > 17):                          #2
            return
        if np.random.random() > 0.01:                          #3
            product_id = np.random.choice(range(num_items_in_inventory))
            if inventory[product_id] > 1000:                   #4
                return
            supplier_id = \
               np.random.choice(range(num_suppliers))          #5
            unit_cost = np.random.exponential() * 20.0
            num_purchased = np.random.randint(10, 200)
            total_cost = num_purchased * unit_cost
            inventory[product_id] += num_purchased                    
            transactions.append([
                        'Purchase', self.staff_id, 
                        supplier_id, product_id, 
                    current_datetime.strftime("%Y-%m-%d %H:%M"),
                    num_purchased, unit_cost, total_cost,
                    inventory[product_id]])

The one-year company simulation shows how a purchaser checks working hours and inventory before adding a purchase transaction. section 11.4

class RoguePurchaser:                                          #1
    def consider_purchase(self):
        if (current_datetime.hour < 9) or (current_datetime.hour > 17):
            return        
        if (current_datetime.day == 28) and \
            (current_datetime.month not in \
               self.extra_purchase_months):                    #2
            product_id = 5
            supplier_id = 10
            unit_cost = np.random.exponential() * 250.0
            trend_factor = np.log2(current_datetime.month+1) + 1
            num_purchased = int(np.random.randint(50, 60) * trend_factor)
            total_cost = num_purchased * unit_cost
            inventory[product_id] += num_purchased        
            transactions.append([
                    'Purchase', self.staff_id, supplier_id, 
                    product_id, 
               current_datetime.strftime("%Y-%m-%d %H:%M"),
                    num_purchased, unit_cost, total_cost, 
                    inventory[product_id]])            
            self.extra_purchase_months.append(current_datetime.month)
        
        elif np.random.random() > 0.01:
            product_id = np.random.choice(range(num_items_in_inventory))
            if product_id == 0:                                #3
                return            
            if inventory[product_id] > 1000:
                return        
            supplier_id = np.random.choice(range(num_suppliers))
            unit_cost = np.random.exponential() * 20.0
            num_purchased = np.random.randint(10, 200)         #4
            total_cost = num_purchased * unit_cost
            inventory[product_id] += num_purchased        
            transactions.append([
                    'Purchase', self.staff_id, supplier_id, product_id, 
                    current_datetime.strftime("%Y-%m-%d %H:%M"),
                    num_purchased, unit_cost, total_cost, 
                    inventory[product_id]])

The rogue purchaser illustrates a separate transaction-generating process with recurring purchases, changing quantities and higher sampled unit costs. section 11.4

Simulation is particularly useful for testing collective outliers: a segment can differ in aggregate even when its rows are individually unremarkable. Its advantage over simply duplicating or deleting records is that the intended anomalous behavior is known. That advantage depends on how well the simulated processes resemble the real setting. Simulations are difficult to set up, and synthetic tests should not replace later work with real data or use the same mechanism to define an outlier and validate its detection. section 12.1 section 11.6

How Outlier Detection in Python covers it

How deep it goes
Explains sequential agents and state through a company simulation, with Python listings; cautions that realistic simulations are difficult to set up.
Examples
Uses a year of purchase and sale transactions with inventory, plus a rogue purchaser whose purchases differ as a group.
What it assumes
Assumes familiarity with outlier detectors and tabular transactions while illustrating sequential simulation through a Python implementation.
What you can do after
Build it from scratch to generate plausible transaction histories with known anomalous behavior and test detector reliability across varied datasets.
How it connects
Connects synthetic data generation to collective outliers, time series analysis, detector evaluation and ground truth.

Also explained in

Compare how 6 books explain simulation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Outlier Detection in Python. The section links point to the parts of the book it draws on.