#!/usr/bin/env python # coding: utf-8 # # 前言 # # 数据源是来自[和鲸社区](https://www.kesci.com/mw/dataset/5ffac64f3441fd001538228b/file)的 3 份互不相关的电商数据集,所以分成 3 部分,每部分只对其中的一个数据集进行分析。 # # # ## part 1 # # tmall_order_report.csv 这个数据集是订单数据,可供挖掘的纬度有订单时间、省份(收货地址),指标则有销售量、销售额、退款金额、退货率、成交率、地区分布、下单时间趋势等。 # # ### 1、数据理解与处理 # In[1]: import pandas as pd data = pd.read_csv('tmall_order_report.csv') data.head() # 退款金额应该就是客户退货后,返还给客户的退款金额 # In[2]: data.info() # 数据集情况 28010 条,6个字段 # In[3]: data.columns = data.columns.str.strip() # 列名有空格,需要处理下 data.columns # In[4]: data[data.duplicated()].count() # 没有完全重复的数据 # In[5]: data.isnull().sum() # 付款时间存在空值,表示订单未付款 # In[6]: data['收货地址'] = data['收货地址'].str.replace('自治区|维吾尔|回族|壮族|省', '') # 对省份做个清洗,便于可视化 data['收货地址'].unique() # ### 2、数据分析可视化 # #### 2.1 整体情况 # In[7]: result = {} result['总订单数'] = data['订单编号'].count() result['已完成订单数'] = data['订单编号'][data['订单付款时间'].notnull()].count() result['未付款订单数'] = data['订单编号'][data['订单付款时间'].isnull()].count() result['退款订单数'] = data['订单编号'][data['退款金额'] > 0].count() result['总订单金额'] = data['总金额'][data['订单付款时间'].notnull()].sum() result['总退款金额'] = data['退款金额'][data['订单付款时间'].notnull()].sum() result['总实际收入金额'] = data['买家实际支付金额'][data['订单付款时间'].notnull()].sum() # In[8]: result # In[9]: from pyecharts import options as opts from pyecharts.charts import Map, Bar, Line from pyecharts.components import Table from pyecharts.options import ComponentTitleOpts from pyecharts.faker import Faker table = Table() headers = ['总订单数', '总订单金额', '已完成订单数', '总实际收入金额', '退款订单数', '总退款金额', '成交率', '退货率'] rows = [ [ result['总订单数'], f"{result['总订单金额']/10000:.2f} 万", result['已完成订单数'], f"{result['总实际收入金额']/10000:.2f} 万", result['退款订单数'], f"{result['总退款金额']/10000:.2f} 万", f"{result['已完成订单数']/result['总订单数']:.2%}", f"{result['退款订单数']/result['已完成订单数']:.2%}", ] ] table.add(headers, rows) table.set_global_opts( title_opts=ComponentTitleOpts(title='整体情况') ) table.render_notebook() # #### 2.2 地区分析 # In[10]: result2 = data[data['订单付款时间'].notnull()].groupby('收货地址').agg({'订单编号':'count'}) result21 = result2.to_dict()['订单编号'] c = ( Map() .add("订单量", [*result21.items()], "china", is_map_symbol_show=False) .set_series_opts(label_opts=opts.LabelOpts(is_show=True)) .set_global_opts( title_opts=opts.TitleOpts(title='地区分布'), visualmap_opts=opts.VisualMapOpts(max_=1000), ) ) c.render_notebook() # #### 2.3 时间分析 # In[11]: data['订单创建时间'] = pd.to_datetime(data['订单创建时间']) data['订单付款时间'] = pd.to_datetime(data['订单付款时间']) # In[12]: result31 = data.groupby(data['订单创建时间'].apply(lambda x: x.strftime("%Y-%m-%d"))).agg({'订单编号':'count'}).to_dict()['订单编号'] c = ( Line() .add_xaxis(list(result31.keys())) .add_yaxis("订单量", list(result31.values())) .set_series_opts( label_opts=opts.LabelOpts(is_show=False), markpoint_opts=opts.MarkPointOpts( data=[ opts.MarkPointItem(type_="max", name="最大值"), ] ), ) .set_global_opts(title_opts=opts.TitleOpts(title="每日订单量走势")) ) c.render_notebook() # 从上图来看,2月份上半月由于受新冠疫情影响,订单量比较少,随着复工开展,下半月的订单量增长明显。 # In[13]: result32 = data.groupby(data['订单创建时间'].apply(lambda x: x.strftime("%H"))).agg({'订单编号':'count'}).to_dict()['订单编号'] x = [*result32.keys()] y = [*result32.values()] c = ( Bar() .add_xaxis(x) .add_yaxis("订单量", y) .set_global_opts(title_opts=opts.TitleOpts(title="每小时订单量走势")) .set_series_opts( label_opts=opts.LabelOpts(is_show=False), markpoint_opts=opts.MarkPointOpts( data=[ opts.MarkPointItem(type_="max", name="峰值"), opts.MarkPointItem(name="第二峰值", coord=[x[15], y[15]], value=y[15]), opts.MarkPointItem(name="第三峰值", coord=[x[10], y[10]], value=y[10]), ] ), ) ) c.render_notebook() # 从每小时订单量走势来看,一天中有3个高峰期(10点、15点、21点),其中21点-22点之间是一天中订单量最多的时候,这个结果和之前 [1 亿条淘宝用户行为数据分析](https://github.com/TurboWay/bigdata_analyse/blob/main/UserBehaviorFromTaobao_Batch/用户行为数据分析.md) 的结果是一致的。对于卖家的指导意义就是,为了提高订单量,高峰期时应该尽量保证客服的回复速度,尤其是晚上21点-22点之间,所以很多做电商的基本都有夜班。 # In[14]: s = data['订单付款时间'] - data['订单创建时间'] s[s.notnull()].apply(lambda x: x.seconds / 60 ).mean() # 从下单到付款的平均耗时为 7.7 分钟 # ## part2 # # 双十一淘宝美妆数据.csv 这个数据集是美妆店铺的双十一销售数据,可以挖掘的纬度有日期、店铺,指标则有销售量、销售额、评论数等。 # ### 1、数据理解与处理 # In[15]: import pandas as pd data2 = pd.read_csv('双十一淘宝美妆数据.csv') data2.head() # In[16]: data2.info() # 数据集情况 28010 条,6个字段 # In[17]: data2[data2.duplicated()].count() # 有86条完全重复数据 # In[18]: data2.drop_duplicates(inplace=True) # 删除重复数据 data2.reset_index(drop=True, inplace=True) # 重建索引 data2.isnull().sum() # 查看空值 ,销售数量和评论数有空值 # In[19]: data2.fillna(0, inplace=True) # 空值填充 data2['update_time'] = pd.to_datetime(data2['update_time']).apply(lambda x: x.strftime("%Y-%m-%d")) # 日期格式化,便于统计 # In[20]: data2[data2['sale_count']>0].sort_values(by=['sale_count']).head() # 从数据来看,sale_count 是销售量 # In[21]: data2['sale_amount'] = data2['price'] * data2['sale_count'] # 增加一列销售额 data2[data2['sale_count']>0].sort_values(by=['sale_count']) # ### 2、数据分析与可视化 # #### 2.1 每日整体销售量走势 # In[22]: result = data2.groupby('update_time').agg({'sale_count':'sum'}).to_dict()['sale_count'] c = ( Line() .add_xaxis(list(result.keys())) .add_yaxis("销售量", list(result.values())) .set_series_opts( areastyle_opts=opts.AreaStyleOpts(opacity=0.5), label_opts=opts.LabelOpts(is_show=False), markpoint_opts=opts.MarkPointOpts( data=[ opts.MarkPointItem(type_="max", name="最大值"), opts.MarkPointItem(type_="min", name="最小值"), opts.MarkPointItem(type_="average", name="平均值"), ] ), ) .set_global_opts(title_opts=opts.TitleOpts(title="每日整体销售量走势")) ) c.render_notebook() # #### 2.2 谁家的化妆品卖的最好 # In[23]: dts = list(data2['update_time'].unique()) dts.reverse() dts # In[24]: from pyecharts import options as opts from pyecharts.charts import Map, Timeline, Bar, Line, Pie from pyecharts.components import Table from pyecharts.options import ComponentTitleOpts tl = Timeline() tl.add_schema( # is_auto_play=True, is_loop_play=False, play_interval=500, ) for dt in dts: item = data2[data2['update_time'] <= dt].groupby('店名').agg({'sale_count': 'sum', 'sale_amount': 'sum'}).sort_values(by='sale_count', ascending=False)[:10].sort_values(by='sale_count').to_dict() bar = ( Bar() .add_xaxis([*item['sale_count'].keys()]) .add_yaxis("销售量", [round(val/10000,2) for val in item['sale_count'].values()], label_opts=opts.LabelOpts(position="right", formatter='{@[1]/} 万')) .add_yaxis("销售额", [round(val/10000/10000,2) for val in item['sale_amount'].values()], label_opts=opts.LabelOpts(position="right", formatter='{@[1]/} 亿元')) .reversal_axis() .set_global_opts( title_opts=opts.TitleOpts("累计销售量排行 TOP10") ) ) tl.add(bar, dt) tl.render_notebook() # In[25]: item = data2.groupby('店名').agg({'sale_count': 'sum'}).sort_values(by='sale_count', ascending=False)[:10].to_dict()['sale_count'] item = {k: round(v/10000, 2) for k, v in item.items()} c = ( Pie() .add("销量", [*item.items()]) .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c} 万({d}%)")) ) c.render_notebook() # #### 2.4 谁家的化妆品最贵 # In[26]: item = data2.groupby('店名').agg({'price': 'mean'}).sort_values(by='price', ascending=False)[:20].sort_values(by='price').to_dict() c = ( Bar() .add_xaxis([*item['price'].keys()]) .add_yaxis("销售量", [round(v, 2) for v in item['price'].values()], label_opts=opts.LabelOpts(position="right")) .reversal_axis() .set_global_opts( title_opts=opts.TitleOpts("平均价格排行 TOP20") ) ) c.render_notebook() # ## part3 # # 日化.xlsx 这个数据集是美妆类商品的订单数据,从数量来看,应该是批发类的订单。包含两个 sheet 页(订单表和商品表),可以挖掘的纬度有日期、地区、商品,指标则有销售量、销售额、增长率等。 # ### 1、数据理解与处理 # In[27]: import pandas as pd fact_order = pd.read_excel('日化.xlsx', sheet_name='销售订单表') dim_product = pd.read_excel('日化.xlsx', sheet_name='商品信息表') # #### 1.1 商品表数据清洗 # In[28]: dim_product.head() # In[29]: dim_product.describe() # In[30]: dim_product[dim_product.duplicated()].count() # 没有完全重复的数据 # In[31]: dim_product[dim_product['商品编号'].duplicated()].count() # ID 唯一没有重复 # In[32]: dim_product.isnull().sum() # 没有空值 # #### 1.2 订单表数据清洗 # In[33]: fact_order.head() # In[34]: fact_order.info() # In[35]: fact_order[fact_order.duplicated()].count() # 没有完全重复的数据 # In[36]: fact_order.drop_duplicates(inplace=True) # 删除重复数据 fact_order.reset_index(drop=True, inplace=True) # 重建索引 fact_order.isnull().sum() # 查看空值,有几条数据缺失 # In[37]: fact_order.fillna(method='bfill', inplace=True) # 空值填充 fact_order.fillna(method='ffill', inplace=True) # 空值填充 fact_order.isnull().sum() # 查看空值,有几条数据缺失 # In[38]: fact_order['订单日期'] = fact_order['订单日期'].apply(lambda x: pd.to_datetime(x, format='%Y#%m#%d') if isinstance(x, str) else x) fact_order[fact_order['订单日期'] > '2021-01-01'] # 有一条脏数据 # In[39]: fact_order = fact_order[fact_order['订单日期'] < '2021-01-01'] # 过滤掉脏数据 fact_order['订单日期'].max(), fact_order['订单日期'].min() # 数据区间在 2019-01-01 到 2019-09-30 之间 # In[40]: fact_order['订购数量'] = fact_order['订购数量'].apply(lambda x: x.strip('个') if isinstance(x, str) else x).astype('int') fact_order['订购单价'] = fact_order['订购单价'].apply(lambda x: x.strip('元') if isinstance(x, str) else x).astype('float') fact_order['金额'] = fact_order['金额'].astype('float') # In[41]: fact_order.info() # In[42]: fact_order['所在省份'] = fact_order['所在省份'].str.replace('自治区|维吾尔|回族|壮族|省|市', '') # 对省份做个清洗,便于可视化 fact_order['所在省份'].unique() # In[43]: fact_order['客户编码'] = fact_order['客户编码'].str.replace('编号', '') # ### 2、数据分析与可视化 # #### 2.1 每月订购情况 # In[44]: from pyecharts import options as opts from pyecharts.charts import Map, Bar, Line from pyecharts.components import Table from pyecharts.options import ComponentTitleOpts from pyecharts.faker import Faker fact_order['订单月份'] = fact_order['订单日期'].apply(lambda x: x.month) item = fact_order.groupby('订单月份').agg({'订购数量': 'sum', '金额': 'sum'}).to_dict() x = [f'{key} 月' for key in item['订购数量'].keys()] y1 = [round(val/10000, 2) for val in item['订购数量'].values()] y2 = [round(val/10000/10000, 2) for val in item['金额'].values()] c = ( Bar() .add_xaxis(x) .add_yaxis("订购数量(万件)", y1, is_selected=False) .add_yaxis("金额(亿元)", y2) .set_global_opts(title_opts=opts.TitleOpts(title="每月订购情况")) .set_series_opts( label_opts=opts.LabelOpts(is_show=True), ) ) c.render_notebook() # #### 2.2 哪里的人最爱美 # In[45]: item = fact_order.groupby('所在地市').agg({'订购数量': 'sum'}).sort_values(by='订购数量', ascending=False)[:20].sort_values(by='订购数量').to_dict()['订购数量'] c = ( Bar() .add_xaxis([*item.keys()]) .add_yaxis("订购量", [round(v/10000, 2) for v in item.values()], label_opts=opts.LabelOpts(position="right", formatter='{@[1]/} 万')) .reversal_axis() .set_global_opts( title_opts=opts.TitleOpts("订购数量排行 TOP20") ) ) c.render_notebook() # #### 2.3 什么类型的美妆需求量最大 # In[46]: order = pd.merge(fact_order, dim_product, on='商品编号',how='inner') # 表关联 order # In[47]: order.groupby(['商品大类','商品小类']).agg({'订购数量': 'sum'}).sort_values(by=['商品大类', '订购数量'], ascending=[True, False]) # #### 2.4 哪些省份的美妆需求量最大 # In[48]: item = fact_order.groupby('所在省份').agg({'订购数量': 'sum'}).to_dict()['订购数量'] c = ( Map() .add("订购数量", [*item.items()], "china", is_map_symbol_show=False) .set_series_opts(label_opts=opts.LabelOpts(is_show=True)) .set_global_opts( title_opts=opts.TitleOpts(title='省份分布'), visualmap_opts=opts.VisualMapOpts(max_=1000000), ) ) c.render_notebook() # #### 2.5 通过 RFM 模型挖掘客户价值 # # RFM 模型是衡量客户价值和客户创利能力的重要工具和手段,其中由3个要素构成了数据分析最好的指标,分别是: # * R-Recency(最近一次购买时间) # * F-Frequency(消费频率) # * M-Money(消费金额) # # 设定一个计算权重,比如 R-Recency 20% F-Frequency 30% M-Money 50% ,最后通过这个权重进行打分,量化客户价值,后续还可以基于分数进一步打标签,用来指导二次营销的策略。 # In[49]: data_rfm = fact_order.groupby('客户编码').agg({'订单日期': 'max', '订单编码': 'count', '金额': 'sum'}) data_rfm.columns = ['最近一次购买时间', '消费频率', '消费金额'] # In[50]: data_rfm['R'] = data_rfm['最近一次购买时间'].rank(pct=True) # 转化为排名 百分比,便于后续切片 data_rfm['F'] = data_rfm['消费频率'].rank(pct=True) data_rfm['M'] = data_rfm['消费金额'].rank(pct=True) data_rfm.sort_values(by='R', ascending=False) # In[51]: data_rfm['score'] = data_rfm['R'] * 20 + data_rfm['F'] * 30 + data_rfm['M'] * 50 data_rfm['score'] = data_rfm['score'].round(1) data_rfm.sort_values(by='score', ascending=False) # 根据这个分数结果,我们可以对客户打上一些标签,比如大于 80 分的,标志为优质客户,在资源有限的情况下,可以优先服务好优质客户。