数据来自kaggle,地址:https://www.kaggle.com/carrie1/ecommerce-data
数据集可以下载到本地再使用,访问Kaggle的话,还可以看看其他人是如何来分析的
好了,这个数据集,我们前面其实用过,上一次是为了练习pandas,这一次我们要从数据分析的角度来,看看我们能了解什么。
了解我们的数据
data_path = r'C:\Users\A\OneDrive\python\datasets\Online Retail.csv'
df = pd.read_csv(data_path , encoding='ISO-8859-1')
df.head()
记录数很多,有50万+,一共8个字段
InvoiceNo:订单号
StockCode:商品编号
Description:商品名称/描述
Quantity:商品数量
InvoiceDate:订单日期
UnitPrice:商品单价
CustomerID:用户ID
Country:国家
为了更好的了解数据,我们还可以使用info
函数和describe
函数看看
df.info()
df.describe()
这里的Quantity
和UnitPrice
中有负值,可能是退货的记录,我们需要注意下
df.query('Quantity<0').head()
df.query('UnitPrice<0').head()
通过现有数据,我们想探索些什么?
这是很典型的交易型数据,所以还是有很多角度可以去探索的
我们直接可以发现的维度:
- 商品维度
- 时间维度
- 用户维度
- 国家维度
指标的话,就有数量、销售额、用户数这些基本的,再延伸下,就有销往的国家数,单均GMV,人均GMV,每个国家的GMV等等等
1. 一共有多少笔订单?多少用户?
df.nunique()
对数据去重之后,我们可以知道:
** 订单数是25900,用户数是4372,国家数是38**
但是这个商品种类数有点问题,我理解的话,这个StockCode
应该和Description
去重数一样,但是不一样,这说明一个商品编码对应了多个描述?
我们确认下
df2 = df.groupby(by=['StockCode'])['Description'].nunique()
df2[df2>1]
这里还是有很多的不一致的,我们随便找一条看看
df.query('StockCode == "10080"')['Description'].unique()
这的确是对应了多个描述,但是我们上面去重后的差异也就200多,这里有600多条重复的,还是哪里不太对
df[df['Description'].isnull()]
居然这里还有好多描述为空的
然后,我又随便看了看,发现这个单价为0的记录剔除之后,还有一种情况
df.query('StockCode == "16156L"')['Description']
这种编码一样,但是描述一样,但是格式不一致的情况
好了,随后还是把Description
就当做描述好了,还是以StockCode
为主吧
这个数据质量,哈哈哈
这里我们需要确认下,这些单价为0,数量为负的记录,我们到底要不要,就这样留着,还是说替换掉?
恩,先留着吧
2. 总销量和总GMV
我们先用单价和数量算一个商品金额
df['sku_amount'] = df['Quantity']*df['UnitPrice']
df[['Quantity','sku_amount']].sum()/10000
结合上一题,我们这里就可以算出来很多均类指标:
单均销量、单均GMV
人均销量、人均GMV
件均GMV(件单价)
这里我就不算了,哈哈哈
单个维度
3. 商品维度:每种商品的销量、销售额、购买人数
从商品维度来分析的话,比如看看哪些是畅销品,哪些是滞销品(卖的不好的)
记得上面我们看过,有销量为负的商品,暂且把他们当做是退货,我们先看看正常订单好了
df_1 = df.query('Quantity>0')
df_2 = df_1.groupby('StockCode').agg({'Quantity':'sum' , 'sku_amount':'sum' , 'CustomerID':'nunique'})
df_2.sort_values('Quantity' , ascending=False).head()
这里,我们就根据商品编码,对销量和销售和做了合计,对用户数做了去重统计
然后,我顺便加了个排名看看,商品再销量、销售额、购买人数上的排列怎么样
df_2['Quantity_rank'] = df_2['Quantity'].rank(method='min' , ascending=False)
df_2['sku_amount_rank'] = df_2['sku_amount'].rank(method='min', ascending=False)
df_2['CustomerID_rank'] = df_2['CustomerID'].rank(method='min', ascending=False)
df_2.sort_values('Quantity' , ascending=False).head()
针对商品,我们再展开一下的话,比如,对商品做个分类,ABC分类,或者根据上面3个指标做一个商品价值总分
贡献度80%销售额的有哪些商品,都是一些探索的角度
还有,这里我们其实忽略了商品的价格,商品的价格和商品的笑脸、销售额、购买人数之间是否有关系呢?
这个价格的我还真想看一下哈
df_3 = df_1.groupby('UnitPrice').agg({'Quantity':'sum' , 'sku_amount':'sum' , 'CustomerID':'nunique'})
df_3.reset_index(inplace=True)
然后,我们画个散点图瞧一瞧
df_3.plot.scatter(x='UnitPrice' , y='Quantity')
这单价都很低呦
顺便来个累计值吧
df_3['Quantity_累计'] = df_3['Quantity'].cumsum()
df_3.plot.line(x='UnitPrice', y='Quantity_累计')
这个貌似看不出啥,看看累计占比吧,80%的销量集中在什么地方
df_3['Quantity_累计占比'] = df_3['Quantity_累计']/df_3['Quantity'].sum()
df_3.query('Quantity_累计占比<=0.8')
4. 时间维度:每天、月、年的销量、销售额、购买人数
要看时间的话,我们得看看这个日期的字段类型
df_1.info()
使用to_datetime转换一下
df_1['InvoiceDate'] = pd.to_datetime(df_1['InvoiceDate'])
我这里出来一个警告,不知道有没有影响
我们先天看一下
df_1.resample('D' , on='InvoiceDate')['Quantity'].sum().plot.line()
这里可以发现1月多少号是一个峰值哎,1月份西方有什么重大节日吗?
再按照月看看
df_1.resample('M' , on='InvoiceDate')['Quantity'].sum().plot.line()
看来,下半年是业绩高峰,尤其是11月份
时间维度可以拓展很多,比如看看星期,看看小时
这里遇到个问题,我想把周几和小时拿出来,但是不想要高维度的信息,我研究一下
df_1.resample('H' , on='InvoiceDate')['Quantity'].sum()
这里的天信息也在,其实我不需要,我咋只把小时拿出来呢?
df_1.groupby(df_1['InvoiceDate'].dt.hour)['Quantity'].sum().plot.line()
这里按销量看的,基本都集中在中午左右
5. 国家维度:每个国家的销量、销售额、购买人数
不行,有点儿搞不动了,思路其实都差不多,看看订单都集中在哪些国家,哪些国家的用户数最多等等,从销售额看看哪些国家贡献的最多,人均贡献额啥的
6. 用户维度:用户的订单数、销量(购买件数)、销售额、商品种类数
用户可以看的信息也很多,对用户做一个分类,比如RFM,打一个价值分,复购?复购周期等
多个维度交叉
比如看看不同国家购买的商品是否一致,不同国家的购物时间是否一致等等
好了,这一篇就到这,下次继续
网友评论