大数据分析——某电商平台药品销售数据分析
大数据分析——某电商平台药品销售数据分析
一、 选题背景
我们已经习惯了在网上购买衣服、数码产品和家用电器,但是在网上买药品的还是不多。据史国网上药店理事会调查报告显示:2022 年,医药 B2C 的规模达到 4 亿元,仅出现 5 家锁售额达.5000 万元的网上药店。而 2022 年医药行业的市场规模达到3718 亿,线上药品的销售额还不到网下药店的一个零头,还有很大的发展潜力。大数据的不断发展影响消费者生活的各个方面,也对企业的营销模式提出挑站对大 数据量化分析,分析数据中的相关性分析,单因素分析等技术对消费者相关数据进行分析,能够挖掘出对企业真正有意义的信息。这就要求企业在有现的人力、物力资源下, 更新并找出合理的销售方案。对于医药企业来说,大数据为企业带来了危机也带来了商机,企业应根据自身发展阶段及药品特征,以及顾客价值最大化作为方向,以信息化为手段,并根据市场对药品需求的变化,把握消费者的个性需求,进行精准营销,与消费者建立起良性有效的互动,及时获得消费者反馈,整合传统媒体与新媒体宣传资源,选择合适的企业发展的营销战略。
二、 大数据分析设计方案
1.本数据集的数据内容数据特征分析
本数据集是一份网络电商平台的药品销售数据集,共7个字段,包括购药时间(string),社保卡号(int),商品编码(int),商品名称(string),销售数量(int),应收金额(int),实收金额(int)。
2.数据分析的课程设计方案概述
(1)先对数据进行预处理和清洗
(2)数据分析和可视化
(3)随机森林填补缺失值
三、数据分析步骤
1.数据源
数据集来源于国外Kaggle数据集网站进行采集。源数据集网址
https://www.kaggle.com/datasets/jack20216915/yaopin
导入库
1 import pandas as pd 2 import stylecloud 3 from PIL import Image 4 from collections import Counter 5 from pyecharts.charts import Bar 6 from pyecharts.charts import Line 7 from pyecharts.charts import Calendar 8 from pyecharts import options as opts 9 from pyecharts.commons.utils import JsCode 10 from pyecharts.globals import SymbolType
读取数据集
1 df = pd.read_excel('电商平台药品销售数据.xlsx') 2 df.head(10)

2数据清洗
数据清洗, 是整个数据分析过程中不可缺少的一个环节,其结果质量直接关系到模型效果和最终结论。在实际操作中,数据清洗通常会占据分析过程的50%—80%的时间。
(1)查看索引、数据类型和内存信息
info() 函数用于打印 DataFrame 的简要摘要,显示有关 DataFrame 的信息,包括索 引的数据类型 dtype 和列的数据类型 dtype,非空值的数量和内存使用情况
1 df.info()

(2)统计空值数据
使用 isnull() 函数时不需要传入任何参数,只需要使用 df 对象去调用它就可以了。 该方法运行之后会将整个表格对象内的所有数据都转为 True 值以及 False 值,其中 NaN 值转换之后得到就是 True
1 df.isnull().sum()

(3) 输出包含空值的行

因为购药时间在后面的分析中会用到,所以我们将购药时间为空的行删除

(4)社保卡号用”000” 填充
fillna() 函数的功能: 该函数的功能是用指定的值去填充 dataframe 中的缺失值
1 df1['社保卡号'].fillna('0000', inplace=True) 2 df1.isnull().sum()

此时可以看到没有空值了
(5)社保卡号、商品编码为一串数字,应为 str 类型,销售数量应为 int 类型
1 df1['社保卡号'] = df1['社保卡号'].astype(str) 2 df1['商品编码'] = df1['商品编码'].astype(str) 3 df1['销售数量'] = df1['销售数量'].astype(int) 4 df1.info() 5 df1.head()

虽然这里强制转换社保卡号、商品编码为 str 类型,但是在读取表格的时候是以 float 读取的,所以存在小数点,这里我们可以在读取表格文件时指定相应列的数据类型 (需要注意如果数据存在空值,那么转换数值型时会失效):
1 df_tmp = pd.read_excel('电商平台药品销售数据.xlsx', converters={'社保卡号':str, '商品编码':str, '销售数量':int}) 2 df_tmp.head()

(6)销售数量、应收金额、实收金额分布情况
1 df2 = df_tmp.copy() 2 df2 = df2.dropna(subset=['购药时间']) 3 df2['社保卡号'].fillna('0000', inplace=True) 4 df2['销售数量'] = df2['销售数量'].astype(int) 5 df2[['销售数量','应收金额','实收金额']].describe()

数据中存在负值,显然不合理,我们看一下负值所在的行
1 df2.loc[(df2['销售数量'] < 0)]

(7)负值转正值
abs 是 python 的绝对值函数,计算绝对值,数据值转为正值
1 df2['销售数量'] = df2['销售数量'].abs() 2 df2['应收金额'] = df2['应收金额'].abs() 3 df2['实收金额'] = df2['实收金额'].abs() 4 df2.loc[(df2['销售数量'] < 0) | (df2['应收金额'] < 0) | (df2['实收金额'] < 0)].sum()

(8)列拆分(购药时间列拆分为两列)
对字符串按照指定规则分割,并将分割后的字段作为 list 返回,对购药日期和星期 两列进行分隔,进行列拆分
1 df3 = df2.copy() 2 df3[['购药日期', '星期']] = df3['购药时间'].str.split(' ', 2, expand = True) 3 df3 = df3[['购药日期', '星期','社保卡号','商品编码', '商品名称', '销售数量', '应收金额', '实收金额' ]] 4 df3

(9) 数据时间范围
unique 函数去除其中重复的元素,并按元素由大到小返回一个新的无元素重复的元组或者列表
1 len(df3['购药日期'].unique()) 2 df3.groupby('购药日期').sum()

一共201个购买日期,时间范围2016-01-01至2016-07-19
3数据可视化
pyecharts可以展示动态图,在线报告使用比较美观,并且展示数据方便,鼠标悬停在图上,即可显示数值、标签等。
(1)一周各天药品销量柱状图
1 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 2 [{offset: 0, color: '#FFFFFF'}, {offset: 1, color: '#ed1941'}], false)""" 3 4 g1 = df3.groupby('星期').sum() 5 x_data = list(g1.index) 6 y_data = g1['销售数量'].values.tolist() 7 b1 = ( 8 Bar() 9 .add_xaxis(x_data) 10 .add_yaxis('',y_data ,itemstyle_opts=opts.ItemStyleOpts(color=JsCode(color_js))) 11 .set_global_opts(title_opts=opts.TitleOpts(title='一周各天药品销量',pos_top='2%',pos_left = 'center'), 12 legend_opts=opts.LegendOpts(is_show=False), 13 xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), 14 yaxis_opts=opts.AxisOpts(name="销量",name_location='middle',name_gap=50,name_textstyle_opts=opts.TextStyleOpts(font_size=16))) 15 16 ) 17 b1.render('一周各天药品销量柱状图.html')

从下图可以清楚直观的看到每一周药品的销量,我发现每天销量整体相差不大,周五、周六偏于购药高峰。
(2)药品销量前十柱状图
1 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 2 [{offset: 0, color: '#FFFFFF'}, {offset: 1, color: '#08519c'}], false)""" 3 4 g2 = df3.groupby('商品名称').sum().sort_values(by='销售数量', ascending=False) 5 x_data = list(g2.index)[:10] 6 y_data = g2['销售数量'].values.tolist()[:10] 7 b2 = ( 8 Bar() 9 .add_xaxis(x_data) 10 .add_yaxis('',y_data ,itemstyle_opts=opts.ItemStyleOpts(color=JsCode(color_js))) 11 .set_global_opts(title_opts=opts.TitleOpts(title='药品销量前十',pos_top='2%',pos_left = 'center'), 12 legend_opts=opts.LegendOpts(is_show=False), 13 xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), 14 yaxis_opts=opts.AxisOpts(name="销量",name_location='middle',name_gap=50,name_textstyle_opts=opts.TextStyleOpts(font_size=16))) 15 16 ) 17 b2.render('药品销量前十柱状图.html')

我们在这可以看出:苯磺酸氨氯地平片 (安内真)、开博通、酒石酸美托洛尔片 (倍他乐克) 等治疗高血压、心绞痛药物购买量比较多
(3)药品销售额前十柱状图
1 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 2 [{offset: 0, color: '#FFFFFF'}, {offset: 1, color: '#871F78'}], false)""" 3 4 g3 = df3.groupby('商品名称').sum().sort_values(by='实收金额', ascending=False) 5 x_data = list(g3.index)[:10] 6 y_data = g3['实收金额'].values.tolist()[:10] 7 b3 = ( 8 Bar() 9 .add_xaxis(x_data) 10 .add_yaxis('',y_data ,itemstyle_opts=opts.ItemStyleOpts(color=JsCode(color_js))) 11 .set_global_opts(title_opts=opts.TitleOpts(title='药品销售额前十',pos_top='2%',pos_left = 'center'), 12 legend_opts=opts.LegendOpts(is_show=False), 13 xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), 14 yaxis_opts=opts.AxisOpts(name="销量",name_location='middle',name_gap=50,name_textstyle_opts=opts.TextStyleOpts(font_size=16))) 15 16 ) 17 b3.render('药品销售额前十柱状图.html')

我们可以清楚看到药品销售额前十的条形图,我们发现开播通销售额最高,为37671
(4)一周每天订单量
1 # 设置样式 2 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 3 [{offset: 0, color: '#25BEAD'}, {offset: 1, color: '#ed1941'}], false)""" 4 5 area_color_js = ( 6 "new echarts.graphic.LinearGradient(0, 0, 0, 1, " 7 "[{offset: 0, color: '#25BEAD'}, {offset: 1, color: '#3fbbff0d'}], false)" 8 ) 9 # 一周每天订单量 10 df_week = df3.groupby(['星期'])['实收金额'].count() 11 week_x_data = df_week.index 12 week_y_data = df_week.values.tolist() 13 14 line1 = ( 15 Line(init_opts=opts.InitOpts(bg_color=JsCode(color_js))) 16 .add_xaxis(xaxis_data=week_x_data) 17 .add_yaxis( 18 series_name="", 19 y_axis=week_y_data, 20 is_smooth=True, 21 is_symbol_show=True, 22 symbol="circle", 23 symbol_size=6, 24 linestyle_opts=opts.LineStyleOpts(color="#fff"), 25 label_opts=opts.LabelOpts(is_show=True, position="top", color="white"), 26 itemstyle_opts=opts.ItemStyleOpts( 27 color="red", border_color="#fff", border_width=3 28 ), 29 tooltip_opts=opts.TooltipOpts(is_show=False), 30 areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), 31 ) 32 .set_global_opts( 33 title_opts=opts.TitleOpts( 34 title="一周每天订单量", 35 pos_top="2%", 36 pos_left="center", 37 title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), 38 ), 39 xaxis_opts=opts.AxisOpts( 40 type_="category", 41 boundary_gap=True, 42 axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63",font_weight =900), 43 axisline_opts=opts.AxisLineOpts(is_show=False), 44 axistick_opts=opts.AxisTickOpts( 45 is_show=True, 46 length=25, 47 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 48 ), 49 splitline_opts=opts.SplitLineOpts( 50 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 51 ), 52 ), 53 yaxis_opts=opts.AxisOpts( 54 type_="value", 55 position="left", 56 axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), 57 axisline_opts=opts.AxisLineOpts( 58 linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") 59 ), 60 axistick_opts=opts.AxisTickOpts( 61 is_show=True, 62 length=15, 63 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 64 ), 65 splitline_opts=opts.SplitLineOpts( 66 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 67 ), 68 ), 69 legend_opts=opts.LegendOpts(is_show=False), 70 ) 71 ) 72 line1.render('一周每天订单量分析图.html')

我们通过折线图来分析每周的订单数量
(5)自然月每天订单数量
1 # 自然月每天订单数量 2 df3['购药日期'] = pd.to_datetime(df3['购药日期']) 3 df_day = df3.groupby(df3['购药日期'].dt.day)['星期'].count() 4 day_x_data = [str(i) for i in list(df_day.index)] 5 day_y_data = df_day.values.tolist() 6 line1 = ( 7 Line(init_opts=opts.InitOpts(bg_color=JsCode(color_js))) 8 .add_xaxis(xaxis_data=day_x_data) 9 .add_yaxis( 10 series_name="", 11 y_axis=day_y_data, 12 is_smooth=True, 13 is_symbol_show=True, 14 symbol="circle", 15 symbol_size=6, 16 linestyle_opts=opts.LineStyleOpts(color="#fff"), 17 label_opts=opts.LabelOpts(is_show=True, position="top", color="white"), 18 itemstyle_opts=opts.ItemStyleOpts( 19 color="red", border_color="#fff", border_width=3 20 ), 21 tooltip_opts=opts.TooltipOpts(is_show=False), 22 areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), 23 ) 24 .set_global_opts( 25 title_opts=opts.TitleOpts( 26 title="自然月每日订单量", 27 pos_top="5%", 28 pos_left="center", 29 title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), 30 ), 31 xaxis_opts=opts.AxisOpts( 32 type_="category", 33 boundary_gap=True, 34 axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63",font_weight =900), 35 axisline_opts=opts.AxisLineOpts(is_show=False), 36 axistick_opts=opts.AxisTickOpts( 37 is_show=True, 38 length=25, 39 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 40 ), 41 splitline_opts=opts.SplitLineOpts( 42 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 43 ), 44 ), 45 yaxis_opts=opts.AxisOpts( 46 type_="value", 47 position="left", 48 axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), 49 axisline_opts=opts.AxisLineOpts( 50 linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") 51 ), 52 axistick_opts=opts.AxisTickOpts( 53 is_show=True, 54 length=15, 55 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 56 ), 57 splitline_opts=opts.SplitLineOpts( 58 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 59 ), 60 ), 61 legend_opts=opts.LegendOpts(is_show=False), 62 ) 63 ) 64 line1.render('自然月每天订单数量分析图.html')

可以看出:5 日、15 日、25 日是药品销售高峰期,尤其是每月 15 日
(6)每月订单数量
1 # 每月订单数量 2 df_month = df3.groupby(df3['购药日期'].dt.month)['星期'].count() 3 day_x_data = [str(i)+'月' for i in list(df_month.index)] 4 day_y_data = df_month.values.tolist() 5 line1 = ( 6 Line(init_opts=opts.InitOpts(bg_color=JsCode(color_js))) 7 .add_xaxis(xaxis_data=day_x_data) 8 .add_yaxis( 9 series_name="", 10 y_axis=day_y_data, 11 is_smooth=True, 12 is_symbol_show=True, 13 symbol="circle", 14 symbol_size=6, 15 linestyle_opts=opts.LineStyleOpts(color="#fff"), 16 label_opts=opts.LabelOpts(is_show=True, position="top", color="black"), 17 itemstyle_opts=opts.ItemStyleOpts( 18 color="red", border_color="#fff", border_width=3 19 ), 20 tooltip_opts=opts.TooltipOpts(is_show=False), 21 areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), 22 ) 23 .set_global_opts( 24 title_opts=opts.TitleOpts( 25 title="每月订单量", 26 pos_top="2%", 27 pos_left="center", 28 title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), 29 ), 30 xaxis_opts=opts.AxisOpts( 31 type_="category", 32 boundary_gap=True, 33 axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63",font_weight =900), 34 axisline_opts=opts.AxisLineOpts(is_show=False), 35 axistick_opts=opts.AxisTickOpts( 36 is_show=True, 37 length=25, 38 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 39 ), 40 splitline_opts=opts.SplitLineOpts( 41 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 42 ), 43 ), 44 yaxis_opts=opts.AxisOpts( 45 type_="value", 46 position="left", 47 axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), 48 axisline_opts=opts.AxisLineOpts( 49 linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") 50 ), 51 axistick_opts=opts.AxisTickOpts( 52 is_show=True, 53 length=15, 54 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 55 ), 56 splitline_opts=opts.SplitLineOpts( 57 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 58 ), 59 ), 60 legend_opts=opts.LegendOpts(is_show=False), 61 ) 62 ) 63 line1.render('每月订单数量分析图.html')

在这里我们可以发现 1 月份和 4 月份药品销售数据较其他几个月更多
(7)五月每日订单量
1 # 五月每日订单量 2 colors = ['#C9DA36','#9ECB3C','#6DBC49','#37B44E','#3DBA78','#7D3990','#A63F98','#C31C88','#F57A34','#FA8F2F','#CF7B25','#CF7B25','#FF5733','#C70039'] 3 df_day = df3.groupby(df3['购药日期'].dt.day)['星期'].count() 4 day_x_data = [str(i) for i in list(df_day.index)] 5 day_y_data = df_day.values.tolist() 6 times = [x.strftime('%Y-%m-%d') for x in list(pd.date_range('20160501', '20160531'))] 7 data = [[times[index],day_y_data[index]] for index,item in enumerate( day_y_data)] 8 Cal = ( 9 Calendar(init_opts=opts.InitOpts(width="800px", height="500px")) 10 .add( 11 series_name="五月每日订单量分布情况", 12 yaxis_data=data, 13 calendar_opts=opts.CalendarOpts( 14 pos_top='20%', 15 pos_left='5%', 16 range_="2016-05", 17 cell_size=40, 18 # 年月日标签样式设置 19 daylabel_opts=opts.CalendarDayLabelOpts(name_map="cn", 20 margin=20, 21 label_font_size=14, 22 label_color='#EB1934', 23 label_font_weight='bold' 24 ), 25 monthlabel_opts=opts.CalendarMonthLabelOpts(name_map="cn", 26 margin=20, 27 label_font_size=14, 28 label_color='#EB1934', 29 label_font_weight='bold', 30 is_show=False 31 ), 32 yearlabel_opts=opts.CalendarYearLabelOpts(is_show=False), 33 ), 34 tooltip_opts='{c}', 35 ) 36 .set_global_opts( 37 title_opts=opts.TitleOpts( 38 pos_top="2%", 39 pos_left="center", 40 title="" 41 ), 42 visualmap_opts=opts.VisualMapOpts( 43 orient="horizontal", 44 max_=800, 45 pos_bottom='10%', 46 is_piecewise=True, 47 pieces=[{"min": 600}, 48 {"min": 300, "max": 599}, 49 {"min": 200, "max": 299}, 50 {"min": 160, "max": 199}, 51 {"min": 100, "max": 159}, 52 {"max": 99}], 53 range_color=['#ffeda0','#fed976','#fd8d3c','#fc4e2a','#e31a1c','#b10026'] 54 55 ), 56 legend_opts=opts.LegendOpts(is_show=True, 57 pos_top='5%', 58 item_width = 50, 59 item_height = 30, 60 textstyle_opts=opts.TextStyleOpts(font_size=16,color='#EB1934'), 61 legend_icon ='path://path://M465.621333 469.333333l-97.813333-114.133333a21.333333 21.333333 0 1 1 32.384-27.733333L512 457.856l111.786667-130.432a21.333333 21.333333 0 1 1 32.426666 27.776L558.357333 469.333333h81.493334c11.84 0 21.461333 9.472 21.461333 21.333334 0 11.776-9.6 21.333333-21.482667 21.333333H533.333333v85.333333h106.517334c11.861333 0 21.482667 9.472 21.482666 21.333334 0 11.776-9.6 21.333333-21.482666 21.333333H533.333333v127.850667c0 11.861333-9.472 21.482667-21.333333 21.482666-11.776 0-21.333333-9.578667-21.333333-21.482666V640h-106.517334A21.354667 21.354667 0 0 1 362.666667 618.666667c0-11.776 9.6-21.333333 21.482666-21.333334H490.666667v-85.333333h-106.517334A21.354667 21.354667 0 0 1 362.666667 490.666667c0-11.776 9.6-21.333333 21.482666-21.333334h81.472zM298.666667 127.957333C298.666667 104.405333 317.824 85.333333 341.12 85.333333h341.76C706.304 85.333333 725.333333 104.490667 725.333333 127.957333v42.752A42.645333 42.645333 0 0 1 682.88 213.333333H341.12C317.696 213.333333 298.666667 194.176 298.666667 170.709333V127.957333zM341.333333 170.666667h341.333334V128H341.333333v42.666667z m-105.173333-42.666667v42.666667H170.752L170.666667 895.893333 853.333333 896V170.773333L789.909333 170.666667V128h63.296C876.842667 128 896 147.072 896 170.773333v725.12C896 919.509333 877.013333 938.666667 853.333333 938.666667H170.666667a42.666667 42.666667 0 0 1-42.666667-42.773334V170.773333C128 147.157333 147.114667 128 170.752 128h65.408z' 62 ), 63 ) 64 ) 65 Cal.render('五月每日订单量分析图.html')

我们把五月每日订单单独拿出来分析,可以看出:苯磺酸氨氯地平片 (安内真)、开博通、酒石酸美托洛尔片 (倍他乐克) 等治疗高血压、心绞痛药物购买量比较多
(8)药品销售数据词云
1 # 词云 2 g = df3.groupby('商品名称').sum() 3 drug_list = [] 4 for idx, value in enumerate(list(g.index)): 5 drug_list += [value] * list(g['销售数量'].values)[idx] 6 stylecloud.gen_stylecloud( 7 text=' '.join(drug_list), 8 font_path=r'STXINWEI.TTF', 9 palette='cartocolors.qualitative.Bold_5',# 设置配色方案 10 icon_name='fas fa-lock', # 设置蒙版方案 11 # background_color='black', 12 max_font_size=200, 13 output_name='药品销量.png', 14 ) 15 Image.open("药品销量.png")

4.随机森林填补缺失值
利用随机森林进行填补缺失值的思想:随机森林是进行回归的操作,我们可以把那 些包含缺失值的列当作标签,如果是很多列都有缺失值,那么就要按照每一列的缺失 值的从小到大来填补(因为这样子的话,正确率会更加高一些,因为缺失值少的那个 对特征等的要求更加低一些),然后在将剩下和原本就已经给的标签组成新的特征矩阵 (一般情况下,最开始的标签是不会有缺失值的),在这个特征矩阵里面,将缺失值利用 numpy,pandas 或者 sklearn 的 impleImputer 填补为 0,因为 0 对数据的影响比较小。接着 就是将取出的那个新的标签列,按照有没有缺失值分为 Ytrain 和 Ytest,同样的道理,按 照新标签列有缺失值所在的行的位置,将新的特征矩阵分为 Xtrain 和 Xtest,然后就可 以利用 RandomForestRegressor() 来进行训练和预测,利用 predict 接口来得到最后的 Y, 其实在前面的 Ytest 并没有用处,只是来确定所在的行而已。在这里的 predict 出来的就 是要填补的内容,将它把 Ytest 覆盖就可以了。如果有缺失值的列很多的话,就可以使 用循环,不断的预测就可以了。最后所填补的缺失值的正确率要远比利用 0 填补,均值 填补,中位数填补,最多数填补的高。
1 from sklearn.impute import SimpleImputer 2 from sklearn.ensemble import RandomForestRegressor 3 import numpy as np 4 data_copy = df.copy() 5 data_copy.drop(data_copy.columns[0], axis=1, inplace=True) 6 sindex = np.argsort(data_copy.isnull().sum()).values 7 8 # 进行缺失值的填补,利用随机森林进行填补缺失值 9 for i in sindex : 10 if data_copy.iloc[:,i].isnull().sum() == 0 : 11 continue 12 df = data_copy 13 fillc = df.iloc[:, i] 14 df = df.iloc[:,df.columns!=df.columns[i]] 15 16 #在下面的是使用了0来对特征矩阵中的缺失值的填补, 17 df_0 = SimpleImputer(missing_values=np.nan 18 ,strategy="constant" 19 ,fill_value=0 20 ).fit_transform(df) 21 Ytrain = fillc[fillc.notnull()] 22 Ytest = fillc[fillc.isnull()] 23 24 Xtrain = df_0[Ytrain.index,:] 25 Xtest = df_0[Ytest.index,:] 26 27 rfc = RandomForestRegressor() 28 rfc.fit(Xtrain, Ytrain) 29 Ypredict = rfc.predict(Xtest) 30 31 data_copy.loc[data_copy.iloc[:,i].isnull(),data_copy.columns[i]] = Ypredict 32 data_copy.isnull().sum()

5完整代码附上
1 import pandas as pd 2 import stylecloud 3 from sklearn.impute import SimpleImputer 4 from sklearn.ensemble import RandomForestRegressor 5 import numpy as np 6 from PIL import Image 7 from collections import Counter 8 from pyecharts.charts import Bar 9 from pyecharts.charts import Line 10 from pyecharts.charts import Calendar 11 from pyecharts import options as opts 12 from pyecharts.commons.utils import JsCode 13 from pyecharts.globals import SymbolType 14 df = pd.read_excel('电商平台药品销售数据.xlsx') 15 df.head(10) 16 from sklearn.impute import SimpleImputer 17 import numpy as np 18 # 取出缺失值所在列的数值,sklearn当中特征矩阵必须是二维才能传入 使用reshape(-1,1)升维 19 sums=df['实收金额'].values.reshape(-1,1) 20 # 按平均值填充 21 imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean') 22 imp_mean=imp_mean.fit_transform(sums) 23 24 df['实收金额']=imp_mean 25 df 26 df.info() 27 df.shape 28 df.isnull().sum() 29 df[df.isnull().T.any()] 30 df1 = df.copy() 31 df1 = df1.dropna(subset=['购药时间']) 32 df1[df1.isnull().T.any()] 33 df1['社保卡号'].fillna('0000', inplace=True) 34 df1.isnull().sum() 35 df1['社保卡号'] = df1['社保卡号'].astype(str) 36 df1['商品编码'] = df1['商品编码'].astype(str) 37 df1['销售数量'] = df1['销售数量'].astype(int) 38 df1.info() 39 df1.head() 40 df_tmp = pd.read_excel('电商平台药品销售数据.xlsx', converters={'社保卡号':str, '商品编码':str, '销售数量':int}) 41 df_tmp.head() 42 df2 = df_tmp.copy() 43 df2 = df2.dropna(subset=['购药时间']) 44 df2['社保卡号'].fillna('0000', inplace=True) 45 df2['销售数量'] = df2['销售数量'].astype(int) 46 df2[['销售数量','应收金额','实收金额']].describe() 47 df2.loc[(df2['销售数量'] < 0)] 48 df2['销售数量'] = df2['销售数量'].abs() 49 df2['应收金额'] = df2['应收金额'].abs() 50 df2['实收金额'] = df2['实收金额'].abs() 51 df2.loc[(df2['销售数量'] < 0) | (df2['应收金额'] < 0) | (df2['实收金额'] < 0)].sum() 52 df3 = df2.copy() 53 df3[['购药日期', '星期']] = df3['购药时间'].str.split(' ', 2, expand = True) 54 df3 = df3[['购药日期', '星期','社保卡号','商品编码', '商品名称', '销售数量', '应收金额', '实收金额' ]] 55 df3 56 len(df3['购药日期'].unique()) 57 df3.groupby('购药日期').sum() 58 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 59 [{offset: 0, color: '#FFFFFF'}, {offset: 1, color: '#ed1941'}], false)""" 60 61 g1 = df3.groupby('星期').sum() 62 x_data = list(g1.index) 63 y_data = g1['销售数量'].values.tolist() 64 b1 = ( 65 Bar() 66 .add_xaxis(x_data) 67 .add_yaxis('',y_data ,itemstyle_opts=opts.ItemStyleOpts(color=JsCode(color_js))) 68 .set_global_opts(title_opts=opts.TitleOpts(title='一周各天药品销量',pos_top='2%',pos_left = 'center'), 69 legend_opts=opts.LegendOpts(is_show=False), 70 xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), 71 yaxis_opts=opts.AxisOpts(name="销量",name_location='middle',name_gap=50,name_textstyle_opts=opts.TextStyleOpts(font_size=16))) 72 73 ) 74 b1.render('一周各天药品销量柱状图.html') 75 76 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 77 [{offset: 0, color: '#FFFFFF'}, {offset: 1, color: '#08519c'}], false)""" 78 79 g2 = df3.groupby('商品名称').sum().sort_values(by='销售数量', ascending=False) 80 x_data = list(g2.index)[:10] 81 y_data = g2['销售数量'].values.tolist()[:10] 82 b2 = ( 83 Bar() 84 .add_xaxis(x_data) 85 .add_yaxis('',y_data ,itemstyle_opts=opts.ItemStyleOpts(color=JsCode(color_js))) 86 .set_global_opts(title_opts=opts.TitleOpts(title='药品销量前十',pos_top='2%',pos_left = 'center'), 87 legend_opts=opts.LegendOpts(is_show=False), 88 xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)), 89 yaxis_opts=opts.AxisOpts(name="销量",name_location='middle',name_gap=50,name_textstyle_opts=opts.TextStyleOpts(font_size=16))) 90 91 ) 92 b2.render('药品销量前十柱状图改.html') 93 94 # 设置样式 95 color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0, 96 [{offset: 0, color: '#25BEAD'}, {offset: 1, color: '#ed1941'}], false)""" 97 98 area_color_js = ( 99 "new echarts.graphic.LinearGradient(0, 0, 0, 1, " 100 "[{offset: 0, color: '#25BEAD'}, {offset: 1, color: '#3fbbff0d'}], false)" 101 ) 102 # 一周每天订单量 103 df_week = df3.groupby(['星期'])['实收金额'].count() 104 week_x_data = df_week.index 105 week_y_data = df_week.values.tolist() 106 107 line1 = ( 108 Line(init_opts=opts.InitOpts(bg_color=JsCode(color_js))) 109 .add_xaxis(xaxis_data=week_x_data) 110 .add_yaxis( 111 series_name="", 112 y_axis=week_y_data, 113 is_smooth=True, 114 is_symbol_show=True, 115 symbol="circle", 116 symbol_size=6, 117 linestyle_opts=opts.LineStyleOpts(color="#fff"), 118 label_opts=opts.LabelOpts(is_show=True, position="top", color="white"), 119 itemstyle_opts=opts.ItemStyleOpts( 120 color="red", border_color="#fff", border_width=3 121 ), 122 tooltip_opts=opts.TooltipOpts(is_show=False), 123 areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), 124 ) 125 .set_global_opts( 126 title_opts=opts.TitleOpts( 127 title="一周每天订单量", 128 pos_top="2%", 129 pos_left="center", 130 title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), 131 ), 132 xaxis_opts=opts.AxisOpts( 133 type_="category", 134 boundary_gap=True, 135 axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63",font_weight =900), 136 axisline_opts=opts.AxisLineOpts(is_show=False), 137 axistick_opts=opts.AxisTickOpts( 138 is_show=True, 139 length=25, 140 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 141 ), 142 splitline_opts=opts.SplitLineOpts( 143 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 144 ), 145 ), 146 yaxis_opts=opts.AxisOpts( 147 type_="value", 148 position="left", 149 axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), 150 axisline_opts=opts.AxisLineOpts( 151 linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") 152 ), 153 axistick_opts=opts.AxisTickOpts( 154 is_show=True, 155 length=15, 156 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 157 ), 158 splitline_opts=opts.SplitLineOpts( 159 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 160 ), 161 ), 162 legend_opts=opts.LegendOpts(is_show=False), 163 ) 164 ) 165 line1.render('一周每天订单量分析图.html') 166 167 # 每月订单数量 168 df_month = df3.groupby(df3['购药日期'].dt.month)['星期'].count() 169 day_x_data = [str(i)+'月' for i in list(df_month.index)] 170 day_y_data = df_month.values.tolist() 171 line1 = ( 172 Line(init_opts=opts.InitOpts(bg_color=JsCode(color_js))) 173 .add_xaxis(xaxis_data=day_x_data) 174 .add_yaxis( 175 series_name="", 176 y_axis=day_y_data, 177 is_smooth=True, 178 is_symbol_show=True, 179 symbol="circle", 180 symbol_size=6, 181 linestyle_opts=opts.LineStyleOpts(color="#fff"), 182 label_opts=opts.LabelOpts(is_show=True, position="top", color="black"), 183 itemstyle_opts=opts.ItemStyleOpts( 184 color="red", border_color="#fff", border_width=3 185 ), 186 tooltip_opts=opts.TooltipOpts(is_show=False), 187 areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), 188 ) 189 .set_global_opts( 190 title_opts=opts.TitleOpts( 191 title="每月订单量", 192 pos_top="2%", 193 pos_left="center", 194 title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), 195 ), 196 xaxis_opts=opts.AxisOpts( 197 type_="category", 198 boundary_gap=True, 199 axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63",font_weight =900), 200 axisline_opts=opts.AxisLineOpts(is_show=False), 201 axistick_opts=opts.AxisTickOpts( 202 is_show=True, 203 length=25, 204 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 205 ), 206 splitline_opts=opts.SplitLineOpts( 207 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 208 ), 209 ), 210 yaxis_opts=opts.AxisOpts( 211 type_="value", 212 position="left", 213 axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), 214 axisline_opts=opts.AxisLineOpts( 215 linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") 216 ), 217 axistick_opts=opts.AxisTickOpts( 218 is_show=True, 219 length=15, 220 linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), 221 ), 222 splitline_opts=opts.SplitLineOpts( 223 is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") 224 ), 225 ), 226 legend_opts=opts.LegendOpts(is_show=False), 227 ) 228 ) 229 line1.render('每月订单数量分析图.html') 230 # 五月每日订单量 231 colors = ['#C9DA36','#9ECB3C','#6DBC49','#37B44E','#3DBA78','#7D3990','#A63F98','#C31C88','#F57A34','#FA8F2F','#CF7B25','#CF7B25','#FF5733','#C70039'] 232 df_day = df3.groupby(df3['购药日期'].dt.day)['星期'].count() 233 day_x_data = [str(i) for i in list(df_day.index)] 234 day_y_data = df_day.values.tolist() 235 times = [x.strftime('%Y-%m-%d') for x in list(pd.date_range('20160501', '20160531'))] 236 data = [[times[index],day_y_data[index]] for index,item in enumerate( day_y_data)] 237 Cal = ( 238 Calendar(init_opts=opts.InitOpts(width="800px", height="500px")) 239 .add( 240 series_name="五月每日订单量分布情况", 241 yaxis_data=data, 242 calendar_opts=opts.CalendarOpts( 243 pos_top='20%', 244 pos_left='5%', 245 range_="2016-05", 246 cell_size=40, 247 # 年月日标签样式设置 248 daylabel_opts=opts.CalendarDayLabelOpts(name_map="cn", 249 margin=20, 250 label_font_size=14, 251 label_color='#EB1934', 252 label_font_weight='bold' 253 ), 254 monthlabel_opts=opts.CalendarMonthLabelOpts(name_map="cn", 255 margin=20, 256 label_font_size=14, 257 label_color='#EB1934', 258 label_font_weight='bold', 259 is_show=False 260 ), 261 yearlabel_opts=opts.CalendarYearLabelOpts(is_show=False), 262 ), 263 tooltip_opts='{c}', 264 ) 265 .set_global_opts( 266 title_opts=opts.TitleOpts( 267 pos_top="2%", 268 pos_left="center", 269 title="" 270 ), 271 visualmap_opts=opts.VisualMapOpts( 272 orient="horizontal", 273 max_=800, 274 pos_bottom='10%', 275 is_piecewise=True, 276 pieces=[{"min": 600}, 277 {"min": 300, "max": 599}, 278 {"min": 200, "max": 299}, 279 {"min": 160, "max": 199}, 280 {"min": 100, "max": 159}, 281 {"max": 99}], 282 range_color=['#ffeda0','#fed976','#fd8d3c','#fc4e2a','#e31a1c','#b10026'] 283 284 ), 285 legend_opts=opts.LegendOpts(is_show=True, 286 pos_top='5%', 287 item_width = 50, 288 item_height = 30, 289 textstyle_opts=opts.TextStyleOpts(font_size=16,color='#EB1934'), 290 legend_icon ='path://path://M465.621333 469.333333l-97.813333-114.133333a21.333333 21.333333 0 1 1 32.384-27.733333L512 457.856l111.786667-130.432a21.333333 21.333333 0 1 1 32.426666 27.776L558.357333 469.333333h81.493334c11.84 0 21.461333 9.472 21.461333 21.333334 0 11.776-9.6 21.333333-21.482667 21.333333H533.333333v85.333333h106.517334c11.861333 0 21.482667 9.472 21.482666 21.333334 0 11.776-9.6 21.333333-21.482666 21.333333H533.333333v127.850667c0 11.861333-9.472 21.482667-21.333333 21.482666-11.776 0-21.333333-9.578667-21.333333-21.482666V640h-106.517334A21.354667 21.354667 0 0 1 362.666667 618.666667c0-11.776 9.6-21.333333 21.482666-21.333334H490.666667v-85.333333h-106.517334A21.354667 21.354667 0 0 1 362.666667 490.666667c0-11.776 9.6-21.333333 21.482666-21.333334h81.472zM298.666667 127.957333C298.666667 104.405333 317.824 85.333333 341.12 85.333333h341.76C706.304 85.333333 725.333333 104.490667 725.333333 127.957333v42.752A42.645333 42.645333 0 0 1 682.88 213.333333H341.12C317.696 213.333333 298.666667 194.176 298.666667 170.709333V127.957333zM341.333333 170.666667h341.333334V128H341.333333v42.666667z m-105.173333-42.666667v42.666667H170.752L170.666667 895.893333 853.333333 896V170.773333L789.909333 170.666667V128h63.296C876.842667 128 896 147.072 896 170.773333v725.12C896 919.509333 877.013333 938.666667 853.333333 938.666667H170.666667a42.666667 42.666667 0 0 1-42.666667-42.773334V170.773333C128 147.157333 147.114667 128 170.752 128h65.408z' 291 ), 292 ) 293 ) 294 Cal.render('五月每日订单量分析图.html') 295 296 # 词云 297 g = df3.groupby('商品名称').sum() 298 drug_list = [] 299 for idx, value in enumerate(list(g.index)): 300 drug_list += [value] * list(g['销售数量'].values)[idx] 301 stylecloud.gen_stylecloud( 302 text=' '.join(drug_list), 303 font_path=r'STXINWEI.TTF', 304 palette='cartocolors.qualitative.Bold_5',# 设置配色方案 305 icon_name='fas fa-lock', # 设置蒙版方案 306 # background_color='black', 307 max_font_size=200, 308 output_name='药品销量.png', 309 ) 310 Image.open("药品销量.png") 311 312 data_copy = df.copy() 313 data_copy.drop(data_copy.columns[0], axis=1, inplace=True) 314 sindex = np.argsort(data_copy.isnull().sum()).values 315 # 进行缺失值的填补,利用随机森林进行填补缺失值 316 for i in sindex : 317 if data_copy.iloc[:,i].isnull().sum() == 0 : 318 continue 319 df = data_copy 320 fillc = df.iloc[:, i] 321 df = df.iloc[:,df.columns!=df.columns[i]] 322 323 #在下面的是使用了0来对特征矩阵中的缺失值的填补, 324 df_0 = SimpleImputer(missing_values=np.nan 325 ,strategy="constant" 326 ,fill_value=0 327 ).fit_transform(df) 328 Ytrain = fillc[fillc.notnull()] 329 Ytest = fillc[fillc.isnull()] 330 331 Xtrain = df_0[Ytrain.index,:] 332 Xtest = df_0[Ytest.index,:] 333 334 rfc = RandomForestRegressor() 335 rfc.fit(Xtrain, Ytrain) 336 Ypredict = rfc.predict(Xtest) 337 338 data_copy.loc[data_copy.iloc[:,i].isnull(),data_copy.columns[i]] = Ypredict 339 data_copy.isnull().sum()
四、总结
在进行药品销售数量的大数据分析时,我通过对数据的分析和挖掘,得出了以下有益的结论:通过对销售数据的时间序列分析,我发现药品销售数量存在季节性波动,在春季和秋季销售数量通常较高,在夏季和冬季销售数量通常较低。在完成此设计过程中,我得到了许多收获。首先,我学会了如何进行大数据分析,包括如何清洗数据、如何使用数据分析工具进行数据分析和可视化。其次,我还学会了如何根据分析结果得出有益的结论并提出建议。在未来的工作中,我建议对数据进行更深入的分析,例如通过进行回归分析来更准确地预测药品销售数量的变化趋势,并进一步优化药品销售策略。此外,我还建议对数据进行实时更新,以便更好地反映市场变化并进行及时调整。
浙公网安备 33010602011771号