数据分析
数据分析的价值主要在于熟悉了解整个数据集的基本情况包括每个文件里有哪些数据,具体的文件中的每个字段表示什么实际含义,以及数据集中特征之间的相关性,在推荐场景下主要就是分析用户本身的基本属性,文章基本属性,以及用户和文章交互的一些分布,这些都有利于后面的召回策略的选择,以及特征工程。
导包
%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.rc('font', family='SimHei', size=13)
import os,gc,re,warnings,sys
warnings.filterwarnings("ignore")
读取数据(数据可以从天池比赛上下载到本地)
path = 'data/' #目录自定义
#####train
trn_click = pd.read_csv(path+'train_click_log.csv')
#trn_click = pd.read_csv(path+'train_click_log.csv', names=['user_id','item_id','click_time','click_environment','click_deviceGroup','click_os','click_country','click_region','click_referrer_type'])
item_df = pd.read_csv(path+'articles.csv')
item_df = item_df.rename(columns={'article_id': 'click_article_id'}) #重命名,方便后续match
item_emb_df = pd.read_csv(path+'articles_emb.csv')
#####test
tst_click = pd.read_csv(path+'testA_click_log.csv')
下面通过notebook展示刚才读取的DF
首先看训练集文件,一共有二十万个用户,1112623条交互数据
可以通过如下代码查看训练集中用户个数:
trn_click.user_id.nunique()
列名对应的属性介绍
user_id: 用户的唯一标识
click_article_id: 用户点击的文章唯一标识
click_timestamp: 用户点击文章时的时间戳
click_environment: 用户点击文章的环境
click_deviceGroup: 用户点击文章的设备组
click_os: 用户点击文章时的操作系统
click_country: 用户点击文章时的所在的国家
click_region: 用户点击文章时所在的区域
click_referrer_type: 用户点击文章时,文章的来源
再看新闻数据,共有364047条新闻
测试集文件共有五万个用户(200000 ~ 249999)
查看测试集用户个数
#测试集中的用户数量为5w
tst_click.user_id.nunique()
新闻embedding文件(每个新闻对应一个251维的向量)
进行数据预处理
计算用户点击rank(即每个用户点击新闻的时间先后)和点击次数
# 对每个用户的点击时间戳进行排序
trn_click['rank'] = trn_click.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)
tst_click['rank'] = tst_click.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)
#计算用户点击文章的次数,并添加新的一列count
trn_click['click_cnts'] = trn_click.groupby(['user_id'])['click_timestamp'].transform('count')
tst_click['click_cnts'] = tst_click.groupby(['user_id'])['click_timestamp'].transform('count')
结果展示如下:
这里要注意的是对每个用户点击时间的排序是降序的,说明越早点击的新闻rank值越大,因此最近点击的新闻对应的rank也就越小(越靠前)
绘制直方图查看基本属性分布
plt.figure()
plt.figure(figsize=(15, 20))
i = 1
for col in ['click_article_id', 'click_timestamp', 'click_environment', 'click_deviceGroup', 'click_os', 'click_country',
'click_region', 'click_referrer_type', 'rank', 'click_cnts']:
plot_envs = plt.subplot(5, 2, i)
i += 1
v = trn_click[col].value_counts().reset_index()[:10]
fig = sns.barplot(x=v['index'], y=v[col])
for item in fig.get_xticklabels():
item.set_rotation(90)
plt.title(col)
plt.tight_layout()
plt.show()
直方图部分展示如下:
先解释代码里 v = trn_click[col].value_counts().reset_index()[:10]的意思,这里拿左上角的点击新闻id举例
对于value_counts()这个函数就是计算所有新闻被点击的次数,并按次数多少进行排序,代码中就是计算出这个排序之后取前十个被点击最多的新闻进行绘制直方图分析。
其他属性数据的分析同理。
查看新闻主题个数以及绘图分析
print(item_df['category_id'].nunique()) # 461个文章主题
item_df['category_id'].hist()
查看用户重复点击
先将训练集用户与测试集用户整合到一起:
#用户重复点击
user_click_count = user_click_merge.groupby(['user_id', 'click_article_id'])['click_timestamp'].agg({'count'}).reset_index()
user_click_count[:10]
,
对于上述这行代码,我个人理解是对每个(用户id和点击的新闻id)交互对进行分组,只要不同,就被分为一组,如果相同,那就说明这个用户重复点击了同一篇新闻,对应的conut就+1,(如果conunt=2,说明这个用户点击了同一个新闻两次),可以发现合并之后的数据经过用户id和文章分组处理之后中取出前十条交互中所点击的文章都没有被重复点击过。
取出被重复点击7次及以上的文章
user_click_count[user_click_count['count']>7]
可以发现只有五条新闻被重复点击超过7次(第一行说明了用户86295点击了74254这条新闻10次)
查看用户点击新闻次数
#用户点击新闻次数
user_click_count.loc[:,'count'].value_counts()
上图可以说明极大部分用户不会重复看同一篇新闻,可以看到只有一个用户重复看了同一篇新闻13次。也就是可以看出:有1605541(约占99.2%)的用户未重复阅读过文章,仅有极少数用户重复点击过某篇文章。 这个也可以单独制作成特征。
进行用户点击新闻数量的分布分析
user_click_item_count = sorted(user_click_merge.groupby('user_id')['click_article_id'].count(), reverse=True)
plt.plot(user_click_item_count)
可以看到用户0总共点击了两篇新闻,用户1也是,249995点击了34篇新闻,通过上面的曲线图可以看出大部分用户都点击了少量的新闻,不会点击太多新闻。
点击次数在前五十的用户
plt.plot(user_click_item_count[:50])
可以看到前五十的用户点击次数都接近200,可以将这些用户定义为活跃用户。需要注意的是,判断用户活跃度,更加全面的是再结合上点击时间,后面我们会基于点击次数和点击时间两个方面来判断用户活跃度。
新闻点击次数分析
item_click_count = sorted(user_click_merge.groupby('click_article_id')['user_id'].count(), reverse=True)
plt.plot(item_click_count)
plt.plot(item_click_count[:100])
可以看出点击次数最多的前100篇新闻,点击次数大于1000次,可以依据新闻被点击的次数来定义热门新闻以及冷门新闻。
新闻共现频次:两篇新闻连续出现的次数
tmp = user_click_merge.sort_values('click_timestamp')
tmp['next_item'] = tmp.groupby(['user_id'])['click_article_id'].transform(lambda x:x.shift(-1))
union_item = tmp.groupby(['click_article_id','next_item'])['click_timestamp'].agg({'count'}).reset_index().sort_values('count', ascending=False)
union_item[['count']].describe()
由统计数据可以看出,平均共现次数3.18,最高为2202。说明用户看的新闻,相关性是比较强的。
#画个图直观地看一看
x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)
可以看到大部分新闻都跟别的新闻有过共现。
分析新闻类型信息
#不同类型的新闻出现的次数
plt.plot(user_click_merge['category_id'].value_counts().values)
可以看到只有大约50个类型的新闻被大多数用户所点击,其他类型的新闻很少被用户所点击。
分析用户点击的新闻类型的偏好
此特征可以用于度量用户的兴趣是否广泛。
plt.plot(sorted(user_click_merge.groupby('user_id')['category_id'].nunique(), reverse=True))
从上图中可以看出有一小部分用户阅读类型是极其广泛的,大部分人都处在20个新闻类型以下。
分析用户查看文章的长度的分布
通过统计不同用户点击新闻的平均字数,这个可以反映用户是对长文更感兴趣还是对短文更感兴趣。
plt.plot(sorted(user_click_merge.groupby('user_id')['words_count'].mean(), reverse=True))
从上图中可以发现有一小部分人看的文章平均词数非常高,也有一小部分人看的平均文章次数非常低。
大多数人偏好于阅读字数在200-400字之间的新闻。
用户点击新闻的时间分析
这里很奇怪,我下载的数据即中没有created_at_ts这一属性,但是天池提供的代码中却有这一属性,所以我直接处理我自己下载的数据
#为了更好的可视化,这里把时间进行归一化操作
from sklearn.preprocessing import MinMaxScaler
mm = MinMaxScaler()
user_click_merge['click_timestamp'] = mm.fit_transform(user_click_merge[['click_timestamp']])
user_click_merge = user_click_merge.sort_values('click_timestamp')
user_click_merge.head()
总结
通过数据分析的过程, 我们目前可以得到以下几点重要的信息, 这个对于我们进行后面的特征制作和分析非常有帮助:
1.训练集和测试集的用户id没有重复,也就是测试集里面的用户模型是没有见过的
2.训练集中用户最少的点击文章数是2, 而测试集里面用户最少的点击文章数是1
3.用户对于文章存在重复点击的情况, 但这个都存在于训练集里面
4.同一用户的点击环境存在不唯一的情况,后面做这部分特征的时候可以采用统计特征
5.用户点击文章的次数有很大的区分度,后面可以根据这个制作衡量用户活跃度的特征
6.文章被用户点击的次数也有很大的区分度,后面可以根据这个制作衡量文章热度的特征
7.用户看的新闻,相关性是比较强的,所以往往我们判断用户是否对某篇文章感兴趣的时候, 在很大程度上会和他历史点击过的文章有关
8.用户点击的文章字数有比较大的区别, 这个可以反映用户对于文章字数的区别
9.用户点击过的文章主题也有很大的区别, 这个可以反映用户的主题偏好
10.不同用户点击文章的时间差也会有所区别, 这个可以反映用户对于文章时效性的偏好