pythonpython-3.xpandasmarket-basket-analysis

Market Basket Analysis


I have the following pandas dataset of transactions, regarding a retail shop:

print(df)

product       Date                   Assistant_name
product_1     2017-01-02 11:45:00    John
product_2     2017-01-02 11:45:00    John
product_3     2017-01-02 11:55:00    Mark
...

I would like to create the following dataset, for Market Basket Analysis:

product       Date                   Assistant_name  Invoice_number
product_1     2017-01-02 11:45:00    John            1
product_2     2017-01-02 11:45:00    John            1
product_3     2017-01-02 11:55:00    Mark            2
    ...

Briefly, if a transaction has the same Assistant_name and Date, I assume it does generate a new Invoice.


Solution

  • Simpliest is factorize with joined columns together:

    df['Invoice'] = pd.factorize(df['Date'].astype(str) + df['Assistant_name'])[0] + 1
    print (df)
         product                 Date Assistant_name  Invoice
    0  product_1  2017-01-02 11:45:00           John        1
    1  product_2  2017-01-02 11:45:00           John        1
    2  product_3  2017-01-02 11:55:00           Mark        2
    

    If performance is important use pd.lib.fast_zip:

    df['Invoice']=pd.factorize(pd.lib.fast_zip([df.Date.values, df.Assistant_name.values]))[0]+1
    

    Timings:

    #[30000 rows x 3 columns]
    df = pd.concat([df] * 10000, ignore_index=True)
    
    In [178]: %%timeit
         ...: df['Invoice'] = list(zip(df['Date'], df['Assistant_name']))
         ...: df['Invoice'] = df['Invoice'].astype('category').cat.codes + 1
         ...: 
    9.16 ms ± 54.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [179]: %%timeit
         ...: df['Invoice'] = pd.factorize(df['Date'].astype(str) + df['Assistant_name'])[0] + 1
         ...: 
    11.2 ms ± 395 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    In [180]: %%timeit 
         ...: df['Invoice'] = pd.factorize(pd.lib.fast_zip([df.Date.values, df.Assistant_name.values]))[0] + 1
         ...: 
    6.27 ms ± 93.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)