Files

116 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from app import *
import dash_table
from mlxtend.frequent_patterns import apriori
def get_market_basket(df, min_support=0.001, min_length=2, threshold=6):
df=pd.DataFrame(df).reset_index(drop=True).reset_index()
# preprocess
notation_replace={"\n":",", " *":"", "/":",", "":",", "":",", "\+":",", ".*":"","\*":""}
df['Description'].replace(notation_replace,regex=True,inplace=True)
# convert string to list then data frame
df['Description']=df['Description'].str.split(pat=',')
df=df.explode('Description')
# drop empty
df=df.mask(df['Description']=='').dropna()
# remoce descriptions have less records
description_count=df['Description'].groupby(df['Description']).count()
description_count=pd.DataFrame({'Description count':description_count}).reset_index()
description_count=description_count.where(description_count['Description count']>=threshold).dropna()
df=df.where(df['Description'].isin(description_count['Description'])).dropna()
# transform
df=pd.crosstab(df['index'], df['Description'])
df=df>0
# apriori
apriori_output=apriori(df, min_support=min_support,use_colnames=True)
apriori_output['length'] = apriori_output['itemsets'].apply(lambda x: len(x))
# table
apriori_output=apriori_output.where(apriori_output['length']>=min_length).dropna()
apriori_output=apriori_output.sort_values('support',ascending=False)
apriori_output['itemsets']=apriori_output['itemsets'].apply(lambda x: ','.join(map(str, x)))
return(apriori_output)
# layout
layout = html.Div([
html.H1('Market basket analysis'),
dbc.Row([
dbc.Col('Select the minimum length',width="auto"),
dbc.Col(
dcc.RadioItems(
options=[
{'label': 'One ', 'value': 1},
{'label': 'Two ', 'value': 2},
{'label': 'Three ', 'value': 3},
{'label': 'Four ', 'value': 4},
{'label': 'Five ', 'value': 5}
],
id='input-length',
value=2)
)
]),
dbc.Row([
dbc.Col('Select the minimum support',width="auto"),
dbc.Col(dcc.Input(id='input-support', type='number', value=0.001),width="auto"),
dbc.Col(html.Button('Update result', id='input-update'))
]),
# table
dbc.Row([
dash_table.DataTable(
id='output-apriori',
style_cell={
'height': 'auto',
# all three widths are needed
'minWidth': '180px', 'width': '250px', 'maxWidth': '360px',
'whiteSpace': 'normal'
},
page_current=0,
page_size=24,
page_action='custom',
sort_action='custom',
sort_mode='multi',
sort_by=[]
)
])
])
@app.callback(
[Output('output-apriori', 'columns'),
Output('output-apriori', 'data')],
[Input('output-apriori', "page_current"),
Input('input-update', 'n_clicks'),
Input('output-apriori', 'sort_by')],
[State('output-apriori', "page_size"),
State('input-support', 'value'),
State('input-length', 'value'),
State('data', 'data')]
)
def update_output(page_current, n_clicks, sort_by, page_size, support, length, data):
description=pd.read_json(data['warehouse'])
description=description['Description']
# ml
apriori_table=get_market_basket(description, min_support=support, min_length=length)
print('got apriori')
# sort
if len(sort_by):
apriori_table.sort_values(
[col['column_id'] for col in sort_by],
ascending=[col['direction'] == 'asc' for col in sort_by],
inplace=True)
# convert to dash table
columns=[{"name": i, "id": i} for i in apriori_table.columns]
data=apriori_table.iloc[page_current*page_size:(page_current+1)*page_size].to_dict('records')
return(columns,data)