数据分析模型
数据来源自阿里云天池的阿里移动推荐算法竞赛,以淘宝app平台在2014年11月18日-12月18日的数据为数据集。
值得注意的是,“双十二”大型促销活动的数据也会大量包含在数据集中,初步推断“双十二”当天的数据应该会出现井喷现象。
数据包含4个字段,分别是
user_id: 用户id
item_id:商品id
behavior_type:用户行为,1:点击,2:收藏,3:添加购物车,4:购买
user_geohash: 用户地理位置hash值
item_category:商品类别
time:时间戳
在这里通过行业的指标对淘宝用户行为进行分析。结合常见的电商数据分析模型与python数据分析及可视化,进行分析任务:
1、每日pv统计、每日uv统计;
2、每日用户行为趋势;
3、漏斗模型:用户行为转化分析;
4、周期内用户行为频率。
1.数据读取
parse_dates
: 这个参数用于指定哪些列应该被解析为日期时间类型。在这个例子中,['date']
表示将 date
列解析为日期时间格式。
infer_datetime_format
: 当设置为 True
时,pandas 会尝试推断日期时间格式,从而加快解析速度。这对于包含大量日期时间数据的列特别有用,可以提高读取效率。
import pandas as pd, numpy as np, matplotlib.pyplot as plt, seaborn as sns
columns_types = {'user_id':'int32', 'item_id':'int32', 'behavior_type':'category', 'item_category':'int16'}
df = pd.read_csv('./阶段2--Python数据分析实战/tianchi_mobile_recommend_train_user.csv',
dtype=columns_types, parse_dates=['time'],infer_datetime_format=True)
print(df.info(memory_usage='deep'))
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\922392374.py:6: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
df = pd.read_csv('./阶段2--Python数据分析实战/tianchi_mobile_recommend_train_user.csv',
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12256906 entries, 0 to 12256905
Data columns (total 6 columns):
# Column Dtype
--- ------ -----
0 user_id int32
1 item_id int32
2 behavior_type category
3 user_geohash object
4 item_category int16
5 time datetime64[ns]
dtypes: category(1), datetime64[ns](1), int16(1), int32(2), object(1)
memory usage: 715.8 MB
None
df.head()
|
user_id |
item_id |
behavior_type |
user_geohash |
item_category |
time |
0 |
98047837 |
232431562 |
1 |
NaN |
4245 |
2014-12-06 02:00:00 |
1 |
97726136 |
383583590 |
1 |
NaN |
5894 |
2014-12-09 20:00:00 |
2 |
98607707 |
64749712 |
1 |
NaN |
2883 |
2014-12-18 11:00:00 |
3 |
98662432 |
320593836 |
1 |
96nn52n |
6562 |
2014-12-06 10:00:00 |
4 |
98145908 |
290208520 |
1 |
NaN |
13926 |
2014-12-16 21:00:00 |
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12256906 entries, 0 to 12256905
Data columns (total 6 columns):
# Column Dtype
--- ------ -----
0 user_id int32
1 item_id int32
2 behavior_type category
3 user_geohash object
4 item_category int16
5 time datetime64[ns]
dtypes: category(1), datetime64[ns](1), int16(1), int32(2), object(1)
memory usage: 315.6+ MB
2.数据预处理
df.columns
Index(['user_id', 'item_id', 'behavior_type', 'user_geohash', 'item_category',
'time'],
dtype='object')
2.1 缺失值处理
df.duplicated().sum()
4092866
df.isnull().sum()
user_id 0
item_id 0
behavior_type 0
user_geohash 8334824
item_category 0
time 0
dtype: int64
这里发现user_geohash有缺失值,但是缺失值太多,我们先看看缺失值的比例,如果很高就可以删去这个列,如果比例较低,可以尝试用众数来填充,或者用平均值来填充,这里我们先不处理
df.isnull().sum()/df.shape[0]
user_id 0.00000
item_id 0.00000
behavior_type 0.00000
user_geohash 0.68001
item_category 0.00000
time 0.00000
dtype: float64
df.drop('user_geohash',axis=1,inplace=True)
df.columns
Index(['user_id', 'item_id', 'behavior_type', 'item_category', 'time'], dtype='object')
2.2日期标签的处理
df['time'] = pd.to_datetime(df['time'])
df['hour'] = df['time'].dt.hour
df['time'] = df['time'].dt.normalize()
df.head()
|
user_id |
item_id |
behavior_type |
item_category |
time |
hour |
0 |
98047837 |
232431562 |
1 |
4245 |
2014-12-06 |
2 |
1 |
97726136 |
383583590 |
1 |
5894 |
2014-12-09 |
20 |
2 |
98607707 |
64749712 |
1 |
2883 |
2014-12-18 |
11 |
3 |
98662432 |
320593836 |
1 |
6562 |
2014-12-06 |
10 |
4 |
98145908 |
290208520 |
1 |
13926 |
2014-12-16 |
21 |
下面对处理好的表格标签重命名
df = df.rename(columns={'user_id':'用户名',
'item_id':'商品',
'behavior_type':'行为',
'item_category':'商品类别',
'time':'日期',
'hour':'小时'})
df.head()
|
用户名 |
商品 |
行为 |
商品类别 |
日期 |
小时 |
0 |
98047837 |
232431562 |
1 |
4245 |
2014-12-06 |
2 |
1 |
97726136 |
383583590 |
1 |
5894 |
2014-12-09 |
20 |
2 |
98607707 |
64749712 |
1 |
2883 |
2014-12-18 |
11 |
3 |
98662432 |
320593836 |
1 |
6562 |
2014-12-06 |
10 |
4 |
98145908 |
290208520 |
1 |
13926 |
2014-12-16 |
21 |
3.数据分析
3.1 PV、UV统计
3.1.1PV统计
PV_daily = df.groupby('日期').count()['用户名'].rename('PV')
pv_daily = data.groupby(data['time'].dt.date).size().reset_index(name='pv')
相同点:
两段代码都计算了每天的访问次数。
最终结果都是一个包含日期和访问次数的 DataFrame。
不同点:
第一段代码假设 ‘日期’ 列已经是以日期格式存储的。
第二段代码从 ‘time’ 列中提取日期部分进行分组,适用于 ‘time’ 列包含时间信息的情况。
第一段代码使用 count() 方法,而第二段代码使用 size() 方法。count() 方法会忽略 NaN 值,而 size() 方法不会。
pv = df.groupby('日期')['用户名'].count().reset_index(name = 'PV')
pv.head()
|
日期 |
PV |
0 |
2014-11-18 |
366701 |
1 |
2014-11-19 |
358823 |
2 |
2014-11-20 |
353429 |
3 |
2014-11-21 |
333104 |
4 |
2014-11-22 |
361355 |
pv = df.groupby('日期').size().reset_index(name='PV')
pv.head()
|
日期 |
PV |
0 |
2014-11-18 |
366701 |
1 |
2014-11-19 |
358823 |
2 |
2014-11-20 |
353429 |
3 |
2014-11-21 |
333104 |
4 |
2014-11-22 |
361355 |
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(figsize=(16,6))
sns.lineplot(data=pv, x='日期', y='PV')
plt.title('PV统计')
plt.show()

3.1.2 UV统计
UV = df.groupby('日期')['用户名'].nunique().reset_index(name='UV')
UV.head()
|
日期 |
UV |
0 |
2014-11-18 |
6343 |
1 |
2014-11-19 |
6420 |
2 |
2014-11-20 |
6333 |
3 |
2014-11-21 |
6276 |
4 |
2014-11-22 |
6187 |
plt.figure(figsize=(16,10))
sns.lineplot(data=UV, x='日期', y='UV')
plt.title('UV统计')
plt.show()

3.1.3 PV、UV一张图表便于观察
daliy_PU = pd.merge(pv,UV,on='日期')
daliy_PU.head()
|
日期 |
PV |
UV |
0 |
2014-11-18 |
366701 |
6343 |
1 |
2014-11-19 |
358823 |
6420 |
2 |
2014-11-20 |
353429 |
6333 |
3 |
2014-11-21 |
333104 |
6276 |
4 |
2014-11-22 |
361355 |
6187 |
plt.figure(figsize=(16,6))
sns.lineplot(data=daliy_PU, x='日期', y='PV',color='red')
sns.lineplot(data=daliy_PU, x='日期', y='UV',color='blue')
plt.title('PV和UV统计')
plt.show()

3.1.4 根据小时具体分析
因为上面根据日期,时间轴过长,所以需要根据小时来分析
pv_hour = df.groupby(['日期','小时']).size().reset_index(name='pv')
uv_hour = df.groupby(['日期','小时']).nunique()['用户名'].reset_index(name='uv')
daliy_hour = pd.merge(pv_hour,uv_hour,on=['日期','小时'])
daliy_hour.head()
|
日期 |
小时 |
pv |
uv |
0 |
2014-11-18 |
0 |
13719 |
599 |
1 |
2014-11-18 |
1 |
7194 |
302 |
2 |
2014-11-18 |
2 |
5343 |
176 |
3 |
2014-11-18 |
3 |
3486 |
116 |
4 |
2014-11-18 |
4 |
2782 |
105 |
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(16,6))
sns.set_style("whitegrid")
sns.lineplot(data=daliy_hour, x='小时', y='pv',color='red',linestyle='dashed',label = 'pv')
sns.lineplot(data=daliy_hour, x='小时', y='uv',color='blue',label = 'uv')
plt.title('每小时PV和UV统计')
plt.legend(loc='best')
plt.grid(True)
plt.show()
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 23567 (\N{CJK UNIFIED IDEOGRAPH-5C0F}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 26102 (\N{CJK UNIFIED IDEOGRAPH-65F6}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27599 (\N{CJK UNIFIED IDEOGRAPH-6BCF}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21644 (\N{CJK UNIFIED IDEOGRAPH-548C}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 32479 (\N{CJK UNIFIED IDEOGRAPH-7EDF}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)
C:\Users\Lenovo\miniconda3\envs\pythonlearning\lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 35745 (\N{CJK UNIFIED IDEOGRAPH-8BA1}) missing from font(s) Arial.
fig.canvas.print_figure(bytes_io, **kw)

3.2 用户行为趋势分析
df.columns
Index(['用户名', '商品', '行为', '商品类别', '日期', '小时'], dtype='object')
3.2.1 以日期分析
behavior_date = pd.pivot_table(df, index='日期', columns='行为', values='用户名', aggfunc='size')
behavior_date.columns = ['点击', '收藏', '加购物车', '购买']
behavior_date.head()
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\1612957649.py:1: FutureWarning: The default value of observed=False is deprecated and will change to observed=True in a future version of pandas. Specify observed=False to silence this warning and retain the current behavior
behavior_df = pd.pivot_table(df, index='日期', columns='行为', values='用户名',aggfunc='size')
|
点击 |
收藏 |
加购物车 |
购买 |
日期 |
|
|
|
|
2014-11-18 |
345855 |
6904 |
10212 |
3730 |
2014-11-19 |
337870 |
7152 |
10115 |
3686 |
2014-11-20 |
332792 |
7167 |
10008 |
3462 |
2014-11-21 |
314572 |
6832 |
8679 |
3021 |
2014-11-22 |
340563 |
7252 |
9970 |
3570 |
plt.figure(figsize=(16,10))
plt.rcParams['font.sans-serif'] = ['SimHei']
sns.pointplot(data=behavior_date[['点击', '收藏', '加购物车', '购买']])
plt.title('用户行为统计')
plt.show()

plt.figure(figsize=(16,10))
sns.lineplot(data=behavior_date[['收藏', '加购物车', '购买']])
plt.title('用户行为统计')
plt.show()

3.2.2 以小时分析
behavior_hour = pd.pivot_table(df, index='小时', columns='行为', values='用户名', aggfunc='size')
behavior_hour.columns = ['点击', '收藏', '加购物车', '购买']
behavior_hour.head()
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\2708058553.py:1: FutureWarning: The default value of observed=False is deprecated and will change to observed=True in a future version of pandas. Specify observed=False to silence this warning and retain the current behavior
behavior_hour = pd.pivot_table(df, index='小时', columns='行为', values='用户名', aggfunc='size')
|
点击 |
收藏 |
加购物车 |
购买 |
小时 |
|
|
|
|
0 |
487341 |
11062 |
14156 |
4845 |
1 |
252991 |
6276 |
6712 |
1703 |
2 |
139139 |
3311 |
3834 |
806 |
3 |
93250 |
2282 |
2480 |
504 |
4 |
75832 |
2010 |
2248 |
397 |
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure(figsize=(16,10))
sns.lineplot(data=behavior_hour[['收藏', '加购物车', '购买']])
plt.title('用户行为统计(小时)')
plt.show()

3.3 漏斗模型
3.3.1 漏斗模型介绍
漏斗模型是一种常用的用户行为分析工具,主要用于分析用户在不同阶段的转化率。在电商领域,漏斗模型通常用于分析用户从浏览商品到最终购买的各个阶段的转化情况。典型的电商漏斗模型包括以下几个阶段:
- 点击(Click)
- 收藏(Collect)
- 添加购物车(Add to Cart)
- 购买(Purchase)
通过漏斗模型,可以识别用户在哪个阶段流失最多,从而采取相应的优化措施。
需要计算的量
- 每个阶段的用户数量:统计每个阶段的用户数量。
- 转化率:计算每个阶段到下一个阶段的转化率,即后一个阶段的用户数量除以前一个阶段的用户数量。
具体分析步骤
1. 读取数据并预处理
假设数据存储在一个CSV文件中,包含user_id
、item_id
、behavior_type
、user_geohash
、item_category
和time
等字段。
import pandas as pd
data = pd.read_csv('taobao_data.csv')
data['time'] = pd.to_datetime(data['time'], unit='s')
data['behavior_type'] = data['behavior_type'].map({1: 'click', 2: 'collect', 3: 'add_to_cart', 4: 'purchase'})
print(data.head())
2. 统计每个阶段的用户数量
funnel_data = data.groupby('behavior_type').size().reset_index(name='count')
funnel_data = funnel_data.sort_values(by='count', ascending=False)
print(funnel_data)
3. 计算转化率
funnel_data['conversion_rate'] = funnel_data['count'] / funnel_data['count'].shift(1)
funnel_data.loc[0, 'conversion_rate'] = 1.0
print(funnel_data)
4. 绘制漏斗图
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(10, 6))
sns.barplot(x='count', y='behavior_type', data=funnel_data, palette='viridis')
plt.title('Funnel Analysis of User Behavior')
plt.xlabel('Count')
plt.ylabel('Behavior')
plt.show()
完整代码
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
data = pd.read_csv('taobao_data.csv')
data['time'] = pd.to_datetime(data['time'], unit='s')
data['behavior_type'] = data['behavior_type'].map({1: 'click', 2: 'collect', 3: 'add_to_cart', 4: 'purchase'})
funnel_data = data.groupby('behavior_type').size().reset_index(name='count')
funnel_data = funnel_data.sort_values(by='count', ascending=False)
funnel_data['conversion_rate'] = funnel_data['count'] / funnel_data['count'].shift(1)
funnel_data.loc[0, 'conversion_rate'] = 1.0
print(funnel_data)
plt.figure(figsize=(10, 6))
sns.barplot(x='count', y='behavior_type', data=funnel_data, palette='viridis')
plt.title('Funnel Analysis of User Behavior')
plt.xlabel('Count')
plt.ylabel('Behavior')
plt.show()
结果解释
- 每个阶段的用户数量:显示了每个行为类型的用户数量。
- 转化率:显示了从一个阶段到下一个阶段的用户转化率。例如,从点击到收藏的转化率、从收藏到添加购物车的转化率等。
通过漏斗模型,可以直观地看到用户在各个阶段的流失情况,帮助电商平台识别关键的优化点,提升用户转化率。例如,如果发现从点击到收藏的转化率较低,可以考虑优化商品详情页的设计或增加推荐系统,以提高用户的兴趣和互动。
3.3.2 漏斗模型计算
behavior_user = df.groupby('行为')['用户名'].size().reset_index(name='用户数')
behavior_user2 = behavior_user.copy()
behavior_user.head()
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\184507160.py:2: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning.
behavior_user = df.groupby('行为')['用户名'].size().reset_index(name='用户数')
|
行为 |
用户数 |
0 |
1 |
11550581 |
1 |
2 |
242556 |
2 |
3 |
343564 |
3 |
4 |
120205 |
1. 单一转化率
pre_num = np.array(behavior_user['用户数'])[:-1]
next_num = np.array(behavior_user['用户数'])[1:]
print(pre_num,'\n',next_num,'\n')
conversion_rate = next_num / pre_num
print(conversion_rate)
[11550581 242556 343564]
[242556 343564 120205]
[0.02099946 1.41643167 0.34987659]
conversion_rate = list(conversion_rate)
conversion_rate.insert(0,1)
print(conversion_rate)
[1, 0.020999463143888605, 1.4164316693876877, 0.34987658776821784]
conversion_rate = [round(i * 100, 2) for i in conversion_rate]
print(conversion_rate)
behavior_user['单一转化率'] = conversion_rate
behavior_user
[100, 2.1, 141.64, 34.99]
|
行为 |
用户数 |
单一转化率 |
0 |
1 |
11550581 |
100.00 |
1 |
2 |
242556 |
2.10 |
2 |
3 |
343564 |
141.64 |
3 |
4 |
120205 |
34.99 |
2. 总转化率
total_rate = behavior_user['用户数'] / behavior_user['用户数'][0]
total_rate = [round(i * 100, 2) for i in total_rate]
behavior_user['总转化率'] = total_rate
behavior_user
|
行为 |
用户数 |
单一转化率 |
总转化率 |
0 |
1 |
11550581 |
100.00 |
100.00 |
1 |
2 |
242556 |
2.10 |
2.10 |
2 |
3 |
343564 |
141.64 |
2.97 |
3 |
4 |
120205 |
34.99 |
1.04 |
3.3.3 漏斗图绘制
behavior_user['行为'] = ['点击', '收藏', '加购物车', '购买']
behavior_user.index = behavior_user['行为']
behavior_user.drop(['行为','用户数'],axis=1,inplace=True)
behavior_user
|
单一转化率 |
总转化率 |
行为 |
|
|
点击 |
100.00 |
100.00 |
收藏 |
2.10 |
2.10 |
加购物车 |
141.64 |
2.97 |
购买 |
34.99 |
1.04 |
funnel_data = behavior_user.sort_values(by='总转化率', ascending=False)
funnel_data
|
单一转化率 |
总转化率 |
行为 |
|
|
点击 |
100.00 |
100.00 |
加购物车 |
141.64 |
2.97 |
收藏 |
2.10 |
2.10 |
购买 |
34.99 |
1.04 |
x = funnel_data.index
y = funnel_data['总转化率']
zip(x,y)
x_y = list(zip(x,y))
x_y
[('点击', 100.0), ('加购物车', 2.97), ('收藏', 2.1), ('购买', 1.04)]
from pyecharts.charts import Funnel
from pyecharts import options as opts
funnel = (
Funnel()
.add
('总转化率', x_y,
label_opts=opts.LabelOpts(position='inside')
)
)
funnel.render_notebook()
<div id="49334925841b45d69ff5087442929358" style="width:900px; height:500px;"></div>

3.4 周期内用户行为频率
def user_behavior_frequency(data, start_date, end_date):
filtered_data = data[(data['日期'] >= start_date) & (data['日期'] <= end_date)]
user_behavior_counts = filtered_data.groupby('用户名')['行为'].count()
avg_behavior_count = user_behavior_counts.mean()
return avg_behavior_count
start_date = pd.to_datetime('2014-11-01')
avg_behavior_counts = []
for i in range(1, 8):
end_date = start_date + pd.Timedelta(days=10)
avg_behavior_count = user_behavior_frequency(df, start_date, end_date)
avg_behavior_counts.append(avg_behavior_count)
print(f"第{i}个周期平均行为数量:{avg_behavior_count:.2f}")
start_date = end_date
print(avg_behavior_counts)
x = range(1, 8)
plt.plot(x, avg_behavior_counts)
plt.xlabel('Period')
plt.ylabel('Average Behavior Count')
plt.title('Average Behavior Count Over Time')
plt.show()
第1个周期平均行为数量:nan
第2个周期平均行为数量:165.81
第3个周期平均行为数量:426.79
第4个周期平均行为数量:460.75
第5个周期平均行为数量:368.99
第6个周期平均行为数量:nan
第7个周期平均行为数量:nan
[nan, 165.8122357914514, 426.78595458368375, 460.7477002583979, 368.9868804664723, nan, nan]

以下是废案
behavior_user2.index = behavior_user2['行为']
behavior_user2.drop(['行为'],axis=1,inplace=True)
behavior_user2
|
用户数 |
行为 |
|
1 |
11550581 |
2 |
242556 |
3 |
343564 |
4 |
120205 |
behavior_trends = behavior_user2.T
print(behavior_trends)
behavior_trends.columns = ['click', 'collect', 'add_to_cart', 'purchase']
print(behavior_trends)
行为 1 2 3 4
用户数 11550581 242556 343564 120205
click collect add_to_cart purchase
用户数 11550581 242556 343564 120205
stats = behavior_trends[['click', 'collect', 'add_to_cart', 'purchase']].describe().transpose()
print(stats)
sns.kdeplot(behavior_trends['purchase'], shade=True)
plt.title('Density Distribution of Purchase Behavior')
plt.xlabel('Purchase Count')
plt.ylabel('Density')
plt.show()
count mean std min 25% 50% \
click 1.0 11550581.0 NaN 11550581.0 11550581.0 11550581.0
collect 1.0 242556.0 NaN 242556.0 242556.0 242556.0
add_to_cart 1.0 343564.0 NaN 343564.0 343564.0 343564.0
purchase 1.0 120205.0 NaN 120205.0 120205.0 120205.0
75% max
click 11550581.0 11550581.0
collect 242556.0 242556.0
add_to_cart 343564.0 343564.0
purchase 120205.0 120205.0
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\4096138241.py:7: FutureWarning:
`shade` is now deprecated in favor of `fill`; setting `fill=True`.
This will become an error in seaborn v0.14.0; please update your code.
sns.kdeplot(behavior_trends['purchase'], shade=True)
C:\Users\Lenovo\AppData\Local\Temp\ipykernel_33996\4096138241.py:7: UserWarning: Dataset has 0 variance; skipping density estimate. Pass `warn_singular=False` to disable this warning.
sns.kdeplot(behavior_trends['purchase'], shade=True)
所有评论(0)