Python数据分析 淘宝用户行为分析案例(One-Hot编码) pandas.Timestamp apply,applymap和map
Python数据分析
1 pandas.Timestamp
1.1 to_datetime
to_datetime函数用于将指定时间格式的数据转换成pd.Timestamp。
- 字符串格式的时间 => pd.Timestamp
使用参数format指定字符串的时间格式。
# 2013-12-11的时间格式为%Y-%m-%d
pd.to_datetime('2013-12-11', format="%Y-%m-%d") # Timestamp('2013-12-11 00:00:00')
# 11/12/2013的时间格式为%d/%m/%Y
pd.to_datetime('11/12/2013', format="%d/%m/%Y") # Timestamp('2013-12-11 00:00:00')
# 20131211 10:9:8的时间格式为%Y%m%d %H:%M:%S
pd.to_datetime('20131211 10:9:8', format="%Y%m%d %H:%M:%S") # Timestamp('2013-12-11 10:09:08')
- 时间戳(str/int) => pd.Timestamp
使用参数unit指定时间戳的单位,默认为ns。
# 1511572885ns
pd.to_datetime(1511572885) # Timestamp('1970-01-01 00:00:01.511572885')
pd.to_datetime(1511572885, unit='ns') # Timestamp('1970-01-01 00:00:01.511572885') 默认
# 一般情况unit='s',即1511572885s
pd.to_datetime(1511572885, unit='s') # Timestamp('2017-11-25 01:21:25')
pd.to_datetime('1511572885', unit='s') # Timestamp('2017-11-25 01:21:25')
1.2 自定义函数处理时间戳
import time
from pandas import DataFrame
# 自定义函数处理时间戳
def get_time_series(timestamp_int):
return time.strftime('%Y-%m-%d', time.localtime(timestamp_int))
df = DataFrame({
'timestamp': [1511572885, 1433572885]
})
'''
timestamp
0 1511572885
1 1433572885
'''
df['datetime'] = df['timestamp'].apply(get_time_series)
'''
timestamp datetime
0 1511572885 2017-11-25
1 1433572885 2015-06-06
'''
df.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 2 non-null int64
1 datetime 2 non-null object
dtypes: int64(1), object(1)
memory usage: 160.0+ bytes
'''
1.3 时间序列操作
1.3.1 创建时间序列
import pandas
import datetime
# 创建pandas.Timestamp
dt1 = pandas.Timestamp('2011-12-13 14:15:16') # Timestamp('2011-12-13 14:15:16')
dt2 = pandas.Timestamp(2010, 11, 12, 13, 14, 15) # Timestamp('2010-11-12 13:14:15')
dt3 = pandas.Timestamp(datetime.datetime(2009, 10, 11, 12, 13, 14)) # Timestamp('2009-10-11 12:13:14')
# 创建时间序列:df['Datetime']
df = pandas.DataFrame({
'Datetime': [dt1, dt2, dt3]
})
'''
Datetime
0 2011-12-13 14:15:16
1 2010-11-12 13:14:15
2 2009-10-11 12:13:14
'''
1.3.2 强制类型转换 astype(‘datetime64[Y/M/D]’)
# 取出时间序列中的年份:Y-01-01
df['Datetime'].astype('datetime64[Y]')
'''
Datetime
0 2011-01-01
1 2010-01-01
2 2009-01-01
'''
# 取出时间序列中的年份-月份:Y-M-01
df['Datetime'].astype('datetime64[M]')
'''
Datetime
0 2011-12-01
1 2010-11-01
2 2009-10-01
'''
# 取出时间序列中的年份-月份-日期:Y-M-D
df['Datetime'].astype('datetime64[D]')
'''
Datetime
0 2011-12-13
1 2010-11-12
2 2009-10-11
'''
1.3.3 dt.year/month/day/date
# 只取出时间序列中的年份
df['Datetime'].dt.year
'''
0 2011
1 2010
2 2009
Name: Datetime, dtype: int64
'''
# 只取出时间序列中的月份
df['Datetime'].dt.month
'''
0 12
1 11
2 10
Name: Datetime, dtype: int64
'''
# 只取出时间序列中的日期
df['Datetime'].dt.day
'''
0 13
1 12
2 11
Name: Datetime, dtype: int64
'''
# 取出时间序列中的年份-月份-日期
df['Datetime'].dt.date
'''
0 2011-12-13
1 2010-11-12
2 2009-10-11
Name: Datetime, dtype: object
'''
2 apply,applymap和map
函数 | 调用者 | 说明 |
---|---|---|
apply | Dataframe | 作用于每行/每列 |
applymap | Dataframe | 作用于每个元素 |
map | Series | 作用于每个元素 |
df = pd.DataFrame(np.random.randint(0, 10, (4, 3)), columns=list('abc'), index=range(4))
'''
a b c
0 7 5 5
1 3 6 5
2 1 6 3
3 6 8 6
'''
2.1 apply
apply 作用于Dataframe的行/列。
# 处理列
df.apply(lambda x: x.max() - x.min()) # 默认处理列
df.apply(lambda x: x.max() - x.min(), axis=0)
'''
a 6
b 3
c 3
dtype: int64
'''
# 处理行
df.apply(lambda x: x.max() - x.min(), axis=1)
'''
0 2
1 3
2 5
3 2
dtype: int64
'''
2.2 applymap
applymap 作用于Dataframe的每个元素。
df.applymap(lambda x: True if x % 2==0 else False)
'''
a b c
0 False False False
1 False True False
2 False True False
3 True True True
'''
2.3 map
map 作用于Series的每个元素。
df['a'].map(lambda x: True if x % 2==0 else False)
'''
0 False
1 False
2 False
3 True
Name: a, dtype: bool
'''
3 淘宝用户行为分析案例
3.1 数据介绍
数据来源:User Behavior Data from Taobao for Recommendation
数据集包含了2017年11月25日至2017年12月3日之间,有行为的约一百万随机用户的所有行为。
字段介绍
字段 | 名称 | 说明 |
---|---|---|
user_id | 用户ID | 整数类型,序列化后的用户ID |
item_id | 商品ID | 整数类型,序列化后的商品ID |
category_id | 商品类目ID | 整数类型,序列化后的商品所属类目ID |
behavior_type | 行为类型 | 字符串,枚举类型,包括(‘pv’, ‘buy’, ‘cart’, ‘fav’) |
time_stamp | 时间戳 | 行为发生的时间戳 |
用户行为类型共有四种,分别是:
pv -- 商品详情页pv,等价于点击
buy -- 商品购买
cart -- 将商品加入购物车
fav -- 收藏商品
3.2 数据处理
3.2.1 数据读取
user_behavior_raw_df = pd.read_csv('./UserBehavior.csv', header=None, names=['User ID', 'Item ID', 'Category ID', 'Behavior type', 'Timestamp'])
user_behavior_raw_df.shape # (100150807, 5)
3.2.2 数据抽样
数据量级达到了1亿,随机抽样其中1百万左右的数据作为本次分析的数据。
方式1:sample
user_behavior_df = user_behavior_raw_df.sample(frac=0.01)
user_behavior_df.shape # (1001508, 5)
'''
方式2:take + random.permutation
user_behavior_df= df.take(indices=np.random.permutation(df.shape[0]), axis=0)[0: 1000000]
保存抽样数据
user_behavior_df.to_csv('./UserBehaviorSample.csv')
3.2.3 数据清洗
3.2.3.1 删除无意义的列
列Unnamed: 0表示抽样前的原始文件中的行索引,对数据分析意义不大,需要删除。
user_behavior_df = pd.read_csv('./UserBehaviorSample.csv')
user_behavior_df.head()
'''
Unnamed: 0 User ID Item ID Category ID Behavior type Timestamp
0 80952084 1199 3298493 4993094 pv 1512179888
1 32429469 651732 5123832 3607361 pv 1511698284
2 39961008 1001379 3838970 4173315 pv 1511609431
3 72665222 657102 3384922 4357323 pv 1511686599
4 79858234 986140 626992 383749 pv 1511568023
'''
user_behavior_df.drop(labels='Unnamed: 0', axis=1, inplace=True)
user_behavior_df.columns # Index(['User ID', 'Item ID', 'Category ID', 'Behavior type', 'Timestamp'], dtype='object')
3.2.3.2 缺失数据处理
检查是否存在缺失数据。
user_behavior_df.isnull().any(axis=0)
'''
User ID False
Item ID False
Category ID False
Behavior type False
Timestamp False
dtype: bool
'''
3.2.3.3 重复数据处理
检查是否存在重复数据。
user_behavior_df.duplicated(keep='first').sum() # 0
3.2.3.4 时间处理
检查时间戳列中是否存在异常数据
user_behavior_df['Timestamp'].min() # -1553487858
获取并删除所有异常数据
# 获取异常数据
user_behavior_df.loc[user_behavior_df['Timestamp'] < 0]
'''
User ID Item ID Category ID Behavior type Timestamp
166593 809603 268231 4756105 pv -1271476754
172870 484124 1662917 2885642 pv -1511634033
743823 841275 3458846 3607361 pv -1553487858
'''
# 删除异常数据
user_behavior_df.drop(index=user_behavior_df.loc[user_behavior_df['Timestamp'] < 0].index, inplace=True)
user_behavior_df['Timestamp'].min() < 0 # False
将时间戳转换为时间序列类型。
方式1 to_datetime
user_behavior_df['Datetime'] = pd.to_datetime(user_behavior_df['Timestamp'], unit='s')
方式2 自定义函数处理时间戳
import time
def get_time_series(timestamp_int):
return time.strftime('%Y-%m-%d', time.localtime(timestamp_int))
user_behavior_df['Datetime'] = user_behavior_df['time_stamp'].apply(get_time_series)
添加日期列和月份列
user_behavior_df['Date'] = user_behavior_df['Datetime'].astype('datetime64[D]')
user_behavior_df['Month'] = user_behavior_df['Datetime'].astype('datetime64[M]')
user_behavior_df.head()
'''
User ID Item ID Category ID Behavior type Timestamp Datetime Date Month
0 1199 3298493 4993094 pv 1512179888 2017-12-02 01:58:08 2017-12-02 2017-12-01
1 651732 5123832 3607361 pv 1511698284 2017-11-26 12:11:24 2017-11-26 2017-11-01
2 1001379 3838970 4173315 pv 1511609431 2017-11-25 11:30:31 2017-11-25 2017-11-01
3 657102 3384922 4357323 pv 1511686599 2017-11-26 08:56:39 2017-11-26 2017-11-01
4 986140 626992 383749 pv 1511568023 2017-11-25 00:00:23 2017-11-25 2017-11-01
'''
检查时间范围,不属于2017年的数据视为异常数据。
user_behavior_df.loc[user_behavior_df['Datetime'].astype('datetime64[Y]') != '2017-01-01'].shape[0] # 9 说明存在9条异常数据
仅保留2017年的数据。
user_behavior_df = user_behavior_df.loc[user_behavior_df['Datetime'].astype('datetime64[Y]') == '2017-01-01']
user_behavior_df.shape # (1001496, 8)
3.2 数据分析
这里主要的研究重点是用户的购买行为。
3.2.1 统计用户购买行为
对所有用户的不同购买行为进行数量统计,并做图展示。
注意,这样分析的主体是进行不同购买行为的用户个体,需要考虑同一用户多次进行同一购买行为的情况,并进行去重处理。
user_behavior_type_df = user_behavior_df.groupby(by='Behavior type')['User ID'].nunique() # 不能使用sum(),需要去重处理。
user_behavior_type_df
'''
Behavior type
buy 19822
cart 51525
fav 26407
pv 493539
Name: User ID, dtype: int64
'''
绘制柱状图
import matplotlib.pyplot as plt
%matplotlib inline
plt.bar(user_behavior_type_df.index, user_behavior_type_df.values)
绘制饼图
plt.pie(user_behavior_type_df, labels=user_behavior_type_df.index, autopct='%1.1f%%')
3.2.2 进一步分析
从上图可知,用户的点击量(pv)占83.5%,而购买量(buy)仅占3.4%,转化率较低。
3.2.2.1 获取每个用户的不同行为
方法1:使用One-Hot编码 get_dummies
One-Hot编码,又称为一位有效编码,通过采用N位状态寄存器来对应N个状态的方式进行编码,每个状态都有独立的寄存器位,且在任意时候只有一位有效。
one_hot_df = pd.get_dummies(user_behavior_df['Behavior type'])
one_hot_df.head()
'''
buy cart fav pv
0 0 0 0 1
1 0 0 0 1
2 0 0 0 1
3 0 0 0 1
4 0 0 0 1
'''
获取用户对同一商品的不同行为
user_item_behavior_df = pd.concat((user_behavior_df[['User ID', 'Item ID']],one_hot_df), axis=1)
user_item_behavior_df.head()
'''
User ID Item ID buy cart fav pv
0 1199 3298493 0 0 0 1
1 651732 5123832 0 0 0 1
2 1001379 3838970 0 0 0 1
3 657102 3384922 0 0 0 1
4 986140 626992 0 0 0 1
'''
方法2:交叉表
pd.crosstab(index=[user_behavior_df['User ID'], user_behavior_df['Item ID']], columns=user_behavior_df['Behavior type'])
'''
Behavior type buy cart fav pv
User ID Item ID
4 2252534 0 0 0 1
4002386 0 0 0 1
4514913 0 0 0 1
4779986 0 0 0 1
5073054 0 1 0 0
... ... ... ... ... ...
1018009 3189764 0 0 0 1
4203691 0 0 0 1
4589118 0 0 0 1
1018010 723316 0 0 0 1
2325932 0 0 0 1
'''
3.2.2.2 获取每个用户不同行为的数量汇总
方法1
pv_sum = user_item_behavior_df.groupby(by='User ID')['pv'].sum()
buy_sum = user_item_behavior_df.groupby(by='User ID')['buy'].sum()
cart_sum = user_item_behavior_df.groupby(by='User ID')['cart'].sum()
fav_sum = user_item_behavior_df.groupby(by='User ID')['fav'].sum()
user_item_behavior_total_df = DataFrame(data=[pv_sum, buy_sum, cart_sum, fav_sum]).T
user_item_behavior_total_df.head()
'''
pv buy cart fav
User ID
4 4 0 1 0
6 2 0 0 0
10 1 0 0 0
11 2 0 1 0
14 1 0 0 0
'''
方法2:交叉表
pd.crosstab(index=user_behavior_df['User ID'], columns=user_behavior_df['Behavior type'])
'''
Behavior type buy cart fav pv
User ID
4 0 1 0 4
6 0 0 0 2
10 0 0 0 1
11 0 1 0 2
14 0 0 0 1
... ... ... ... ...
1018004 0 0 0 1
1018006 0 0 0 5
1018007 0 0 0 2
1018009 0 0 0 8
1018010 0 0 0 2
'''
3.2.2.3 统计行为数据
使用上面获取的交叉表。
user_behavior_cross_df = pd.crosstab(index=user_behavior_df['User ID'], columns=user_behavior_df['Behavior type'])
- 点击量
用户总点击量
pv_count = user_behavior_cross_df.query('pv > 0')['pv'].shape[0] # 493539
- 点击 => 购买
点击后,无加购或收藏的情况下直接购买的行为。
pv_buy_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart == 0 & buy > 0')['buy'].shape[0] # 9982
- 点击 => 加购
点击后,无收藏的情况下直接加购的行为。
pv_cart_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart > 0')['cart'].shape[0] # 31718
- 点击 => 加购 => 购买
点击后,无收藏的情况下的加购和购买行为。
pv_cart_buy_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart > 0 & buy > 0')['buy'].shape[0] # 951
- 点击 => 收藏
无加购情况下的收藏行为。
pv_fav_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart == 0')['fav'].shape[0] # 16631
- 点击 => 收藏 => 购买
点击后,无加购情况下的收藏和购买行为
pv_fav_buy_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart == 0 & buy > 0')['buy'].shape[0] # 411
- 点击 => 收藏 + 加购
点击后的收藏和加购行为。
pv_fav_cart_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart > 0')['fav'].shape[0] + user_behavior_cross_df.query('pv > 0 & fav > 0 & cart > 0')['cart'].shape[0] # 2154
- 点击 => 收藏 + 加购 => 购买
点击后的收藏加购到购买的行为。
pv_fav_cart_buy_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart > 0 & buy > 0')['buy'].shape[0] # 42
- 点击 => 流失
点击后无购买无加购无收藏的行为。
pv_loss_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart == 0 & buy == 0')['pv'].shape[0] # 434131
3.2.2.4 计算转化率
- 直接购买转化率:点击–购买 / 点击量
pv_buy_count / pv_count # 0.02022535199852494
- 加购购买转换率:点击 => 加购 + 购买 / 点击 => 加购
pv_cart_buy_count / pv_cart_count # 0.029982974966895767
- 收藏购买转换率:点击 => 收藏 => 购买 / 点击 => 收藏
pv_fav_buy_count / pv_fav_count # 0.02471288557513078
- 加购收藏购买转换率:点击 => 加购 + 收藏 => 购买 / 点击 => 加购 + 收藏
pv_fav_cart_buy_count / pv_fav_cart_count # 0.019498607242339833
- 流失率:点击–流失 / 点击量
pv_loss_count / pv_count # 0.8796285602556232
直接购买转化率低于加购和收藏等行为的综合转换率,因此通过修改产品交互界面和营销机制等方式增加用户的加购和收藏行为,进一步提高购买量。
3.2.2.5 转化率低的原因分析
提出假设:推荐机制不合理,向用户推荐的商品大部分是用户不喜欢的商品,导致转化率低。
分析思路:通过分析高浏览量商品与高购买量商品之间是否存在高度重合来验证假设,如果存在高度重合,就说明推荐的商品大部分是用户喜欢的商品,反之则可以说明假设成立。
- 获取点击量前十的商品
# 使用前面的交叉表
item_behavior_cross_df = pd.crosstab(index=[user_behavior_df['Item ID']], columns=user_behavior_df['Behavior type'])
pv_top10_df = item_behavior_cross_df.sort_values(by='pv', axis=0, ascending=False)[:10]
'''
Behavior type buy cart fav pv
Item ID
812879 2 16 7 290
3845720 2 6 10 251
138964 0 12 6 212
2032668 2 7 4 196
2338453 1 7 2 193
1591862 0 0 0 191
1535294 5 11 9 176
59883 0 1 1 176
3031354 9 10 4 174
4211339 1 6 7 172
'''
- 获取购买量前十的商品
buy_top10_df = item_behavior_cross_df.sort_values(by='buy', axis=0, ascending=False)[:10]
'''
Behavior type buy cart fav pv
Item ID
3189426 9 2 0 40
3031354 9 10 4 174
2560262 9 13 0 86
5062984 8 2 0 37
3964583 8 12 1 62
3122135 8 4 5 27
1397311 7 2 0 9
222342 7 3 1 31
740947 7 5 5 66
3677861 7 3 3 49
'''
- 查看点击量高且购买量也高的商品类别个数。
判断点击量前十的商品的购买量是否位于前十名。
pv_top10_df.append(buy_top10_df).index.value_counts()
'''
3031354 2
1397311 1
740947 1
2560262 1
3964583 1
5062984 1
222342 1
59883 1
812879 1
3189426 1
138964 1
1535294 1
2338453 1
1591862 1
3122135 1
3845720 1
2032668 1
4211339 1
3677861 1
'''
可以看出,只有商品3031354的点击量和购买量都位于前十名。
4. 获取点击量前十商品的购买量
item_behavior_cross_df.sort_values(by='pv', axis=0, ascending=False)[:10]['buy']
'''
Item ID
812879 2
3845720 2
138964 0
2032668 2
2338453 1
1591862 0
1535294 5
59883 0
3031354 9
4211339 1
'''
- 获取购买量前十商品的点击量
item_behavior_cross_df.sort_values(by='buy', axis=0, ascending=False)[:10]['pv']
'''
Item ID
3189426 40
3031354 174
2560262 86
5062984 37
3964583 62
3122135 27
1397311 9
222342 31
740947 66
3677861 49
'''
结论:
可以看出,商品的点击量高,其购买量不一定高,顾客并不趋向于购买推荐商品。
由于高点击量并没有引发高购买量,所以转化率较低。
本文地址:https://blog.****.net/qq_36565509/article/details/107412768