mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/cief-dashboard.git
synced 2026-08-19 04:24:13 +00:00
116 lines
4.0 KiB
Python
116 lines
4.0 KiB
Python
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)
|