Files
cief-dashboard/apps/apriori.py
T
2020-10-12 11:00:10 +08:00

154 lines
8.9 KiB
Python
Raw 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
df=pd.read_csv('data/warehouse1.csv',parse_dates=['Date'])
def select_date(df,start_date,end_date):
start_date=pd.Timestamp(start_date)
end_date=pd.Timestamp(end_date)
selected_df = df.loc[df.loc[:,'Date'] >= start_date]
selected_df = selected_df.loc[selected_df.loc[:,'Date'] <= end_date]
selected=selected_df.loc[:,['Cleaned Marking','Description']]
return(selected_df)
def preprocess(selected_df):
preprocessed_df=selected_df.copy()
notation_convertion={"\n":",", " *":"", "/":",", "":",", "":",", "\+":",", ".*":"","\*":""}
preprocessed_df.loc[:,'Description'].replace(to_replace=notation_convertion,regex=True,inplace=True)
description_convertion={
"^套锅$|^胶带$|^绳$|^拖鞋$|^挂钩$|^手套$|^绳子$|^洗衣凝珠$|^袋子$|^衣架$|^打托盘$|^冰袋$|^口罩$|^垫子$|^毛刷$|^抹布$|^盖子$|^消毒液$|^纸$|^毛巾$|^塑料盖$|^洗发水$|^抱枕$|^香皂花$|^塑料袋$|^胶袋$|^纸盒$|^垃圾袋$|^拖把架$|^拖把$|^包装袋$|^日用品$|家居用品":"生活用品",
"^碗架$|^陶瓷$|^杯$|^纸杯$|碗架}^套锅$|^塑料瓶$|^塑料盒$|^塑料杯盖$|^文胸收纳盒$|^便当盒$|^胶瓶$|^塑料杯$|^玻璃瓶$|^陶瓷杯$|^保温杯$|^电磁炉$|^锅$|^瓶子$|^吸管$|^杯子$|^厨具$|饭盒":"餐具",
"^购物车$|^眼镜展示架$|^保温箱$|^三件套$|^礼盒$|^香水瓶盖$|^展示架$|^婚庆用品$|^吊牌$|^货架$|礼品":"百货",
"^百货盒$|^手袋$|^包包$|^包$|^背包$|^双肩背包$|^单肩包$|^眼镜盒$|^纸箱$|^背带$|^包装盒$|^扶手箱$|^袋$|^收纳筐$|^化妆包$|^双肩包$|^手表盒$|^电脑包$|^包装袋$|^收纳盒$|^礼品盒$|^收纳袋$|^收纳包$|收纳箱":"箱包",
"^母婴产品$|^猫砂$|^母婴用品$|^水族用品$|^手推车配件$|^饲料$|^猫窝$|^宠物用品$|^学步车$|婴儿用品":"宠物婴儿",
"^电源$|^稳压器$|^相纸$|^音圈$|^功放$|^相框$|^耳机$|^电子琴架$|^鼓$|^小提琴$|^琴架$|^琴包$|^电鼓$|^乐器配件$|^电子琴$|^吉他$|^音箱$|^钢琴$|^音响$|^电子配件$|^插头$|^适配器$|^手机壳$|^手机配件$|^游戏机$|^网桥$|^电子$|数码产品":"电子产品",
"^水质改良剂$|^水质处理剂$|^滤芯$|^电池$|^机械配件$|^塑件$|^模具$|^防水材料$|^铝材$|^不锈钢$|^疏通器$|^按钮开关$|^劳保用品$|^原料$|^塑料$|^材料$|^线材$|^铁$|^贴纸$|^瓷砖$|^水龙头$|^提取物$|^滤芯$|^快递袋$|^包装材料$|^工具$|耗材":"五金",
"^PVC水池$|^灯$|^灯具$|^喷头$|^衣柜$|^门栏$|^家具配件$|^置物架$|^卫浴$|^止水针头$|^窗帘布$|^床$|PVC^水池$|^充气水池$|^水槽$|^爬行垫$|^花洒$|^地板$|^镜子$|^桌子$|^鞋架$|^风扇$|^地毯$|^沙发$|^电火锅$|^椅子$|^茶几$|^支架$|^架子$|^电炖锅$|按摩椅":"家具",
"^床笠$|^抱枕套$|^枕头$|枕套":"床上用品",
"^奶茶用品$|^保健品$|^固体饮料$|^牛奶$|^果汁$|^饮料$|^茶叶$|糖浆":"食品",
"^逆变器$|^风机网罩$|^风机$|^电子秤$|^净化器$|^家用电器$|^数码电器$|^冰淇淋机$|^娃娃机$|^烫画机$|^足疗机$|^覆膜机$|^眼镜仪器$|^焊接机器$|^封口机$|^按摩器$|^灭蚊灯$|^激光切割机$|^制冰机$|^原汁机$|^缝纫机$|^净水器$|^输送带$|^车载吸尘器$|^吸尘器$|^饮水机$|^切碎机$|^打印机$|^吸奶器$|^洗车器$|^雕刻机$|^水泵$|^设备$|喷绘机":"机器",
"^轴承$|^摩配$|^汽车配件$|^电动车$|^脚轮$|^电动自行车$|^自行车$|^汽车发电机$|^轮子$|^汽车发动机$|^轮胎$|^摩托车配件$|^座椅$|汽车用品":"汽配",
"^裙子$|^鞋$|^鞋子$|^裙子$|^内裤$|^无纺布$|^女士背心$|^披肩$|^狮头$|^袜子$|^眼镜配件$|^腰带$|^背心$|^女士内衣$|^珍珠$|^布鞋$|^化妆品$|^内衣$|^服装$|^睡衣$|^眼镜$|^车衣$|^衣服$|^连衣裙$|^针头$|^帽子$|^饰品$|^睡袋$|^女上衣$|^布$|^皮带$|布卷":"服饰",
"^瑜珈球$|^美腿机$|^甩脂机$|^瑜珈垫$|^跨栏$|^跳箱$|^篮球$|^体育用品$|^衣物$|^哑铃$|跑步机":"健身器材",
"^装饰品$|^工艺品$|^标签纸$|^切纸机$|墨水":"文具",
"^积木玩具$|^毛公仔$|^充气玩具$|^桌游$|桌面游戏":"玩具",
"^.*配件.*$":"配件", "^.*五金.*$":"五金", "^.*LED.*$":"家具",
}
df.loc[:,'Description'].replace(to_replace=description_convertion,regex=True,inplace=True)
# convert string to list then data frame
preprocessed_df.loc[:,'Description']=preprocessed_df.loc[:,'Description'].str.split(pat=',')
preprocessed_df=preprocessed_df.explode('Description')
# drop empty
preprocessed_df=preprocessed_df.loc[preprocessed_df.loc[:,'Description']!='']
# filter descriptions have more than 2 records
count_filter_df=preprocessed_df.loc[:,'Description'].value_counts()
count_filter_df=pd.DataFrame(count_filter_df)
count_filter_df.reset_index(inplace=True)
count_filter_df=count_filter_df.loc[count_filter_df.iloc[:,1]>2]
count_filter_df=count_filter_df.iloc[:,0]
count_filter_df=pd.DataFrame(count_filter_df)
count_filter_df.columns=['Description']
preprocessed_df=pd.merge(preprocessed_df, count_filter_df, how='right', on='Description')
return(preprocessed_df)
def transform(preprocessed_df):
transformed_df=pd.crosstab(preprocessed_df.loc[:,'Cleaned Marking'], preprocessed_df.loc[:,'Description'])
transformed_df=transformed_df>0
return(transformed_df)
def apriori_data_mining(transformed_df, min_support, min_length):
apriori_output=apriori(transformed_df, min_support=min_support,use_colnames=True)
apriori_output['length'] = apriori_output['itemsets'].apply(lambda x: len(x))
apriori_output=apriori_output.loc[apriori_output.loc[:,'length']>=min_length]
apriori_output=apriori_output.sort_values(by=['support'],ascending=False)
apriori_output.loc[:,'support']=apriori_output.loc[:,'support']
apriori_output.loc[:,'itemsets']=apriori_output.loc[:,'itemsets'].apply(lambda x: ','.join(map(str, x)))
return(apriori_output)
layout = html.Div([
html.H1('Market basket analysis'),
dbc.Row([
dbc.Col('Select date',width="auto"),
dbc.Col(
dcc.DatePickerRange(
id='input-date_range',
min_date_allowed=pd.Timestamp(2018, 1, 1),
max_date_allowed=pd.Timestamp(2020, 12, 31),
# initial_visible_month=pd.Timestamp(2020, 9, 1),
start_date=pd.Timestamp(2020, 7, 1),
end_date=pd.Timestamp(2020, 9, 1)
)
)
]),
dbc.Row([
dbc.Col('Select the minimum length of the market basket rules',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=1)
)
]),
dbc.Row([
dbc.Col(dcc.Input(id='input-support', type='number', value=0.1),width="auto"),
dbc.Col(html.Button('Update result', id='input-update'))
]),
# table
#html.Div([
dbc.Row([
dash_table.DataTable(
id='input-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'
)
])
# ],className="row"),
])
@app.callback(
[Output('input-output-apriori', 'columns'),
Output('input-output-apriori', 'data')],
[Input('input-output-apriori', "page_current"),
Input('input-update', 'n_clicks')],
[State('input-date_range', 'start_date'),
State('input-date_range', 'end_date'),
State('input-output-apriori', "page_size"),
State('input-support', 'value'),
State('input-length', 'value')]
)
def update_output(page_current, n_clicks,start_date,end_date,page_size,support,length):
if start_date is not None and end_date is not None:
selected_df=select_date(df,start_date,end_date)
else:
selected_df=select_date(df,'20190101','20200901')
preprocessed_df=preprocess(selected_df)
transfomed_df=transform(preprocessed_df)
apriori_output=apriori_data_mining(transfomed_df,support,length)
columns=[{"name": i, "id": i} for i in apriori_output.columns]
data=apriori_output.iloc[page_current*page_size:(page_current+1)*page_size].to_dict('records')
return(columns,data)