Pages

Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Sunday, 26 June 2016

Monte Carlo simulation

Yesterday I coded a quick and dirty Monte-Carlo simulation function. Here it is.

def monte_carlo(df, n=1000, verbose=False):
    """Take a DataFrame of probabilities (in range 0..1) for outcomes (in columns)
       for each case (in rows), and conduct a Monte Carlo simulation.
       Return a tuple of three DataFrames. The first is the raw simulation results.
       The second is the outcome tally of those results for each simulation. 
       The third DataFrame returned is a binned summary of the tally for each outcome.
    """

    # contract
    assert((df.sum(axis=1) == 1.0).all)
    
    # monte carlo - we do this by rows to use the pandas.cut() function
    print('Doing the MC simulation ...')
    simulation = {}
    for (name, series) in df.iterrows():
        # for each case MC similate n outcomes ...
        if verbose:
            print(name)
        # set up this simulation
        votes = np.random.rand(n)
        s = series[series > 0.0]
        labels = s.index.tolist()
        cuts = [0.0] + s.cumsum().tolist()
        # and simulate
        simulation[name] = pd.cut(votes, bins=cuts, labels=labels, precision=7)

    # Take the dictionary of case outcomes above, 
    # Put them into a DataFrame as columns.
    # So that we can subsequently tally rows of simulation outcomes below.
    simulation = pd.DataFrame(simulation)

    # tally the results - for each simulation
    print('Tallying the results of the MC simulation ...')
    tally = {}
    for (name, series) in simulation.iterrows():  
        tally[name] = series.value_counts()
    tally = pd.DataFrame.from_dict(tally, orient='index')
    tally.fillna(0, inplace=True)
    tally = tally.astype(int)
    
    # - summarise into value_counts
    print('Summarising the tally of the MC simulation ...')
    summary = {}
    for (name, series) in tally.iteritems():
        summary[name] = series.value_counts()
    summary = pd.DataFrame(summary)
    summary.fillna(0, inplace=True)
    summary = summary.astype(int)

    # - return simulation summary
    return (simulation, tally, summary)


Sunday, 19 June 2016

Combining two lists into a human readable string

I wanted to list the odds I had scraped from a website as a comma delimited string list.

The first task was to join the party names with their odds.

The second challenge was to bring that list into a delimited string.

It took me a few goes to land the ideal approach

Let's start with some play data
names = ['Alpha', 'Beta', 'Gamma', 'Delta']
amounts = [1.20, 4.50, 151, 19.50]

My first go at combining the party names with their odds.
In [19]: [' '.join([a, str(b)]) for a, b in zip(names, amounts)]
Out[19]: ['Alpha 1.2', 'Beta 4.5', 'Gamma 151', 'Delta 19.5']

My second attempt
In [20]: [' '.join([a, '$'+ str(b)]) for a, b in zip(names, amounts)]
Out[20]: ['Alpha $1.2', 'Beta $4.5', 'Gamma $151', 'Delta $19.5']

My third attempt - this looks about right
In [21]: ['{} ${:.2f}'.format(a, b) for a, b in zip(names, amounts)]
Out[21]: ['Alpha $1.20', 'Beta $4.50', 'Gamma $151.00', 'Delta $19.50']

Now, to get that into a delimited string. Voila!
In [22]: ', '.join(['{} ${:.2f}'.format(a, b) for a, b in zip(names, amounts)])
Out[22]: 'Alpha $1.20, Beta $4.50, Gamma $151.00, Delta $19.50'