【Python】推荐系统入门之数据分析-天池新闻推荐

数据分析

在上一节的内容中,已经使用了ItemCF构建了一个baseline,并得到了一个结果。如果我们需要在baseline的基础上进一步提升,就需要对数据进行进一步的分析。

导入库

python">

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

import re

import warnings

import sys

%matplotlib inline

# 不打印 ignore 级别的消息

warnings.filterwarnings("ignore")

读取数据

data_dir = './data'

# train data

train_user_click_df = pd.read_csv(data_dir+'/train_click_log.csv')

item_df = pd.read_csv(data_dir+'/articles.csv')

item_df = item_df.rename(columns={'article_id': 'click_article_id'}) #重命名,方便后续match

item_emb_df = pd.read_csv(data_dir+'articles_emb.csv')

# test data

test_user_click_df = pd.read_csv(data_dir+'testA_click_log.csv')

数据预处理

对每个用户的点击时间戳进行降序排序,得到排名

train_user_click_df['rank'] = train_user_click_df.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)

test_user_click_df['rank'] = test_user_click_df.groupby(['user_id'])['click_timestamp'].rank(ascending=False).astype(int)

计算用户点击文章的次数,并添加新的一列count

train_user_click_df['click_cnts'] = train_user_click_df.groupby(['user_id'])['click_timestamp'].transform('count')

test_user_click_df['click_cnts'] = test_user_click_df.groupby(['user_id'])['click_timestamp'].transform('count')

数据浏览
用户点击日志文件_训练集

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

train_user_click_df.head()

【Python】推荐系统入门之数据分析-天池新闻推荐

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

1.  user_id: 用户的唯一标识

2. click_article_id: 用户点击的文章唯一标识

3. click_timestamp: 用户点击文章时的时间戳

4. click_environment: 用户点击文章的环境

5. click_deviceGroup: 用户点击文章的设备组

6. click_os: 用户点击文章时的操作系统

7. click_country: 用户点击文章时的所在的国家

8. click_region: 用户点击文章时所在的区域

9. click_referrer_type: 用户点击文章时,文章的来源

#用户点击日志信息

train_user_click_df.info()

【Python】推荐系统入门之数据分析-天池新闻推荐

train_user_click_df.describe()

【Python】推荐系统入门之数据分析-天池新闻推荐

train_user_click_df.user_id.nunique(), train_user_click_df.groupby('user_id')['click_article_id'].count().min()

下面通过直方图来看一下,不同字段的分布

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 = train_user_click_df[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()

【Python】推荐系统入门之数据分析-天池新闻推荐

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

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

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

测试集用户点击日志

test_user_click_df = train_user_click_df.merge(item_df, how='left', on=['click_article_id'])

tst_click.head()

【Python】推荐系统入门之数据分析-天池新闻推荐

test_user_click_df.describe()

【Python】推荐系统入门之数据分析-天池新闻推荐
可以看出训练集和测试集的用户是完全不一样的

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

#测试集中的用户数量为5w

test_user_click_df.user_id.nunique(), test_user_click_df.groupby('user_id')['click_article_id'].count().min()

#新闻文章数据集浏览

item_df.head().append(item_df.tail())

【Python】推荐系统入门之数据分析-天池新闻推荐

item_df['words_count'].value_counts()

【Python】推荐系统入门之数据分析-天池新闻推荐

item_df.shape 

新闻文章embedding向量表示

item_emb_df.head()

【Python】推荐系统入门之数据分析-天池新闻推荐

item_emb_df.shape

数据分析

用户重复点击

# merge

user_click_merge = train_user_click_df.append(test_user_click_df)

#用户重复点击

user_click_count = user_click_merge.groupby(['user_id', 'click_article_id'])['click_timestamp'].agg({'count'}).reset_index()

user_click_count[:10]

【Python】推荐系统入门之数据分析-天池新闻推荐

user_click_count[user_click_count['count']>7]

【Python】推荐系统入门之数据分析-天池新闻推荐

user_click_count['count'].unique()

【Python】推荐系统入门之数据分析-天池新闻推荐

#用户点击新闻次数

user_click_count.loc[:,'count'].value_counts()

【Python】推荐系统入门之数据分析-天池新闻推荐

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

用户点击环境变化分析

def plot_envs(df, cols, r, c):

plt.figure()

plt.figure(figsize=(10, 5))

i = 1

for col in cols:

plt.subplot(r, c, i)

i += 1

v = 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_user_click_df['user_id'].unique(), size=5, 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)

【Python】推荐系统入门之数据分析-天池新闻推荐
【Python】推荐系统入门之数据分析-天池新闻推荐
【Python】推荐系统入门之数据分析-天池新闻推荐
【Python】推荐系统入门之数据分析-天池新闻推荐
【Python】推荐系统入门之数据分析-天池新闻推荐
可以看出绝大多数数的用户的点击环境是比较固定的。思路:可以基于这些环境的统计特征来代表该用户本身的属性

用户点击新闻数量的分布

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

plt.plot(user_click_item_count)

【Python】推荐系统入门之数据分析-天池新闻推荐
可以根据用户的点击文章次数看出用户的活跃度

#点击次数在前50的用户

plt.plot(user_click_item_count[:50])

【Python】推荐系统入门之数据分析-天池新闻推荐

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

#点击次数排名在[25000:50000]之间

plt.plot(user_click_item_count[25000:50000])

【Python】推荐系统入门之数据分析-天池新闻推荐

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

新闻点击次数分析

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

plt.plot(item_click_count)

【Python】推荐系统入门之数据分析-天池新闻推荐

plt.plot(item_click_count[:100])

【Python】推荐系统入门之数据分析-天池新闻推荐

可以看出点击次数最多的前100篇新闻,点击次数大于1000次

plt.plot(item_click_count[:20])

【Python】推荐系统入门之数据分析-天池新闻推荐

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

plt.plot(item_click_count[3500:])

【Python】推荐系统入门之数据分析-天池新闻推荐

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

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

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

【Python】推荐系统入门之数据分析-天池新闻推荐
由统计数据可以看出,平均共现次数2.88,最高为1687。

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

#画个图直观地看一看

x = union_item['click_article_id']

y = union_item['count']

plt.scatter(x, y)

【Python】推荐系统入门之数据分析-天池新闻推荐

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

【Python】推荐系统入门之数据分析-天池新闻推荐
大概有70000个pair至少共现一次。

新闻文章信息

#不同类型的新闻出现的次数

plt.plot(user_click_merge['category_id'].value_counts().values)

【Python】推荐系统入门之数据分析-天池新闻推荐

#出现次数比较少的新闻类型, 有些新闻类型,基本上就出现过几次

plt.plot(user_click_merge['category_id'].value_counts().values[150:])

【Python】推荐系统入门之数据分析-天池新闻推荐

plt.plot(user_click_merge['words_count'].values) 

【Python】推荐系统入门之数据分析-天池新闻推荐

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

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

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

【Python】推荐系统入门之数据分析-天池新闻推荐
从上图中可以看出有一小部分用户阅读类型是极其广泛的,大部分人都处在20个新闻类型以下。

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

【Python】推荐系统入门之数据分析-天池新闻推荐

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

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

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

【Python】推荐系统入门之数据分析-天池新闻推荐
从上图中可以发现有一小部分人看的文章平均词数非常高,也有一小部分人看的平均文章次数非常低。

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

#挑出大多数人的区间仔细看看

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

【Python】推荐系统入门之数据分析-天池新闻推荐
可以发现大多数人都是看250字以下的文章

#更加详细的参数

user_click_merge.groupby('user_id')['words_count'].mean().reset_index().describe()

【Python】推荐系统入门之数据分析-天池新闻推荐

用户点击新闻的时间分析

#为了更好的可视化,这里把时间进行归一化操作

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

【Python】推荐系统入门之数据分析-天池新闻推荐

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

【Python】推荐系统入门之数据分析-天池新闻推荐

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

前后点击文章的创建时间差的平均值

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

【Python】推荐系统入门之数据分析-天池新闻推荐
从图中可以发现用户先后点击文章,文章的创建时间也是有差异的

用户前后点击文章的相似性分布

item_idx_2_rawid_dict = dict(zip(item_emb_df['article_id'], item_emb_df.index))

# 随机选择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()

【Python】推荐系统入门之数据分析-天池新闻推荐

def get_item_sim_list(df):

sim_list = []

item_list = df['click_article_id'].values

for 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_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)

【Python】推荐系统入门之数据分析-天池新闻推荐
从图中可以看出有些用户前后看的商品的相似度波动比较大,有些波动比较小,也是有一定的区分度的。

总结

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

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

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

[1] 天池新闻推荐入门赛之【数据分析】Task02

以上是 【Python】推荐系统入门之数据分析-天池新闻推荐 的全部内容, 来源链接: utcz.com/a/74346.html

回到顶部