前言读取数据

此次比赛是新闻推荐场景下的用户行为预测挑战赛, 是Datawhale与天池联合举办,该赛题是以新闻APP中的新闻推荐为背景, 目的是要求我们根据用户历史浏览点击新闻文章的数据信息预测用户未来的点击行为, 即用户的最后一次点击的新闻文章, 这道赛题的设计初衷是引导大家了解推荐系统中的一些业务背景, 解决实际问题!

赛题链接: 零基础入门推荐系统 - 新闻推荐

对于刚接触推荐系统同学推荐先浏览以下基础知识:

  • 推荐系统摘要
  • 推荐系统知识梳理——协同过滤
  • 推荐系统知识梳理——矩阵分解
  • 推荐系统知识梳理——FM
  • 推荐系统知识梳理——Wide&Deep
  • 推荐系统知识梳理——GBDT&LR

数据分析

数据分析的价值主要在于熟悉了解整个数据集的基本情况包括每个文件里有哪些数据,具体的文件中的每个字段表示什么实际含义,以及数据集中特征之间的相关性,在推荐场景下主要就是分析用户本身的基本属性,文章基本属性,以及用户和文章交互的一些分布,这些都有利于后面的召回策略的选择,以及特征工程。

建议:当特征工程和模型调参已经很难继续上分了,可以回来在重新从新的角度去分析这些数据,或许可以找到上分的灵感

导包

%matplotlib inline
import pandas as pd
import numpy as npimport 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 = './python/python_project/datawhale/tuijian/tianchi-news/dataset/'#####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')
trn_click.head()

item_df.head()

tst_click.head()

数据预处理

计算用户点击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')

数据浏览

用户点击日志文件_训练集

trn_click = trn_click.merge(item_df, how='left', on=['click_article_id'])
trn_click.head()

train_click_log.csv文件数据中每个字段的含义

  • user_id: 用户的唯一标识
  • click_article_id: 用户点击的文章唯一标识
  • click_timestamp: 用户点击文章时的时间戳
  • click_environment: 用户点击文章的环境
  • click_deviceGroup: 用户点击文章的设备组
  • click_os: 用户点击文章时的操作系统
  • click_country: 用户点击文章时的所在的国家
  • click_region: 用户点击文章时所在的区域
  • click_referrer_type: 用户点击文章时,文章的来源
#用户点击日志信息
trn_click.info()

trn_click.describe()

#训练集中的用户数量为20w
trn_click.user_id.nunique()
#200000trn_click.groupby('user_id')['click_article_id'].count().min()  # 训练集里面每个用户至少点击了两篇文章
#2

画直方图大体看一下基本的属性分布(常画)

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 += 1v = 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()


从图片分析可以得出:

  • 从点击时间clik_timestamp来看,分布较为平均,可不做特殊处理。由于时间戳是13位的,后续将时间格式转换成10位方便计算。

  • 从点击环境click_environment来看,仅有1922次(占0.1%)点击环境为1;仅有24617次(占2.3%)点击环境为2;剩余(占97.6%)点击环境为4。

  • 从点击设备组click_deviceGroup来看,设备1占大部分(60.4%),设备3占36%。

  • 从点击国家可以看出大部分为1号国家

  • 从点击文章来看分布较为均匀

测试集用户点击日志

tst_click = tst_click.merge(item_df, how='left', on=['click_article_id'])
tst_click.head()

tst_click.describe()

我们可以看出训练集和测试集的用户是完全不一样的

训练集的用户ID由0 ~ 199999,而测试集A的用户ID由200000 ~ 249999。

#测试集中的用户数量为5w
tst_click.user_id.nunique()
#50000tst_click.groupby('user_id')['click_article_id'].count().min() # 注意测试集里面有只点击过一次文章的用户
#1

新闻文章信息数据表

#新闻文章数据集浏览
item_df.head().append(item_df.tail())

item_df['words_count'].value_counts()

print(item_df['category_id'].nunique())     # 461个文章主题
item_df['category_id'].hist()

item_df.shape       # 364047篇文章
#(364047, 4)

新闻文章embedding向量表示

item_emb_df.head()

item_emb_df.shape
#(364047, 251)

数据分析

用户重复点击

#####merge
user_click_merge = trn_click.append(tst_click)#用户重复点击
user_click_count = user_click_merge.groupby(['user_id', 'click_article_id'])['click_timestamp'].agg({'count'}).reset_index()
user_click_count[:10]

user_click_count[user_click_count['count']>7]

user_click_count['count'].unique()
#array([ 1,  2,  4,  3,  6,  5, 10,  7, 13])#用户点击新闻次数
user_click_count.loc[:,'count'].value_counts()
'''
1     1605541
2       11621
3         422
4          77
5          26
6          12
10          4
7           3
13          1
Name: count, dtype: int64
'''

可以看出:有1605541(约占99.2%)的用户未重复阅读过文章,仅有极少数用户重复点击过某篇文章。 这个也可以单独制作成特征

用户点击环境变化分析

def plot_envs(df, cols, r, c):plt.figure()plt.figure(figsize=(10, 5))i = 1for col in cols:plt.subplot(r, c, i)i += 1v = df[col].value_counts().reset_index()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()# 分析用户点击环境变化是否明显,这里随机采样10个用户分析这些用户的点击环境分布
sample_user_ids = np.random.choice(tst_click['user_id'].unique(), size=10, replace=False)
sample_users = user_click_merge[user_click_merge['user_id'].isin(sample_user_ids)]
cols = ['click_environment','click_deviceGroup', 'click_os', 'click_country', 'click_region','click_referrer_type']
for _, user_df in sample_users.groupby('user_id'):plot_envs(user_df, cols, 2, 3)








可以看出绝大多数数的用户的点击环境是比较固定的。思路:可以基于这些环境的统计特征来代表该用户本身的属性

用户点击新闻数量的分布

user_click_item_count = sorted(user_click_merge.groupby('user_id')['click_article_id'].count(), reverse=True)
plt.plot(user_click_item_count)


可以根据用户的点击文章次数看出用户的活跃度

#点击次数在前50的用户
plt.plot(user_click_item_count[:50])


点击次数排前50的用户的点击次数都在100次以上。思路:我们可以定义点击次数大于等于100次的用户为活跃用户,这是一种简单的处理思路, 判断用户活跃度,更加全面的是再结合上点击时间,后面我们会基于点击次数和点击时间两个方面来判断用户活跃度。

#点击次数排名在[25000:50000]之间
plt.plot(user_click_item_count[25000:50000])

可以看出点击次数小于等于两次的用户非常的多,这些用户可以认为是非活跃用户

新闻点击次数分析

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次

plt.plot(item_click_count[:20])


点击次数最多的前20篇新闻,点击次数大于2500。思路:可以定义这些新闻为热门新闻, 这个也是简单的处理方式,后面我们也是根据点击次数和时间进行文章热度的一个划分。

plt.plot(item_click_count[3500:])


可以发现很多新闻只被点击过一两次。思路:可以定义这些新闻是冷门新闻

新闻共现频次:两篇新闻连续出现的次数

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()

由统计数据可以看出,平均共现次数2.88,最高为1687。

说明用户看的新闻,相关性是比较强的。

#画个图直观地看一看
x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)

plt.plot(union_item['count'].values[40000:])


大概有70000个pair至少共现一次

新闻文章信息

#不同类型的新闻出现的次数
plt.plot(user_click_merge['category_id'].value_counts().values)

#出现次数比较少的新闻类型, 有些新闻类型,基本上就出现过几次
plt.plot(user_click_merge['category_id'].value_counts().values[150:])

#新闻字数的描述性统计
user_click_merge['words_count'].describe()
'''
count    1.630633e+06
mean     2.043012e+02
std      6.382198e+01
min      0.000000e+00
25%      1.720000e+02
50%      1.970000e+02
75%      2.290000e+02
max      6.690000e+03
Name: words_count, dtype: float64
'''plt.plot(user_click_merge['words_count'].values)

用户点击的新闻类型的偏好

此特征可以用于度量用户的兴趣是否广泛。

plt.plot(sorted(user_click_merge.groupby('user_id')['category_id'].nunique(), reverse=True))

从上图中可以看出有一小部分用户阅读类型是极其广泛的,大部分人都处在20个新闻类型以下。

user_click_merge.groupby('user_id')['category_id'].nunique().reset_index().describe()

用户查看文章的长度的分布

通过统计不同用户点击新闻的平均字数,这个可以反映用户是对长文更感兴趣还是对短文更感兴趣。

plt.plot(sorted(user_click_merge.groupby('user_id')['words_count'].mean(), reverse=True))

从上图中可以发现有一小部分人看的文章平均词数非常高,也有一小部分人看的平均文章次数非常低。

大多数人偏好于阅读字数在200-400字之间的新闻。

#挑出大多数人的区间仔细看看
plt.plot(sorted(user_click_merge.groupby('user_id')['words_count'].mean(), reverse=True)[1000:45000])

可以发现大多数人都是看250字以下的文章

#更加详细的参数
user_click_merge.groupby('user_id')['words_count'].mean().reset_index().describe()

用户点击新闻的时间分析

#为了更好的可视化,这里把时间进行归一化操作
from sklearn.preprocessing import MinMaxScaler
mm = MinMaxScaler()
user_click_merge['click_timestamp'] = mm.fit_transform(user_click_merge[['click_timestamp']])
user_click_merge['created_at_ts'] = mm.fit_transform(user_click_merge[['created_at_ts']])user_click_merge = user_click_merge.sort_values('click_timestamp')user_click_merge.head()

def mean_diff_time_func(df, col):df = pd.DataFrame(df, columns={col})df['time_shift1'] = df[col].shift(1).fillna(0)df['diff_time'] = abs(df[col] - df['time_shift1'])return df['diff_time'].mean()# 点击时间差的平均值
mean_diff_click_time = user_click_merge.groupby('user_id')['click_timestamp', 'created_at_ts'].apply(lambda x: mean_diff_time_func(x, 'click_timestamp'))plt.plot(sorted(mean_diff_click_time.values, reverse=True))


从上图可以发现不同用户点击文章的时间差是有差异的

# 前后点击文章的创建时间差的平均值
mean_diff_created_time = user_click_merge.groupby('user_id')['click_timestamp', 'created_at_ts'].apply(lambda x: mean_diff_time_func(x, 'created_at_ts'))plt.plot(sorted(mean_diff_created_time.values, reverse=True))

从图中可以发现用户先后点击文章,文章的创建时间也是有差异的

# 用户前后点击文章的相似性分布
item_idx_2_rawid_dict = dict(zip(item_emb_df['article_id'], item_emb_df.index))del item_emb_df['article_id']item_emb_np = np.ascontiguousarray(item_emb_df.values, dtype=np.float32)# 随机选择5个用户,查看这些用户前后查看文章的相似性
sub_user_ids = np.random.choice(user_click_merge.user_id.unique(), size=15, replace=False)
sub_user_info = user_click_merge[user_click_merge['user_id'].isin(sub_user_ids)]sub_user_info.head()

def get_item_sim_list(df):sim_list = []item_list = df['click_article_id'].valuesfor i in range(0, len(item_list)-1):emb1 = item_emb_np[item_idx_2_rawid_dict[item_list[i]]]emb2 = item_emb_np[item_idx_2_rawid_dict[item_list[i+1]]]sim_list.append(np.dot(emb1,emb2)/(np.linalg.norm(emb1)*(np.linalg.norm(emb2))))sim_list.append(0)return sim_listfor _, user_df in sub_user_info.groupby('user_id'):item_sim_list = get_item_sim_list(user_df)plt.plot(item_sim_list)

从图中可以看出有些用户前后看的商品的相似度波动比较大,有些波动比较小,也是有一定的区分度的

总结

通过数据分析的过程, 我们目前可以得到以下几点重要的信息, 这个对于我们进行后面的特征制作和分析非常有帮助:

  • 训练集和测试集的用户id没有重复,也就是测试集里面的用户没有模型是没有见过的
  • 训练集中用户最少的点击文章数是2, 而测试集里面用户最少的点击文章数是1
  • 用户对于文章存在重复点击的情况, 但这个都存在于训练集里面
  • 同一用户的点击环境存在不唯一的情况,后面做这部分特征的时候可以采用统计特征
  • 用户点击文章的次数有很大的区分度,后面可以根据这个制作衡量用户活跃度的特征
  • 文章被用户点击的次数也有很大的区分度,后面可以根据这个制作衡量文章热度的特征
  • 用户看的新闻,相关性是比较强的,所以往往我们判断用户是否对某篇文章感兴趣的时候, 在很大程度上会和他历史点击过的文章有关
  • 用户点击的文章字数有比较大的区别, 这个可以反映用户对于文章字数的区别
  • 用户点击过的文章主题也有很大的区别, 这个可以反映用户的主题偏好 10.不同用户点击文章的时间差也会有所区别, 这个可以反映用户对于文章时效性的偏好

所以根据上面的一些分析,可以更好的帮助我们后面做好特征工程, 充分挖掘数据的隐含信息。

天池-新闻推荐-数据分析相关推荐

  1. 天池-新闻推荐-多路召回

    前言读取数据 此次比赛是新闻推荐场景下的用户行为预测挑战赛, 是Datawhale与天池联合举办,该赛题是以新闻APP中的新闻推荐为背景, 目的是要求我们根据用户历史浏览点击新闻文章的数据信息预测用户 ...

  2. 天池-新闻推荐-Baseline

    前言 此次比赛是新闻推荐场景下的用户行为预测挑战赛, 是Datawhale与天池联合举办,该赛题是以新闻APP中的新闻推荐为背景, 目的是要求我们根据用户历史浏览点击新闻文章的数据信息预测用户未来的点 ...

  3. 推荐系统入门(六):新闻推荐实践1(附代码)

    推荐系统入门(六):新闻推荐实践1 目录 推荐系统入门(六):新闻推荐实践1 前言 赛题简介 数据概况 评价方式理解 Baseline 总结 参考资料 前言 相关系列笔记: 推荐系统入门(一):概述 ...

  4. 推荐系统入门(七):新闻推荐实践2(附代码)

    推荐系统入门(七):新闻推荐实践2(附代码) 目录 推荐系统入门(七):新闻推荐实践2(附代码) 引言 数据收集 数据存储 数据分析 实战 总结 参考资料 引言 相关系列笔记: 推荐系统入门(一):概 ...

  5. 【数据挖掘】天池挑战赛 新闻推荐

    比赛网址:https://tianchi.aliyun.com/competition/entrance/531842/introduction 项目源码:Github 一.项目知识点 数据预处理: ...

  6. AI比赛-推荐系统(一)-新闻推荐03:多路召回【用不同策略分别召回部分候选集,然后把候选集混在一起供后续排序模型使用】【①、YoutubeDNN双塔召回;②、基于物品召回;③、基于用户召回】【天池】

    所谓的"多路召回"策略,就是指采用不同的策略.特征或简单模型,分别召回一部分候选集,然后把候选集混合在一起供后续排序模型使用,可以明显的看出,"多路召回策略"是 ...

  7. 零基础入门推荐系统(新闻推荐)

    零基础入门推荐系统(新闻推荐) 比赛介绍 本次新人赛是Datawhale与天池联合发起的零基础入门系列赛事第五场 -- 零基础入门推荐系统之新闻推荐场景下的用户行为预测挑战赛. 赛题简介 此次比赛是新 ...

  8. 基于Python热点新闻关键词数据分析系统

    温馨提示:文末有 CSDN 平台官方提供的博主 Wechat / QQ 名片 :) 1. 项目简介 利用网络爬虫技术从某新闻网站爬取最新的新闻数据,并进行版块分类,对某篇版块下的所有新闻进行中文分词, ...

  9. 【毕设项目】新闻推荐平台功能详解----新闻推荐系统

    系列目录 基于Python网络爬虫与推荐算法新闻推荐平台 新闻推荐平台功能详解----新闻爬虫 新闻推荐平台功能详解----数据分析系统 文章目录 系列目录 功能介绍 一.结构 二.具体实现 1.标签 ...

最新文章

  1. 简单了解音视频传输协议SDP、RTP、RTMP、SIP等
  2. 下面属于javascript内部对象的有_【JavaScript 教程】面向对象编程——this 关键字...
  3. 实战SSM_O2O商铺_03项目结构规划及Maven配置
  4. Magicodes.IE基础教程之导出Pdf
  5. [转载] JAVA笔记_(Day04,Day05)函数数组
  6. 求python一个类与对象的代码_Python基础系列(五)类和对象,让你更懂你的python代码...
  7. 厚积薄发 - 关于runtime的几个问题
  8. mysql字符集修改(ubuntu)
  9. 程序员做外包有前途吗?
  10. 四年STM32研发的工作感悟
  11. Redis数据倾斜与JD开源hotkey源码分析揭秘
  12. DFS实现传教士野人渡河问题
  13. Ubuntu16.04中python升级到3.6版本后Terminal打不开的解决方法
  14. 海量数据处理方法总结 常见大数据题目汇总
  15. Matlab 高光谱影像信息熵/信噪比计算
  16. 居家养老要智能化?阿里云构建民政大脑,引导民政进入智能化时代
  17. linux通过Squid代理上网
  18. Android 如何保存图片
  19. 在excel表格中,如何将一个工作簿中十张工作表的数据统一归整到同一张表上?
  20. 完成新一轮融资估值220亿美元,Citadel证券为何这么会吸金?

热门文章

  1. Java i18n - Java中的国际化
  2. Python3 - 刷博客访问量脚本
  3. C#LeetCode刷题之#190-颠倒二进制位(Reverse Bits)
  4. 面向对象设计原则之7-迪米特法则
  5. aws lambda使用_如何使用AWS Lambda为发布/订阅消息选择最佳事件源
  6. 远程桌面连接一个域网的计算机,怎样远程控制局域网的另一台电脑(远程桌面)win10...
  7. 从面试官问“为什么选择mysql数据库”说开去
  8. 您能解决这3个(看似)简单的Python问题吗?
  9. Python 爬虫是什么
  10. Express-router