零基础入门推荐系统 - 新闻推荐-Task2 (DataWhale学习小组)

数据探索性分析

加载需要的module

%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)
plt.rcParams['font.family'] = ['PingFang HK'] import os,gc,re,warnings,sys
warnings.filterwarnings("ignore")

导入数据并查看

articles = pd.read_csv('articles.csv')
articles = articles.rename(columns={'article_id':'click_article_id'})
print(articles.shape)
articles.head()
(364047, 4)
click_article_id category_id created_at_ts words_count
0 0 0 1513144419000 168
1 1 1 1405341936000 189
2 2 1 1408667706000 250
3 3 1 1408468313000 230
4 4 1 1407071171000 162
text_emb = pd.read_csv('articles_emb.csv')
print(text_emb.shape)
text_emb.head()
(364047, 251)
article_id emb_0 emb_1 emb_2 emb_3 emb_4 emb_5 emb_6 emb_7 emb_8 ... emb_240 emb_241 emb_242 emb_243 emb_244 emb_245 emb_246 emb_247 emb_248 emb_249
0 0 -0.161183 -0.957233 -0.137944 0.050855 0.830055 0.901365 -0.335148 -0.559561 -0.500603 ... 0.321248 0.313999 0.636412 0.169179 0.540524 -0.813182 0.286870 -0.231686 0.597416 0.409623
1 1 -0.523216 -0.974058 0.738608 0.155234 0.626294 0.485297 -0.715657 -0.897996 -0.359747 ... -0.487843 0.823124 0.412688 -0.338654 0.320786 0.588643 -0.594137 0.182828 0.397090 -0.834364
2 2 -0.619619 -0.972960 -0.207360 -0.128861 0.044748 -0.387535 -0.730477 -0.066126 -0.754899 ... 0.454756 0.473184 0.377866 -0.863887 -0.383365 0.137721 -0.810877 -0.447580 0.805932 -0.285284
3 3 -0.740843 -0.975749 0.391698 0.641738 -0.268645 0.191745 -0.825593 -0.710591 -0.040099 ... 0.271535 0.036040 0.480029 -0.763173 0.022627 0.565165 -0.910286 -0.537838 0.243541 -0.885329
4 4 -0.279052 -0.972315 0.685374 0.113056 0.238315 0.271913 -0.568816 0.341194 -0.600554 ... 0.238286 0.809268 0.427521 -0.615932 -0.503697 0.614450 -0.917760 -0.424061 0.185484 -0.580292

5 rows × 251 columns

train_click = pd.read_csv('train_click_log.csv')
print(train_click.shape)
train_click.head()
(1112623, 9)
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type
0 199999 160417 1507029570190 4 1 17 1 13 1
1 199999 5408 1507029571478 4 1 17 1 13 1
2 199999 50823 1507029601478 4 1 17 1 13 1
3 199998 157770 1507029532200 4 1 17 1 25 5
4 199998 96613 1507029671831 4 1 17 1 25 5
test_click = pd.read_csv('testA_click_log.csv')
print(test_click.shape)
test_click.head()
(518010, 9)
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type
0 249999 160974 1506959142820 4 1 17 1 13 2
1 249999 160417 1506959172820 4 1 17 1 13 2
2 249998 160974 1506959056066 4 1 12 1 13 2
3 249998 202557 1506959086066 4 1 12 1 13 2
4 249997 183665 1506959088613 4 1 17 1 15 5

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

user_id: 用户的唯一标识
click_article_id: 用户点击的文章唯一标识
click_timestamp: 用户点击文章时的时间戳
click_environment: 用户点击文章的环境
click_deviceGroup: 用户点击文章的设备组
click_os: 用户点击文章时的操作系统
click_country: 用户点击文章时的所在的国家
click_region: 用户点击文章时所在的区域
click_referrer_type: 用户点击文章时,文章的来源

数据预处理:增加新变量

  • 计算用户点击rank和点击次数
# 对每个用户的点击时间戳进行排序
train_click['rank'] = train_click.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)
test_click['rank'] = test_click.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)#计算用户点击文章的次数,并添加新的一列count
train_click['click_cnts'] = train_click.groupby(['user_id'])['click_timestamp'].transform('count')
test_click['click_cnts'] = test_click.groupby(['user_id'])['click_timestamp'].transform('count')
  • 结合article查看数据
train_click = train_click.merge(articles, how='left', on=['click_article_id'])
train_click.head()
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type rank click_cnts category_id created_at_ts words_count
0 199999 160417 1507029570190 4 1 17 1 13 1 11 11 281 1506942089000 173
1 199999 5408 1507029571478 4 1 17 1 13 1 10 11 4 1506994257000 118
2 199999 50823 1507029601478 4 1 17 1 13 1 9 11 99 1507013614000 213
3 199998 157770 1507029532200 4 1 17 1 25 5 40 40 281 1506983935000 201
4 199998 96613 1507029671831 4 1 17 1 25 5 39 40 209 1506938444000 185
# 结合articles
test_click = test_click.merge(articles, how='left', on=['click_article_id'])
test_click.head()
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type rank click_cnts category_id created_at_ts words_count
0 249999 160974 1506959142820 4 1 17 1 13 2 19 19 281 1506912747000 259
1 249999 160417 1506959172820 4 1 17 1 13 2 18 19 281 1506942089000 173
2 249998 160974 1506959056066 4 1 12 1 13 2 5 5 281 1506912747000 259
3 249998 202557 1506959086066 4 1 12 1 13 2 4 5 327 1506938401000 219
4 249997 183665 1506959088613 4 1 17 1 15 5 7 7 301 1500895686000 256
# 确认用户数
print('train:',train_click.user_id.nunique())
print('test:',test_click.user_id.nunique())
train: 200000
test: 50000
# 用户查看文章数
user_articles = train_click.groupby('user_id')['click_article_id'].count()
print(user_articles.nlargest(5))
print(user_articles.nsmallest(5))
user_id
185083    241
143986    212
193264    180
150481    175
179488    175
Name: click_article_id, dtype: int64
user_id
0    2
1    2
2    2
3    2
4    2
Name: click_article_id, dtype: int64
# 用户查看文章数
user_articles_test = test_click.groupby('user_id')['click_article_id'].count()
print(user_articles_test.nlargest(5))
print(user_articles_test.nsmallest(5))
user_id
249322    938
242546    782
239302    361
245163    326
240519    259
Name: click_article_id, dtype: int64
user_id
200001    1
200009    1
200010    1
200014    1
200026    1
Name: click_article_id, dtype: int64

数据浏览

  • 查看各个特征的值的分布
train_click.columns
Index(['user_id', 'click_article_id', 'click_timestamp', 'click_environment','click_deviceGroup', 'click_os', 'click_country', 'click_region','click_referrer_type', 'rank', 'click_cnts', 'category_id','created_at_ts', 'words_count'],dtype='object')
cols = ['click_article_id', 'click_timestamp', 'click_environment', 'click_deviceGroup', 'click_os', 'click_country', 'click_region', 'click_referrer_type', 'rank', 'click_cnts']
#plt.rcParams['font.family'] = ['PingFang HK']
plt.figure()
plt.figure(figsize=(15, 20))
i = 1
for col in cols:plot_envs = plt.subplot(5, 2, i)i += 1v = train_click[col].value_counts().nlargest(10).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()
findfont: Font family ['PingFang HK'] not found. Falling back to DejaVu Sans.
findfont: Font family ['PingFang HK'] not found. Falling back to DejaVu Sans.<Figure size 432x288 with 0 Axes>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZtEM8BsT-1606490162867)(output_46_2.png)]

  • 比较明显的可以看出:

    • click_enviroment主要是4
    • click_device_group主要是1,3
    • click_os主要是2,17,20
    • click_country主要是1

探索新闻文件 articles.csv

articles.head().append(articles.tail())
click_article_id category_id created_at_ts words_count
0 0 0 1513144419000 168
1 1 1 1405341936000 189
2 2 1 1408667706000 250
3 3 1 1408468313000 230
4 4 1 1407071171000 162
364042 364042 460 1434034118000 144
364043 364043 460 1434148472000 463
364044 364044 460 1457974279000 177
364045 364045 460 1515964737000 126
364046 364046 460 1505811330000 479
# 查看新闻词数
plt.plot(all_click['words_count'].values)

# 查看新闻词数的出现频率
articles.words_count.value_counts().plot()

  • x轴显示词数,y轴显示文章数。可以看出大部分文章的词数都在500以内
# 查看新闻类别
print(articles['category_id'].nunique())
articles['category_id'].hist()

数据探索性分析

  • 关于用户重复点击率
# 首先合并训练集和测试集
all_click = train_click.append(test_click)
#用户重复点击
user_click_count = all_click.groupby(['user_id', 'click_article_id'])['click_timestamp'].agg({'count'}).reset_index()
user_click_count[:10]
user_id click_article_id count
0 0 30760 1
1 0 157507 1
2 1 63746 1
3 1 289197 1
4 2 36162 1
5 2 168401 1
6 3 36162 1
7 3 50644 1
8 4 39894 1
9 4 42567 1
# 重复点击的可能次数
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
  • 大部分用户对同一篇新闻不会重复浏览,重复点击文章的用户很少,可以作为一个新的特征

  • 关于用户点击时的环境

# 构造一个绘图函数
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(test_click['user_id'].unique(), size=15, replace=False)
sample_users = all_click[all_click['user_id'].isin(sample_user_ids)]
en_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, en_cols, 2, 3)















  • 大部分的环境因素表现出稳定,只有referer会出现少量变动 可以通过环境因素的特点来构造关于用户的新特征

  • 用户点击新闻数量的分布

user_click_item_count = sorted(all_click.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])## 既然有了活跃用户,可不可以用相同的方法找出非活跃用户呢?

  • 新闻点击次数分析(之前可以认为是user-item,这里是item-user)
# 每篇新闻被点击的次数
item_click_count = sorted(all_click.groupby('click_article_id')['user_id'].count(), reverse=True)
plt.plot(item_click_count)

plt.plot(item_click_count[:100])
## 同上定义热门文章

plt.plot(item_click_count[:20])

tmp = all_click.sort_values('click_timestamp')
# shift用于数据的上下移动,shift(-1)表示这一列上该数据点的下一个
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)
tmp.head()
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type rank click_cnts category_id created_at_ts words_count next_item
18 249990 162300 1506959050386 4 3 20 1 25 2 5 5 281 1506945129000 193 160974.0
2 249998 160974 1506959056066 4 1 12 1 13 2 5 5 281 1506912747000 259 202557.0
30 249985 160974 1506959062960 4 1 17 1 8 2 8 8 281 1506912747000 259 160417.0
50 249979 162300 1506959063933 4 1 17 1 25 2 2 2 281 1506945129000 193 16129.0
25 249988 160974 1506959064384 4 1 17 1 21 2 17 17 281 1506912747000 259 300470.0
print(union_item['count'].value_counts().nlargest(10))
union_item['count'].describe()
1     315411
2      49151
3      20504
4      11036
5       6978
6       4813
7       3417
8       2581
9       2087
10      1748
Name: count, dtype: int64count    433597.000000
mean          3.184139
std          18.851753
min           1.000000
25%           1.000000
50%           1.000000
75%           2.000000
max        2202.000000
Name: count, dtype: float64
  • 由统计数据可以看出,有不少用户看新闻的上下相关性是比较强的。
#画个图直观地看一看
x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)

用户对新闻的偏好探索

  • 用户点击的新闻类型
plt.plot(sorted(all_click.groupby('user_id')['category_id'].nunique(), reverse=True))
[<matplotlib.lines.Line2D at 0x7f83c09750f0>]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nO9GGKMp-1606490162886)(output_81_1.png)]

print(all_click.groupby('user_id')['category_id'].nunique().reset_index()['category_id'].value_counts().nlargest(10))
all_click.groupby('user_id')['category_id'].nunique().reset_index()['category_id'].describe()
2     77921
1     32474
3     29946
4     26958
5     17650
6     13557
7     10333
8      8050
9      6260
10     4959
Name: category_id, dtype: int64count    250000.000000
mean          4.573188
std           4.419800
min           1.000000
25%           2.000000
50%           3.000000
75%           6.000000
max          95.000000
Name: category_id, dtype: float64
  • 用户点击的新闻长度
plt.plot(sorted(all_click.groupby('user_id')['words_count'].mean(), reverse=True))

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

#更加详细的参数
print(all_click.groupby('user_id')['words_count'].mean().reset_index()['words_count'].nlargest(10))
all_click.groupby('user_id')['words_count'].mean().reset_index()['words_count'].describe()
45586     3434.500000
240259    2743.000000
67219     1493.500000
51322     1479.000000
89119     1453.000000
207664    1421.000000
42731     1204.666667
221983    1194.666667
88709     1089.000000
212161    1044.000000
Name: words_count, dtype: float64count    250000.000000
mean        205.830189
std          47.174030
min           8.000000
25%         187.500000
50%         202.000000
75%         217.750000
max        3434.500000
Name: words_count, dtype: float64
  • 用户点击新闻的时间分析
#为了更好的可视化,这里把时间进行归一化操作
from sklearn.preprocessing import MinMaxScaler
mm = MinMaxScaler()
all_click['click_timestamp'] = mm.fit_transform(all_click[['click_timestamp']])
all_click['created_at_ts'] = mm.fit_transform(all_click[['created_at_ts']])all_click = all_click.sort_values('click_timestamp')all_click.head()
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type rank click_cnts category_id created_at_ts words_count
18 249990 162300 0.000000 4 3 20 1 25 2 5 5 281 0.989186 193
2 249998 160974 0.000002 4 1 12 1 13 2 5 5 281 0.989092 259
30 249985 160974 0.000003 4 1 17 1 8 2 8 8 281 0.989092 259
50 249979 162300 0.000004 4 1 17 1 25 2 2 2 281 0.989186 193
25 249988 160974 0.000004 4 1 17 1 21 2 17 17 281 0.989092 259
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 = all_click.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))

# 用户前后点击文章的相似性分布
item_idx_2_rawid_dict = dict(zip(text_emb['article_id'], text_emb.index))
del text_emb['article_id']
text_emb = np.ascontiguousarray(text_emb.values, dtype=np.float32)
# 随机选择5个用户,查看这些用户前后查看文章的相似性
sub_user_ids = np.random.choice(all_click.user_id.unique(), size=15, replace=False)
sub_user_info = all_click[all_click['user_id'].isin(sub_user_ids)]sub_user_info.head()
user_id click_article_id click_timestamp click_environment click_deviceGroup click_os click_country click_region click_referrer_type rank click_cnts category_id created_at_ts words_count
5674 247664 160974 0.000465 4 1 17 1 8 2 1 1 281 0.989092 259
22621 240940 160974 0.001886 4 1 17 1 25 2 5 5 281 0.989092 259
22622 240940 156808 0.001894 4 1 17 1 25 2 4 5 281 0.989155 227
34033 236697 225055 0.002968 4 1 17 1 21 2 17 17 354 0.989211 245
34034 236697 160974 0.003067 4 1 17 1 21 2 16 17 281 0.989092 259
def get_item_sim_list(df):sim_list = []item_list = df['click_article_id'].valuesfor i in range(0, len(item_list)-1):emb1 = text_emb[item_idx_2_rawid_dict[item_list[i]]]emb2 = text_emb[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_list
for _, user_df in sub_user_info.groupby('user_id'):item_sim_list = get_item_sim_list(user_df)plt.plot(item_sim_list)

零基础入门推荐系统 - 新闻推荐-Task2 (DataWhale学习小组)相关推荐

  1. 零基础入门推荐系统 - 新闻推荐实战-笔记四

    零基础入门推荐系统 - 新闻推荐实战-笔记四-特征工程 什么是特征工程 本次特征工程内容 已有特征 特征构造 负采样 什么是特征工程 工业界名言:数据和特征决定了机器学习的上限,而模型和算法只是逼近这 ...

  2. 零基础入门推荐系统 - 新闻推荐(一)

    赛题地址 背景: 随着信息技术和互联网的发展,人们逐渐从信息匮乏的时代走入了信息过载(information overload)的时代.在这个时代,无论是信息消费者还是信息生产者都遇到了很大的挑战:作 ...

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

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

  4. 基于hadoop的商品推荐系统_[零基础入门推荐系统(1)]基于用户和基于物品的协同过滤方法(python代码实现)...

    1. 前言: 为什么会有该系列? 最近,打算写<零基础入门推荐系统>系列,为了系统地介绍推荐系统知识,以及加强基础的实践能力. 该系列将结合一些书籍,比如项亮的<推荐系统实践> ...

  5. Task01——零基础入门NLP - 新闻文本分类之赛题理解

    本篇目标 首先本篇文章会对赛题进行介绍以及个人对赛题的理解,带大家接触NLP的预处理.模型构建和模型训练等知识点. 赛题介绍 赛题名称:零基础入门NLP - 新闻文本分类 赛题任务:赛题以自然语言处理 ...

  6. 零基础入门NLP - 新闻文本分类

    本文是对阿里云新人竞赛中的"零基础入门NLP - 新闻文本分类"解体过程进行的记录,目前仅使用了textCNN模型进行预测,后续还会考虑使用LSTM进行对比. 赛题数据 赛题以新闻 ...

  7. 零基础入门NLP - 新闻文本分类,正式赛第一名方案分享

    零基础入门NLP - 新闻文本分类,正式赛第一名方案分享:https://mp.weixin.qq.com/s/7WpZUqdlItBToLYuRLm44g

  8. 【初学者入门】零基础入门NLP - 新闻文本分类

    序言 从今天开始入门学习NLP,虽然有点晚,但是我觉得任何时候都值得开始,尤其是面对你去感兴趣的事情.今天的任务是 [零基础入门NLP - 新闻文本分类],这是天池大赛中的入门级算法比赛,入口链接请自 ...

  9. 天池零基础入门NLP - 新闻文本分类Top1方案的bert4torch复现

    天池有些长期比赛可以练习玩玩(还可以继续提交),于是试了下简单的新闻文本分类任务,Top1的解决方案思路是"预训练+fgm+交叉验证模型融合",代码是基于bert4keras的,本 ...

最新文章

  1. 【洛谷p1313】计算系数
  2. 让AI有道德!用AI的方式去发展AI
  3. e.getMessage 为空NULL
  4. 解决在非spring上下文的环境中无法获取Spring容器的bean【nullpointer:connot invoke because xxx is null问题】
  5. Spark:使用partitionColumn选项读取数据库原理
  6. 当前版本与卡刷包android_Z2 Android 6.0.1卡刷包 23.5.0.486发布,快刷起来!(来自XDA)...
  7. jq事件不自执行方法
  8. matlab分析xml文件_修改Java中的XML文件(DOM分析器)
  9. TensorFlow入门(2)矩阵基础
  10. z-buffer的概念和算法
  11. 冰蝎工具的最新检测特征
  12. keras上运行Tensorflow-gpu的艰难历程(最新版,更新中)
  13. STM32——CAN通信实验
  14. java8 利用reduce实现将列表中的多个元素的属性求和并返回
  15. 什么无线蓝牙耳机延迟低?延迟低的无线蓝牙耳机推荐
  16. 数字语音信号处理学习笔记——语音信号的数字模型(1)
  17. 【网络技术题库梳理8】网络系统结构与设计的基本原则
  18. idea中设置jdk
  19. Android 数据库知识回顾
  20. python 常用转义字符对照表 键盘各键对应的ASCII码值

热门文章

  1. 小学生心理测试软件,小学生趣味心理测试:性格测试
  2. access百度翻译 get_php百度翻译类
  3. 表演动画中的动作捕捉技术的应用
  4. C++STL面试详解
  5. 网易云易盾关于极验所述问题的致歉和说明
  6. C++bellman算法
  7. VC-VQA: Visual Calibration Mechanism for Visual Question Answering (VQA的视觉校准机制)
  8. bash中正确处理文件或路径名中的空格
  9. STM32——DHT11温湿度传感器
  10. 68 SpringBoot