欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python数据分析 淘宝用户行为分析案例(One-Hot编码) pandas.Timestamp apply,applymap和map

程序员文章站 2022-04-16 16:16:13
Python数据分析1 Pandas时间处理1.1 to_datetimeto_datetime用于将指定时间格式的数据转换成时间序列。字符串 => 时间序列,使用参数format指定字符串的时间格式。# 2013-12-11的时间格式为%Y-%m-%dpd.to_datetime('2013-12-11', format="%Y-%m-%d") # Timestamp('2013-12-11 00:00:00')# 11/12/2013的时间格式为%d/%m/%Ypd.to_...

Python数据分析

1 pandas.Timestamp

1.1 to_datetime

to_datetime函数用于将指定时间格式的数据转换成pd.Timestamp。

  1. 字符串格式的时间 => 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')
  1. 时间戳(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)

Python数据分析 淘宝用户行为分析案例(One-Hot编码) pandas.Timestamp apply,applymap和map
绘制饼图

plt.pie(user_behavior_type_df, labels=user_behavior_type_df.index, autopct='%1.1f%%')

Python数据分析 淘宝用户行为分析案例(One-Hot编码) pandas.Timestamp apply,applymap和map

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'])
  1. 点击量
    用户总点击量
pv_count = user_behavior_cross_df.query('pv > 0')['pv'].shape[0]  # 493539
  1. 点击 => 购买
    点击后,无加购或收藏的情况下直接购买的行为。
pv_buy_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart == 0 & buy > 0')['buy'].shape[0]  # 9982
  1. 点击 => 加购
    点击后,无收藏的情况下直接加购的行为。
pv_cart_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart > 0')['cart'].shape[0]  # 31718
  1. 点击 => 加购 => 购买
    点击后,无收藏的情况下的加购和购买行为。
pv_cart_buy_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart > 0 & buy > 0')['buy'].shape[0]  # 951
  1. 点击 => 收藏
    无加购情况下的收藏行为。
pv_fav_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart == 0')['fav'].shape[0]  # 16631
  1. 点击 => 收藏 => 购买
    点击后,无加购情况下的收藏和购买行为
pv_fav_buy_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart == 0 & buy > 0')['buy'].shape[0]  # 411
  1. 点击 => 收藏 + 加购
    点击后的收藏和加购行为。
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
  1. 点击 => 收藏 + 加购 => 购买
    点击后的收藏加购到购买的行为。
pv_fav_cart_buy_count = user_behavior_cross_df.query('pv > 0 & fav > 0 & cart > 0 & buy > 0')['buy'].shape[0]  # 42
  1. 点击 => 流失
    点击后无购买无加购无收藏的行为。
pv_loss_count = user_behavior_cross_df.query('pv > 0 & fav == 0 & cart == 0 & buy == 0')['pv'].shape[0]  # 434131
3.2.2.4 计算转化率
  1. 直接购买转化率:点击–购买 / 点击量
pv_buy_count / pv_count  # 0.02022535199852494
  1. 加购购买转换率:点击 => 加购 + 购买 / 点击 => 加购
pv_cart_buy_count / pv_cart_count  # 0.029982974966895767
  1. 收藏购买转换率:点击 => 收藏 => 购买 / 点击 => 收藏
pv_fav_buy_count / pv_fav_count  # 0.02471288557513078
  1. 加购收藏购买转换率:点击 => 加购 + 收藏 => 购买 / 点击 => 加购 + 收藏
pv_fav_cart_buy_count / pv_fav_cart_count  # 0.019498607242339833
  1. 流失率:点击–流失 / 点击量
pv_loss_count / pv_count  # 0.8796285602556232

直接购买转化率低于加购和收藏等行为的综合转换率,因此通过修改产品交互界面和营销机制等方式增加用户的加购和收藏行为,进一步提高购买量。

3.2.2.5 转化率低的原因分析

提出假设:推荐机制不合理,向用户推荐的商品大部分是用户不喜欢的商品,导致转化率低。
分析思路:通过分析高浏览量商品与高购买量商品之间是否存在高度重合来验证假设,如果存在高度重合,就说明推荐的商品大部分是用户喜欢的商品,反之则可以说明假设成立。

  1. 获取点击量前十的商品
# 使用前面的交叉表
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
'''
  1. 获取购买量前十的商品
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
'''
  1. 查看点击量高且购买量也高的商品类别个数。
    判断点击量前十的商品的购买量是否位于前十名。
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
'''
  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