mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/cief-dashboard.git
synced 2026-08-25 23:44:11 +00:00
154 lines
8.9 KiB
Python
154 lines
8.9 KiB
Python
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)
|