I've been learning Python like for a year and started learning a little about pandas DataFrame. I made this little program to practice all the concepts and would like to hear your suggestions for improvement.GOALThis program should plot how the inventory levels behave according some initials conditions: number of periods, demand distribution, lead time distribution and the chosen control policy (see types of policy).DEFINITIONS AND FORMULASinventory position =    on hand inventory + inventory on orderlead time = the amount of time between the placing of an order and the receipt of the goods ordered.NOTATIONs reorder point, Q order quantity, R review period, S order-up-to levelTYPES OF POLICYWe use four different base policy types: (s, Q)-policy. Whenever the inventory position reaches the reorder point s or drops below this point, an order of size Q is triggered.(s, S)-policy. Under this policy, the size of the order  triggered whenever the inventory position reaches or drops below the reorder point s  equals the difference between the order-up-to level S and the current inventory position.(R, S)-policy. The review period R indicates the length of the interval in-between two reviews. At these points of time, the inventory position is observed and the difference between the inventory position and the order-up-to level S is ordered.(R, s, S)-policy. Every R intervals the inventory position is checked. An order is triggered only if the inventory position has reached or dropped below the reorder point s. Then the order size equals the difference between the order-up-to level S and the current inventory position.import matplotlib.pyplot as pltimport numpy as npfrom pandas import DataFrame# The distribution factorydef make_distribution(function,*pars):    def distribution():        return function(*pars)    return distributiondef make_data(periods=52,               initial_inventory = 10,               demand_dist = make_distribution(np.random.normal,2,1),              lead_time_dist = make_distribution(np.random.triangular,1,2,3),              policy = {'method':'Qs', 'arguments': {'Q':3,'s':5}}):     Return a Pandas dataFrame that contains the details of the inventory simulation.    Keyword arguments:    periods           -- numbers of periods of the simulation (default 52 weeks)    initial_inventory -- initial inventory for the simulation    demand_dist       -- distribution of the demand (default triangular min=1, mode=2, max=3)     lead_time_dist    -- distribution of the lead time (default triangular min=1, mode=2, max=3)    policy            -- dict that contains the policy specs (default = {'method':'Qs', 'arguments': {'Q':3,'s':5}})        # Create zero-filled Dataframe    period_lst = np.arange(periods) # index    header = ['initial_inv_pos', 'initial_net_inv', 'demand', 'final_inv_pos',               'final_net_inv', 'lost_sales', 'avg_inv', 'order', 'lead_time'] # columns    df = DataFrame(index = period_lst, columns = header).fillna(0)    # Create a list that will store each period order    order_list = [Order(quantity=0, lead_time=0, sent=False) for x in range(periods)]     # Fill DataFrame    for period in period_lst:        if period == 0:            df['initial_inv_pos'][period] = initial_inventory            df['initial_net_inv'][period] = initial_inventory        else:            df['initial_inv_pos'][period] = df['final_inv_pos'][period-1] + order_list[period - 1].quantity            df['initial_net_inv'][period] = df['final_net_inv'][period-1] + pending_order(order_list, period)        df['demand'][period] = int(demand_dist())        df['final_inv_pos'][period] = df['initial_inv_pos'][period] - df['demand'][period]        order_list[period].quantity, order_list[period].lead_time, order_list[period].sent = placeorder(df['final_inv_pos'][period], policy, lead_time_dist, period)        df['final_net_inv'][period] = df['initial_net_inv'][period] - df['demand'][period]        if df['final_net_inv'][period] < 0:            df['lost_sales'][period] = abs(df['final_net_inv'][period])            df['final_net_inv'][period] = 0        else:            df['lost_sales'][period] = 0        df['avg_inv'][period] = 0        df['order'][period] = order_list[period].quantity        df['lead_time'][period] = order_list[period].lead_time         return dfdef placeorder(final_inv_pos, policy, lead_time_dist, period):    Place the order acording the inventory policy:        Keywords arguments:       final_inv_pos    -- final inventory position of period       policy           -- chosen policy Reorder point (Qs, Ss) or Periodic Review (RS, Rss)       lead_time_dist   -- distribution of lead time       period           -- actual period        lead_time = int(lead_time_dist())    # Qs = if we hit the reorder point s, order Q units    if policy['method'] == 'Qs' and \       final_inv_pos <= policy['arguments']['s']:        return policy['arguments']['Q'], lead_time, True    # Ss = if we hit the reorder point s, order S - final inventory pos    elif policy['method'] == 'Ss' and \         final_inv_pos <= policy['arguments']['s']:        return policy['arguments']['S'] - final_inv_pos, lead_time, True    # RS = if we hit the review period and the reorder point S, order S - final inventory pos    elif policy['method'] == 'RS' and \         period%policy['arguments']['R'] == 0 and \         final_inv_pos <= policy['arguments']['S']:        return policy['arguments']['S'] - final_inv_pos, lead_time, True    # RSs = if we hit the review period and the reorder point s, order S - final inventory pos    elif policy['method'] == 'RSs' and \         period%policy['arguments']['R'] == 0 and \         final_inv_pos <= policy['arguments']['s']:        return policy['arguments']['S'] - final_inv_pos, lead_time, True    # If the conditions arent satisfied, do not order    else:        return 0, 0, Falsedef pending_order(order_list, period):    Return the order that arrives in actual period    indices = [i for i, order in enumerate(order_list) if order.sent == True]    sum = 0    for i in indices:        if period - (i + order_list[i].lead_time +1) == 0:             sum += order_list[i].quantity    return sumclass Order(object):    Object that stores basic data of an order    def __init__(self, quantity, lead_time, sent):        self.quantity = quantity        self.lead_time = lead_time        self.sent = sent # True if the order is already sentdef make_plot(df, policy, period):    #Plot    plt.rcParams['figure.figsize'] = 15,4 #define the fig size    fig = plt.figure()    ax = fig.add_subplot(111)    y1 = df['final_inv_pos']    l1, = plt.plot(y1, 'k', linewidth=1.2, drawstyle='steps', label='Final Inv')    if policy['method'] == 'Qs':        title = 'Simulation Policy = (Q: {Q}, s: {s})'.format(**policy['arguments'])        y2 = policy['arguments']['s']*np.ones(period)        l2, = plt.plot(y2, 'r:', label='Reorder point')    elif policy['method'] == 'Ss':        #TODO        pass    t = ax.set_title(title)    ax.tick_params(axis='both', which='major', labelsize=8)    plt.xticks(np.arange(period))    plt.ylim(bottom=0)         plt.legend(loc='best', prop={'size':10})    plt.xlabel(Periods)    plt.ylabel(Inventory Level)    plt.show()def simulate():    #parameters of simulation    Qs_policy   = {'method':'Qs', 'arguments': {'Q':3,'s':5}}    demand_dist = make_distribution(np.random.normal,3,1)    lead_time_dist = make_distribution(np.random.triangular,1,4,5)    period = 52    df = make_data(period,10,demand_dist,lead_time_dist,Qs_policy)    #df.to_csv(out.csv)    make_plot(df, Qs_policy, period)if __name__ == '__main__':    simulate()
Inventory simulation using Pandas DataFrame
python;simulation;pandas