Python数据分析第8天 - 运营复盘项目实战¶
In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'].insert(0, 'SimHei')
plt.rcParams['axes.unicode_minus'] = False
In [2]:
%config InlineBackend.figure_format = 'svg'
In [9]:
# 加载订单明细表
orders = pd.read_csv(
'../wenjian/orders.csv',
true_values=['是'],
false_values=['否'],
# converters={'orderTime': pd.to_datetime}
)
orders.head(3)
Out[9]:
orderID | userID | goodsID | num | orderAmount | payment | orderTime | chargeback | |
---|---|---|---|---|---|---|---|---|
0 | sys-2021-129388536 | user-233240 | PR000366 | 1 | 838 | 838 | 2021-01-05 00:01:11 | False |
1 | sys-2021-129388537 | user-184666 | PR000716 | 4 | 3344 | 3344 | 2021-01-05 00:02:12 | True |
2 | sys-2021-129388538 | user-283751 | PR000323 | 1 | 1648 | 1648 | 2021-01-05 00:02:46 | True |
In [10]:
orders.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 33501 entries, 0 to 33500 Data columns (total 8 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 orderID 33501 non-null object 1 userID 33501 non-null object 2 goodsID 33501 non-null object 3 num 33501 non-null int64 4 orderAmount 33501 non-null int64 5 payment 33501 non-null int64 6 orderTime 33501 non-null object 7 chargeback 33501 non-null bool dtypes: bool(1), int64(3), object(4) memory usage: 1.8+ MB
In [11]:
orders['orderTime'] = pd.to_datetime(orders.orderTime)
orders.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 33501 entries, 0 to 33500 Data columns (total 8 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 orderID 33501 non-null object 1 userID 33501 non-null object 2 goodsID 33501 non-null object 3 num 33501 non-null int64 4 orderAmount 33501 non-null int64 5 payment 33501 non-null int64 6 orderTime 33501 non-null datetime64[ns] 7 chargeback 33501 non-null bool dtypes: bool(1), datetime64[ns](1), int64(3), object(3) memory usage: 1.8+ MB
In [ ]:
orders.orderTime.agg(['min', 'max'])
In [12]:
def make_tag(day):
if day < 8: return '预热期'
elif day < 11: return '活动期'
return '返场期'
# 运营活动分为三个阶段,分别是:预热期(5-7日)、活动期(8-10日)和返场期(11-13日)
orders['stage'] = orders.orderTime.dt.day.map(make_tag).astype('category').cat.reorder_categories(['预热期', '活动期', '返场期'])
orders.head(3)
Out[12]:
orderID | userID | goodsID | num | orderAmount | payment | orderTime | chargeback | stage | |
---|---|---|---|---|---|---|---|---|---|
0 | sys-2021-129388536 | user-233240 | PR000366 | 1 | 838 | 838 | 2021-01-05 00:01:11 | False | 预热期 |
1 | sys-2021-129388537 | user-184666 | PR000716 | 4 | 3344 | 3344 | 2021-01-05 00:02:12 | True | 预热期 |
2 | sys-2021-129388538 | user-283751 | PR000323 | 1 | 1648 | 1648 | 2021-01-05 00:02:46 | True | 预热期 |
In [13]:
# 订单是否参与了活动(有没有享受到活动优惠)
orders['inActivity'] = orders.payment < orders.orderAmount
orders.head(3)
Out[13]:
orderID | userID | goodsID | num | orderAmount | payment | orderTime | chargeback | stage | inActivity | |
---|---|---|---|---|---|---|---|---|---|---|
0 | sys-2021-129388536 | user-233240 | PR000366 | 1 | 838 | 838 | 2021-01-05 00:01:11 | False | 预热期 | False |
1 | sys-2021-129388537 | user-184666 | PR000716 | 4 | 3344 | 3344 | 2021-01-05 00:02:12 | True | 预热期 | False |
2 | sys-2021-129388538 | user-283751 | PR000323 | 1 | 1648 | 1648 | 2021-01-05 00:02:46 | True | 预热期 | False |
In [14]:
# 加载商品表
products = pd.read_csv('../wenjian/products.csv')
products.head(3)
Out[14]:
goodsID | price | category | cost | key | |
---|---|---|---|---|---|
0 | PR000001 | 785 | 商品 | 299 | False |
1 | PR000002 | 1310 | 家居 | 458 | False |
2 | PR000003 | 2325 | 家居 | 837 | True |
In [15]:
# 处理异常值
products['category'] = products.category.replace('商品', '食品')
products.category.value_counts()
Out[15]:
category 美妆 490 食品 319 家居 191 Name: count, dtype: int64
In [ ]:
products.info()
In [16]:
# 加载用户表
users = pd.read_csv(
'../wenjian/users.csv',
usecols=['userID', 'age', 'sex', 'recentAcc', 'channelID', 'area', 'isOld'],
converters={'recentAcc': pd.to_datetime}
)
users.head(3)
Out[16]:
userID | age | sex | recentAcc | channelID | area | isOld | |
---|---|---|---|---|---|---|---|
0 | user-550507 | 39 | 女 | 2021-01-12 | 渠道-52 | 山东 | False |
1 | user-499937 | 30 | 男 | 2021-01-08 | 渠道-89 | 河南 | True |
2 | user-515582 | 39 | 女 | 2021-01-09 | 渠道-89 | 四川 | True |
In [17]:
users.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 69395 entries, 0 to 69394 Data columns (total 7 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 userID 69395 non-null object 1 age 69395 non-null int64 2 sex 69395 non-null object 3 recentAcc 69395 non-null datetime64[ns] 4 channelID 69395 non-null object 5 area 69395 non-null object 6 isOld 69395 non-null bool dtypes: bool(1), datetime64[ns](1), int64(1), object(4) memory usage: 3.2+ MB
In [18]:
# 清除掉非活动期间访问的用户
index = users[users.recentAcc.dt.day < 5].index
users.drop(index=index, inplace=True)
In [19]:
orders = pd.merge(orders, products, how='inner', on='goodsID')
orders
Out[19]:
orderID | userID | goodsID | num | orderAmount | payment | orderTime | chargeback | stage | inActivity | price | category | cost | key | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | sys-2021-129388536 | user-233240 | PR000366 | 1 | 838 | 838 | 2021-01-05 00:01:11 | False | 预热期 | False | 838 | 食品 | 208 | False |
1 | sys-2021-129388537 | user-184666 | PR000716 | 4 | 3344 | 3344 | 2021-01-05 00:02:12 | True | 预热期 | False | 836 | 家居 | 217 | False |
2 | sys-2021-129388538 | user-283751 | PR000323 | 1 | 1648 | 1648 | 2021-01-05 00:02:46 | True | 预热期 | False | 1648 | 食品 | 531 | False |
3 | sys-2021-129388539 | user-279635 | PR000652 | 1 | 651 | 651 | 2021-01-05 00:03:37 | False | 预热期 | False | 651 | 美妆 | 187 | True |
4 | sys-2021-129388540 | user-124652 | PR000774 | 2 | 2830 | 2830 | 2021-01-05 00:04:44 | False | 预热期 | False | 1415 | 美妆 | 462 | False |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
33496 | sys-2021-129422913 | user-235535 | PR000164 | 4 | 2372 | 2372 | 2021-01-13 23:57:24 | True | 返场期 | False | 593 | 家居 | 180 | False |
33497 | sys-2021-129422914 | user-139042 | PR000096 | 1 | 661 | 661 | 2021-01-13 23:57:51 | False | 返场期 | False | 661 | 美妆 | 185 | False |
33498 | sys-2021-129422915 | user-133379 | PR000984 | 1 | 696 | 696 | 2021-01-13 23:58:19 | False | 返场期 | False | 696 | 家居 | 272 | True |
33499 | sys-2021-129422916 | user-156013 | PR000753 | 4 | 5936 | 5936 | 2021-01-13 23:59:24 | False | 返场期 | False | 1484 | 美妆 | 451 | False |
33500 | sys-2021-129422917 | user-271551 | PR000738 | 1 | 1014 | 1014 | 2021-01-13 23:59:45 | False | 返场期 | False | 1014 | 美妆 | 319 | False |
33501 rows × 14 columns
In [20]:
orders['profit'] = orders.payment - orders.cost * orders.num
orders
Out[20]:
orderID | userID | goodsID | num | orderAmount | payment | orderTime | chargeback | stage | inActivity | price | category | cost | key | profit | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | sys-2021-129388536 | user-233240 | PR000366 | 1 | 838 | 838 | 2021-01-05 00:01:11 | False | 预热期 | False | 838 | 食品 | 208 | False | 630 |
1 | sys-2021-129388537 | user-184666 | PR000716 | 4 | 3344 | 3344 | 2021-01-05 00:02:12 | True | 预热期 | False | 836 | 家居 | 217 | False | 2476 |
2 | sys-2021-129388538 | user-283751 | PR000323 | 1 | 1648 | 1648 | 2021-01-05 00:02:46 | True | 预热期 | False | 1648 | 食品 | 531 | False | 1117 |
3 | sys-2021-129388539 | user-279635 | PR000652 | 1 | 651 | 651 | 2021-01-05 00:03:37 | False | 预热期 | False | 651 | 美妆 | 187 | True | 464 |
4 | sys-2021-129388540 | user-124652 | PR000774 | 2 | 2830 | 2830 | 2021-01-05 00:04:44 | False | 预热期 | False | 1415 | 美妆 | 462 | False | 1906 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
33496 | sys-2021-129422913 | user-235535 | PR000164 | 4 | 2372 | 2372 | 2021-01-13 23:57:24 | True | 返场期 | False | 593 | 家居 | 180 | False | 1652 |
33497 | sys-2021-129422914 | user-139042 | PR000096 | 1 | 661 | 661 | 2021-01-13 23:57:51 | False | 返场期 | False | 661 | 美妆 | 185 | False | 476 |
33498 | sys-2021-129422915 | user-133379 | PR000984 | 1 | 696 | 696 | 2021-01-13 23:58:19 | False | 返场期 | False | 696 | 家居 | 272 | True | 424 |
33499 | sys-2021-129422916 | user-156013 | PR000753 | 4 | 5936 | 5936 | 2021-01-13 23:59:24 | False | 返场期 | False | 1484 | 美妆 | 451 | False | 4132 |
33500 | sys-2021-129422917 | user-271551 | PR000738 | 1 | 1014 | 1014 | 2021-01-13 23:59:45 | False | 返场期 | False | 1014 | 美妆 | 319 | False | 695 |
33501 rows × 15 columns
In [21]:
# 按阶段统计各项指标
temp1 = pd.pivot_table(
orders,
index='stage',
values=['orderAmount', 'orderID', 'num', 'userID'],
aggfunc={
'orderAmount': 'sum',
'orderID': 'nunique',
'num': 'sum',
'userID': 'nunique'
},
observed=True
).rename(
columns={'orderAmount': 'GMV', 'num': '商品数量', 'orderID': '订单数量', 'userID': '用户数量'},
)
temp1
Out[21]:
商品数量 | GMV | 订单数量 | 用户数量 | |
---|---|---|---|---|
stage | ||||
预热期 | 17155 | 18004237 | 6273 | 6059 |
活动期 | 40789 | 42794651 | 15441 | 14769 |
返场期 | 30331 | 31777545 | 11787 | 11312 |
In [22]:
temp2 = pd.pivot_table(
orders.query('not chargeback'),
index='stage',
values=['payment', 'profit', 'orderID', 'num'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'nunique'
},
observed=True
).rename(
columns={'payment': '净销售额', 'num': '成交商品数量', 'orderID': '成交订单数量', 'profit': '毛利润'},
)
temp2
Out[22]:
成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | |
---|---|---|---|---|
stage | ||||
预热期 | 14159 | 5164 | 14841296 | 10387440 |
活动期 | 26050 | 9841 | 25636091 | 17442507 |
返场期 | 24207 | 9392 | 24215453 | 16580731 |
In [23]:
pd.merge(temp1, temp2, left_index=True, right_index=True)
Out[23]:
商品数量 | GMV | 订单数量 | 用户数量 | 成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | |
---|---|---|---|---|---|---|---|---|
stage | ||||||||
预热期 | 17155 | 18004237 | 6273 | 6059 | 14159 | 5164 | 14841296 | 10387440 |
活动期 | 40789 | 42794651 | 15441 | 14769 | 26050 | 9841 | 25636091 | 17442507 |
返场期 | 30331 | 31777545 | 11787 | 11312 | 24207 | 9392 | 24215453 | 16580731 |
In [24]:
result1 = pd.concat((temp1, temp2), axis=1)
result1
Out[24]:
商品数量 | GMV | 订单数量 | 用户数量 | 成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | |
---|---|---|---|---|---|---|---|---|
stage | ||||||||
预热期 | 17155 | 18004237 | 6273 | 6059 | 14159 | 5164 | 14841296 | 10387440 |
活动期 | 40789 | 42794651 | 15441 | 14769 | 26050 | 9841 | 25636091 | 17442507 |
返场期 | 30331 | 31777545 | 11787 | 11312 | 24207 | 9392 | 24215453 | 16580731 |
In [25]:
result1['毛利率'] = result1.毛利润 / result1.净销售额
result1['AOV'] = (result1.净销售额 / result1.成交订单数量).round(2)
result1['连带率'] = (result1.成交商品数量 / result1.成交订单数量).round(2)
result1['客单价'] = (result1.净销售额 / result1.用户数量).round(2)
result1['拒退率'] = 1 - result1.成交订单数量 / result1.订单数量
result1
Out[25]:
商品数量 | GMV | 订单数量 | 用户数量 | 成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | 毛利率 | AOV | 连带率 | 客单价 | 拒退率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
stage | |||||||||||||
预热期 | 17155 | 18004237 | 6273 | 6059 | 14159 | 5164 | 14841296 | 10387440 | 0.699901 | 2873.99 | 2.74 | 2449.46 | 0.176789 |
活动期 | 40789 | 42794651 | 15441 | 14769 | 26050 | 9841 | 25636091 | 17442507 | 0.680389 | 2605.03 | 2.65 | 1735.80 | 0.362671 |
返场期 | 30331 | 31777545 | 11787 | 11312 | 24207 | 9392 | 24215453 | 16580731 | 0.684717 | 2578.31 | 2.58 | 2140.69 | 0.203190 |
In [26]:
# 计算定基变化百分比
result2 = pd.concat((result1.pct_change(1)[:2], result1.pct_change(2)[2:3]))
result2.style.format(formatter='{:.2%}', na_rep='------')
Out[26]:
商品数量 | GMV | 订单数量 | 用户数量 | 成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | 毛利率 | AOV | 连带率 | 客单价 | 拒退率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
stage | |||||||||||||
预热期 | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ |
活动期 | 137.77% | 137.69% | 146.15% | 143.75% | 83.98% | 90.57% | 72.73% | 67.92% | -2.79% | -9.36% | -3.28% | -29.14% | 105.14% |
返场期 | 76.81% | 76.50% | 87.90% | 86.70% | 70.97% | 81.87% | 63.16% | 59.62% | -2.17% | -10.29% | -5.84% | -12.61% | 14.93% |
In [27]:
# 绘制柱状图对比数据
result1.plot(
figsize=(8, 4),
kind='bar',
y=['GMV', '净销售额'],
width=0.4,
xlabel='',
color=['#1679AB', '#81A263']
)
plt.plot(np.arange(3) - 0.1, result1.GMV, marker='^', linewidth=0.8, color='#BC5A94', linestyle='--')
plt.plot(np.arange(3) + 0.1, result1.净销售额, marker='^', linewidth=0.8, color='#BC5A94', linestyle='--')
for i in range(1, 3):
plt.text(i - 0.1, result1.GMV.iloc[i], f'{result2.GMV.iloc[i]:.2%}')
plt.text(i + 0.1, result1.净销售额.iloc[i], f'{result2.净销售额.iloc[i]:.2%}')
plt.title('活动期间GMV和净销售额对比', fontdict={'size': 20, 'color': '#1A2130'})
plt.xticks(rotation=0)
plt.ylim(0, 50000000)
plt.ticklabel_format(axis='y', style='plain')
plt.show()
In [28]:
result3 = pd.pivot_table(
orders.query('not chargeback'),
index=['category'],
values=['payment', 'profit', 'orderID', 'num', 'userID'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'nunique',
'userID': 'nunique'
},
observed=True
).rename(
columns={'num': '成交商品数量', 'orderID': '成交订单数量', 'payment': '净销售额', 'profit': '毛利润', 'userID': '成交用户数量'}
)
result3['毛利率'] = result3.毛利润 / result3.净销售额
result3['AOV'] = (result3.净销售额 / result3.成交订单数量).round(2)
result3['连带率'] = (result3.成交商品数量 / result3.成交订单数量).round(2)
result3['客单价'] = (result3.净销售额 / result3.成交用户数量).round(2)
result3
Out[28]:
成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | 成交用户数量 | 毛利率 | AOV | 连带率 | 客单价 | |
---|---|---|---|---|---|---|---|---|---|
category | |||||||||
家居 | 12188 | 4608 | 11768215 | 8117181 | 4557 | 0.689755 | 2553.87 | 2.64 | 2582.45 |
美妆 | 31666 | 12041 | 32087809 | 21934662 | 11738 | 0.683582 | 2664.88 | 2.63 | 2733.67 |
食品 | 20562 | 7748 | 20836816 | 14358835 | 7621 | 0.689109 | 2689.32 | 2.65 | 2734.13 |
In [29]:
result4 = pd.pivot_table(
orders.query('not chargeback'),
index=['stage', 'category'],
values=['payment', 'profit', 'orderID', 'num', 'userID'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'nunique',
'userID': 'nunique'
},
observed=True
).rename(
columns={'num': '成交商品数量', 'orderID': '成交订单数量', 'payment': '净销售额', 'profit': '毛利润', 'userID': '成交用户数量'}
)
result4['毛利率'] = result4.毛利润 / result4.净销售额
result4['AOV'] = (result4.净销售额 / result4.成交订单数量).round(2)
result4['连带率'] = (result4.成交商品数量 / result4.成交订单数量).round(2)
result4['客单价'] = (result4.净销售额 / result4.成交用户数量).round(2)
result4
Out[29]:
成交商品数量 | 成交订单数量 | 净销售额 | 毛利润 | 成交用户数量 | 毛利率 | AOV | 连带率 | 客单价 | ||
---|---|---|---|---|---|---|---|---|---|---|
stage | category | |||||||||
预热期 | 家居 | 2784 | 993 | 2823369 | 1984482 | 989 | 0.702877 | 2843.27 | 2.80 | 2854.77 |
美妆 | 6914 | 2535 | 7293513 | 5087927 | 2500 | 0.697596 | 2877.13 | 2.73 | 2917.41 | |
食品 | 4461 | 1636 | 4724414 | 3315031 | 1619 | 0.701681 | 2887.78 | 2.73 | 2918.11 | |
活动期 | 家居 | 4806 | 1857 | 4477521 | 3056715 | 1851 | 0.682680 | 2411.16 | 2.59 | 2418.97 |
美妆 | 12866 | 4836 | 12852941 | 8716111 | 4769 | 0.678141 | 2657.76 | 2.66 | 2695.10 | |
食品 | 8378 | 3148 | 8305629 | 5669681 | 3122 | 0.682631 | 2638.38 | 2.66 | 2660.36 | |
返场期 | 家居 | 4598 | 1758 | 4467325 | 3075984 | 1742 | 0.688552 | 2541.14 | 2.62 | 2564.48 |
美妆 | 11886 | 4670 | 11941355 | 8130624 | 4597 | 0.680880 | 2557.04 | 2.55 | 2597.64 | |
食品 | 7723 | 2964 | 7806773 | 5374123 | 2940 | 0.688392 | 2633.86 | 2.61 | 2655.36 |
In [30]:
temp3 = pd.pivot_table(
orders.query('not chargeback'),
index='userID',
values=['payment', 'profit', 'num', 'orderID'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'nunique'
}
)
temp3['buy'] = 1
temp3
Out[30]:
num | orderID | payment | profit | buy | |
---|---|---|---|---|---|
userID | |||||
user-100000 | 1 | 1 | 1195 | 905 | 1 |
user-100032 | 4 | 2 | 5074 | 3156 | 1 |
user-100033 | 3 | 1 | 2154 | 1602 | 1 |
user-100034 | 1 | 1 | 1048 | 664 | 1 |
user-100038 | 4 | 1 | 2616 | 1964 | 1 |
... | ... | ... | ... | ... | ... |
user-548272 | 1 | 1 | 978 | 688 | 1 |
user-548274 | 7 | 1 | 9919 | 6370 | 1 |
user-548279 | 2 | 1 | 1848 | 1262 | 1 |
user-548280 | 4 | 1 | 4108 | 3092 | 1 |
user-548282 | 3 | 1 | 2685 | 1806 | 1 |
23119 rows × 5 columns
In [31]:
temp4 = pd.merge(users, temp3, how='left', on='userID').fillna(0)
temp4
Out[31]:
userID | age | sex | recentAcc | channelID | area | isOld | num | orderID | payment | profit | buy | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | user-550507 | 39 | 女 | 2021-01-12 | 渠道-52 | 山东 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | user-499937 | 30 | 男 | 2021-01-08 | 渠道-89 | 河南 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2 | user-515582 | 39 | 女 | 2021-01-09 | 渠道-89 | 四川 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 | user-519645 | 34 | 男 | 2021-01-10 | 渠道-00 | 广东 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
4 | user-529356 | 24 | 女 | 2021-01-08 | 渠道-19 | 四川 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
66153 | user-531290 | 24 | 女 | 2021-01-08 | 渠道-52 | 北京 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
66154 | user-537409 | 33 | 女 | 2021-01-10 | 渠道-39 | 上海 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
66155 | user-511000 | 40 | 女 | 2021-01-09 | 渠道-98 | 湖北 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
66156 | user-518649 | 36 | 女 | 2021-01-10 | 渠道-00 | 上海 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
66157 | user-545810 | 18 | 女 | 2021-01-10 | 渠道-39 | 上海 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
66158 rows × 12 columns
In [32]:
# 统计每个渠道的净销售额、毛利润、销售数量、订单数量、拉新用户数量、购买用户数量
result5 = pd.pivot_table(
temp4,
index='channelID',
values=['payment', 'profit', 'num', 'orderID', 'userID', 'buy'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'sum',
'userID': 'count',
'buy': 'sum',
}
).rename(
columns={'payment': '净销售额', 'profit': '毛利润', 'num': '销售数量', 'orderID': '订单数量', 'userID': '拉新用户数', 'buy': '购买用户数'}
).astype('i8')
result5.sort_values(by='拉新用户数', ascending=False)
Out[32]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | |
---|---|---|---|---|---|---|
channelID | ||||||
渠道-89 | 1005 | 2843 | 1059 | 2806740 | 1906726 | 11331 |
渠道-52 | 767 | 2120 | 814 | 2089450 | 1426467 | 8434 |
渠道-53 | 731 | 1972 | 764 | 1990945 | 1361766 | 7909 |
渠道-76 | 594 | 1668 | 633 | 1655802 | 1128539 | 6213 |
渠道-39 | 501 | 1438 | 530 | 1386851 | 946564 | 5663 |
渠道-00 | 466 | 1348 | 491 | 1344906 | 918124 | 5360 |
渠道-98 | 396 | 1081 | 420 | 1056999 | 726693 | 4272 |
渠道-28 | 389 | 1065 | 410 | 1072763 | 736434 | 4090 |
渠道-56 | 274 | 784 | 307 | 822426 | 558868 | 2841 |
渠道-16 | 232 | 608 | 241 | 601559 | 411468 | 2826 |
渠道-46 | 248 | 659 | 260 | 643569 | 440691 | 2805 |
渠道-78 | 206 | 552 | 215 | 547785 | 375983 | 2246 |
渠道-19 | 186 | 550 | 202 | 554238 | 378912 | 2168 |
In [33]:
# 统计不同渠道的转化率和客单价
result5['转化率'] = (result5.购买用户数 / result5.拉新用户数).round(4)
result5['ARPU'] = (result5.净销售额 / result5.拉新用户数).round(2)
result5['ARPPU'] = (result5.净销售额 / result5.购买用户数).round(2)
result5.sort_values(
by='净销售额',
ascending=False
).style.format(formatter={
'转化率': '{:.2%}',
'ARPU': '{:,.2f}',
'ARPPU': '{:,.2f}'
})
Out[33]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | 转化率 | ARPU | ARPPU | |
---|---|---|---|---|---|---|---|---|---|
channelID | |||||||||
渠道-89 | 1005 | 2843 | 1059 | 2806740 | 1906726 | 11331 | 8.87% | 247.70 | 2,792.78 |
渠道-52 | 767 | 2120 | 814 | 2089450 | 1426467 | 8434 | 9.09% | 247.74 | 2,724.19 |
渠道-53 | 731 | 1972 | 764 | 1990945 | 1361766 | 7909 | 9.24% | 251.73 | 2,723.59 |
渠道-76 | 594 | 1668 | 633 | 1655802 | 1128539 | 6213 | 9.56% | 266.51 | 2,787.55 |
渠道-39 | 501 | 1438 | 530 | 1386851 | 946564 | 5663 | 8.85% | 244.90 | 2,768.17 |
渠道-00 | 466 | 1348 | 491 | 1344906 | 918124 | 5360 | 8.69% | 250.92 | 2,886.06 |
渠道-28 | 389 | 1065 | 410 | 1072763 | 736434 | 4090 | 9.51% | 262.29 | 2,757.75 |
渠道-98 | 396 | 1081 | 420 | 1056999 | 726693 | 4272 | 9.27% | 247.42 | 2,669.19 |
渠道-56 | 274 | 784 | 307 | 822426 | 558868 | 2841 | 9.64% | 289.48 | 3,001.55 |
渠道-46 | 248 | 659 | 260 | 643569 | 440691 | 2805 | 8.84% | 229.44 | 2,595.04 |
渠道-16 | 232 | 608 | 241 | 601559 | 411468 | 2826 | 8.21% | 212.87 | 2,592.93 |
渠道-19 | 186 | 550 | 202 | 554238 | 378912 | 2168 | 8.58% | 255.64 | 2,979.77 |
渠道-78 | 206 | 552 | 215 | 547785 | 375983 | 2246 | 9.17% | 243.89 | 2,659.15 |
In [35]:
mean_users = result5.拉新用户数.mean()
mean_crate = result5.转化率.mean()
In [36]:
# 绘制渠道象限分析的散点图
plt.scatter(result5.拉新用户数, result5.转化率)
plt.plot([0, 12000], [mean_crate] * 2, color='r', linestyle='--', linewidth=0.5)
plt.plot([mean_users] * 2, [0.08, 0.1], color='r', linestyle='--', linewidth=0.5)
plt.xlim(0, 12000)
plt.ylim(0.08, 0.1)
for idx in result5.index:
y, x = result5.at[idx, '转化率'], result5.at[idx, '拉新用户数']
plt.text(x, y, idx, ha='center', va='bottom')
plt.show()
In [37]:
# 统计不同性别的净销售额、销售数量、订单数量、拉新用户数量、购买用户数量
result6 = pd.pivot_table(
temp4,
index='sex',
values=['payment', 'num', 'orderID', 'userID', 'buy'],
aggfunc={
'payment': 'sum',
'num': 'sum',
'orderID': 'sum',
'userID': 'count',
'buy': 'sum',
}
).astype('i8').rename(
columns={'payment': '净销售额', 'num': '销售数量', 'orderID': '订单数量', 'userID': '拉新用户数', 'buy': '购买用户数'}
)
result6.index.name = '性别'
result6
Out[37]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 拉新用户数 | |
---|---|---|---|---|---|
性别 | |||||
女 | 3989 | 11209 | 4234 | 11106698 | 44398 |
男 | 2006 | 5479 | 2112 | 5467335 | 21760 |
In [38]:
# 统计不同性别的转化率和客单价
result6['转化率'] = result6.购买用户数 / result6.拉新用户数
result6['ARPU'] = result6.净销售额 / result6.拉新用户数
result6['ARPPU'] = result6.净销售额 / result6.购买用户数
result6.drop(
columns=['拉新用户数', '购买用户数']
).style.format(formatter={
'净销售额': '{:,}',
'转化率': '{:.2%}',
'ARPU': '{:,.2f}',
'ARPPU': '{:,.2f}'
})
Out[38]:
销售数量 | 订单数量 | 净销售额 | 转化率 | ARPU | ARPPU | |
---|---|---|---|---|---|---|
性别 | ||||||
女 | 11209 | 4234 | 11,106,698 | 8.98% | 250.16 | 2,784.33 |
男 | 5479 | 2112 | 5,467,335 | 9.22% | 251.26 | 2,725.49 |
In [39]:
temp4['ageGroup'] = pd.cut(
temp4.age,
bins=[18, 25, 35, 45, 55, 66],
right=False,
labels=['18-24岁', '25-34岁', '35-44岁', '45-54岁', '55岁+']
)
temp4
Out[39]:
userID | age | sex | recentAcc | channelID | area | isOld | num | orderID | payment | profit | buy | ageGroup | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | user-550507 | 39 | 女 | 2021-01-12 | 渠道-52 | 山东 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 35-44岁 |
1 | user-499937 | 30 | 男 | 2021-01-08 | 渠道-89 | 河南 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 25-34岁 |
2 | user-515582 | 39 | 女 | 2021-01-09 | 渠道-89 | 四川 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 35-44岁 |
3 | user-519645 | 34 | 男 | 2021-01-10 | 渠道-00 | 广东 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 25-34岁 |
4 | user-529356 | 24 | 女 | 2021-01-08 | 渠道-19 | 四川 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 18-24岁 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
66153 | user-531290 | 24 | 女 | 2021-01-08 | 渠道-52 | 北京 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 18-24岁 |
66154 | user-537409 | 33 | 女 | 2021-01-10 | 渠道-39 | 上海 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 25-34岁 |
66155 | user-511000 | 40 | 女 | 2021-01-09 | 渠道-98 | 湖北 | False | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 35-44岁 |
66156 | user-518649 | 36 | 女 | 2021-01-10 | 渠道-00 | 上海 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 35-44岁 |
66157 | user-545810 | 18 | 女 | 2021-01-10 | 渠道-39 | 上海 | True | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 18-24岁 |
66158 rows × 13 columns
In [40]:
# 统计不同年龄段的净销售额、销售数量、订单数量、拉新用户数量、购买用户数量
result7 = pd.pivot_table(
temp4,
index='ageGroup',
values=['payment', 'num', 'orderID', 'userID', 'buy'],
aggfunc={
'payment': 'sum',
'num': 'sum',
'orderID': 'sum',
'userID': 'count',
'buy': 'sum',
},
observed=True
).astype('i8').rename(
columns={'payment': '净销售额', 'num': '销售数量', 'orderID': '订单数量', 'userID': '拉新用户数', 'buy': '购买用户数'}
)
result7
Out[40]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 拉新用户数 | |
---|---|---|---|---|---|
ageGroup | |||||
18-24岁 | 1170 | 3244 | 1238 | 3231708 | 12261 |
25-34岁 | 1568 | 4410 | 1661 | 4371373 | 17338 |
35-44岁 | 1602 | 4519 | 1688 | 4443134 | 17380 |
45-54岁 | 1266 | 3411 | 1341 | 3447739 | 13711 |
55岁+ | 389 | 1104 | 418 | 1080079 | 5468 |
In [41]:
# 统计不同年龄段的转化率和客单价
result7['转化率'] = result7.购买用户数 / result7.拉新用户数
result7['ARPU'] = result7.净销售额 / result7.拉新用户数
result7['ARPPU'] = result7.净销售额 / result7.购买用户数
result7.sort_values(
by='净销售额',
ascending=False
).style.format(formatter={
'净销售额': '{:,}',
'转化率': '{:.2%}',
'ARPU': '{:,.2f}',
'ARPPU': '{:,.2f}'
})
Out[41]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 拉新用户数 | 转化率 | ARPU | ARPPU | |
---|---|---|---|---|---|---|---|---|
ageGroup | ||||||||
35-44岁 | 1602 | 4519 | 1688 | 4,443,134 | 17380 | 9.22% | 255.65 | 2,773.49 |
25-34岁 | 1568 | 4410 | 1661 | 4,371,373 | 17338 | 9.04% | 252.13 | 2,787.87 |
45-54岁 | 1266 | 3411 | 1341 | 3,447,739 | 13711 | 9.23% | 251.46 | 2,723.33 |
18-24岁 | 1170 | 3244 | 1238 | 3,231,708 | 12261 | 9.54% | 263.58 | 2,762.14 |
55岁+ | 389 | 1104 | 418 | 1,080,079 | 5468 | 7.11% | 197.53 | 2,776.55 |
In [42]:
# 统计各省份的净销售额、销售数量、订单数量、拉新用户数量、购买用户数量
result8 = pd.pivot_table(
temp4,
index='area',
values=['payment', 'profit', 'num', 'orderID', 'userID', 'buy'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'sum',
'userID': 'count',
'buy': 'sum',
},
observed=True
).astype('i8').rename(
columns={'payment': '净销售额', 'profit': '毛利润', 'num': '销售数量', 'orderID': '订单数量', 'userID': '拉新用户数', 'buy': '购买用户数'}
)
result8
Out[42]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | |
---|---|---|---|---|---|---|
area | ||||||
上海 | 721 | 2014 | 756 | 1951379 | 1325965 | 7889 |
云南 | 68 | 160 | 71 | 155529 | 105775 | 664 |
北京 | 728 | 2030 | 769 | 1981054 | 1360129 | 7949 |
四川 | 657 | 1881 | 699 | 1793699 | 1217002 | 7294 |
安徽 | 48 | 124 | 51 | 120022 | 85302 | 680 |
山东 | 537 | 1505 | 564 | 1544444 | 1057210 | 5967 |
山西 | 64 | 169 | 66 | 168417 | 115786 | 679 |
广东 | 648 | 1732 | 689 | 1714908 | 1174084 | 7302 |
广西 | 56 | 178 | 61 | 183028 | 124292 | 612 |
江苏 | 624 | 1736 | 656 | 1740676 | 1189495 | 7354 |
江西 | 71 | 191 | 76 | 192670 | 131827 | 677 |
河北 | 55 | 156 | 58 | 153676 | 101156 | 648 |
河南 | 61 | 157 | 63 | 145070 | 99357 | 646 |
浙江 | 431 | 1220 | 457 | 1245445 | 857575 | 4667 |
湖北 | 190 | 526 | 203 | 546404 | 370781 | 1962 |
湖南 | 256 | 722 | 272 | 724999 | 488082 | 2591 |
福建 | 478 | 1327 | 506 | 1352620 | 928288 | 5283 |
贵州 | 58 | 160 | 63 | 166793 | 112253 | 664 |
重庆 | 244 | 700 | 266 | 693200 | 472876 | 2630 |
In [43]:
# 统计各省份的转化率和客单价
result8['转化率'] = result8.购买用户数 / result8.拉新用户数
result8['ARPU'] = result8.净销售额 / result8.拉新用户数
result8['ARPPU'] = result8.净销售额 / result8.购买用户数
result8.sort_values(
by='净销售额',
ascending=False
).style.format(formatter={
'净销售额': '{:,}',
'转化率': '{:.2%}',
'ARPU': '{:,.2f}',
'ARPPU': '{:,.2f}'
})
Out[43]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | 转化率 | ARPU | ARPPU | |
---|---|---|---|---|---|---|---|---|---|
area | |||||||||
北京 | 728 | 2030 | 769 | 1,981,054 | 1360129 | 7949 | 9.16% | 249.22 | 2,721.23 |
上海 | 721 | 2014 | 756 | 1,951,379 | 1325965 | 7889 | 9.14% | 247.35 | 2,706.49 |
四川 | 657 | 1881 | 699 | 1,793,699 | 1217002 | 7294 | 9.01% | 245.91 | 2,730.14 |
江苏 | 624 | 1736 | 656 | 1,740,676 | 1189495 | 7354 | 8.49% | 236.70 | 2,789.54 |
广东 | 648 | 1732 | 689 | 1,714,908 | 1174084 | 7302 | 8.87% | 234.85 | 2,646.46 |
山东 | 537 | 1505 | 564 | 1,544,444 | 1057210 | 5967 | 9.00% | 258.83 | 2,876.06 |
福建 | 478 | 1327 | 506 | 1,352,620 | 928288 | 5283 | 9.05% | 256.03 | 2,829.75 |
浙江 | 431 | 1220 | 457 | 1,245,445 | 857575 | 4667 | 9.24% | 266.86 | 2,889.66 |
湖南 | 256 | 722 | 272 | 724,999 | 488082 | 2591 | 9.88% | 279.81 | 2,832.03 |
重庆 | 244 | 700 | 266 | 693,200 | 472876 | 2630 | 9.28% | 263.57 | 2,840.98 |
湖北 | 190 | 526 | 203 | 546,404 | 370781 | 1962 | 9.68% | 278.49 | 2,875.81 |
江西 | 71 | 191 | 76 | 192,670 | 131827 | 677 | 10.49% | 284.59 | 2,713.66 |
广西 | 56 | 178 | 61 | 183,028 | 124292 | 612 | 9.15% | 299.07 | 3,268.36 |
山西 | 64 | 169 | 66 | 168,417 | 115786 | 679 | 9.43% | 248.04 | 2,631.52 |
贵州 | 58 | 160 | 63 | 166,793 | 112253 | 664 | 8.73% | 251.19 | 2,875.74 |
云南 | 68 | 160 | 71 | 155,529 | 105775 | 664 | 10.24% | 234.23 | 2,287.19 |
河北 | 55 | 156 | 58 | 153,676 | 101156 | 648 | 8.49% | 237.15 | 2,794.11 |
河南 | 61 | 157 | 63 | 145,070 | 99357 | 646 | 9.44% | 224.57 | 2,378.20 |
安徽 | 48 | 124 | 51 | 120,022 | 85302 | 680 | 7.06% | 176.50 | 2,500.46 |
In [44]:
# 统计新老用户的净销售额、销售数量、订单数量、拉新用户数量、购买用户数量
result9 = pd.pivot_table(
temp4,
index='isOld',
values=['payment', 'profit', 'num', 'orderID', 'userID', 'buy'],
aggfunc={
'payment': 'sum',
'profit': 'sum',
'num': 'sum',
'orderID': 'sum',
'userID': 'count',
'buy': 'sum',
},
observed=True
).astype('i8').rename(
columns={'payment': '净销售额', 'profit': '毛利润', 'num': '销售数量', 'orderID': '订单数量', 'userID': '拉新用户数', 'buy': '购买用户数'}
).rename(
index={False: '新用户', True: '老用户'}
)
result9
Out[44]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | |
---|---|---|---|---|---|---|
isOld | ||||||
新用户 | 2292 | 6401 | 2428 | 6304970 | 4302207 | 25095 |
老用户 | 3703 | 10287 | 3918 | 10269063 | 7015028 | 41063 |
In [45]:
# 统计新老用户的转化率和客单价
result9['转化率'] = result9.购买用户数 / result9.拉新用户数
result9['ARPU'] = result9.净销售额 / result9.拉新用户数
result9['ARPPU'] = result9.净销售额 / result9.购买用户数
result9.sort_values(
by='净销售额',
ascending=False
).style.format(formatter={
'净销售额': '{:,}',
'转化率': '{:.2%}',
'ARPU': '{:,.2f}',
'ARPPU': '{:,.2f}'
})
Out[45]:
购买用户数 | 销售数量 | 订单数量 | 净销售额 | 毛利润 | 拉新用户数 | 转化率 | ARPU | ARPPU | |
---|---|---|---|---|---|---|---|---|---|
isOld | |||||||||
老用户 | 3703 | 10287 | 3918 | 10,269,063 | 7015028 | 41063 | 9.02% | 250.08 | 2,773.17 |
新用户 | 2292 | 6401 | 2428 | 6,304,970 | 4302207 | 25095 | 9.13% | 251.24 | 2,750.86 |
In [ ]:
# Todo: 建议进行用户相关维度、商品相关维度的交叉组合分析