一、新闻推荐之数据探索与数据分析

简介: 一、新闻推荐之数据探索与数据分析

导入相关的包

%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/' # 自定义的路径
path='./data_raw/'
trn_click = pd.read_csv(path+'train_click_log.csv')
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()
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
item_df.head()
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
item_emb_df.head()
• 1
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

数据预处理

计算用户点击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.groupby(['user_id'])['click_timestamp'].transform('count')
0          11
1          11
2          11
3          40
4          40
           ..
1112618     4
1112619     2
1112620     2
1112621    14
1112622    14
Name: click_timestamp, Length: 1112623, dtype: int64
trn_click.groupby(['user_id'])['click_timestamp'].agg('count')
user_id
0          2
1          2
2          2
3          2
4          2
          ..
199995     7
199996    13
199997     2
199998    40
199999    11
Name: click_timestamp, Length: 200000, dtype: int64
trn_click = trn_click.merge(item_df, how='left', on=['click_article_id'])
trn_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

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()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1112623 entries, 0 to 1112622
Data columns (total 14 columns):
user_id                1112623 non-null int64
click_article_id       1112623 non-null int64
click_timestamp        1112623 non-null int64
click_environment      1112623 non-null int64
click_deviceGroup      1112623 non-null int64
click_os               1112623 non-null int64
click_country          1112623 non-null int64
click_region           1112623 non-null int64
click_referrer_type    1112623 non-null int64
rank                   1112623 non-null int32
click_cnts             1112623 non-null int64
category_id            1112623 non-null int64
created_at_ts          1112623 non-null int64
words_count            1112623 non-null int64
dtypes: int32(1), int64(13)
memory usage: 123.1 MB
trn_click.describe([0.01,0.25,0.5,0.75,0.99])
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
count 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06 1.112623e+06
mean 1.221198e+05 1.951541e+05 1.507588e+12 3.947786e+00 1.815981e+00 1.301976e+01 1.310776e+00 1.813587e+01 1.910063e+00 7.118518e+00 1.323704e+01 3.056176e+02 1.506598e+12 2.011981e+02
std 5.540349e+04 9.292286e+04 3.363466e+08 3.276715e-01 1.035170e+00 6.967844e+00 1.618264e+00 7.105832e+00 1.220012e+00 1.016095e+01 1.631503e+01 1.155791e+02 8.343066e+09 5.223881e+01
min 0.000000e+00 3.000000e+00 1.507030e+12 1.000000e+00 1.000000e+00 2.000000e+00 1.000000e+00 1.000000e+00 1.000000e+00 1.000000e+00 2.000000e+00 1.000000e+00 1.166573e+12 0.000000e+00
1% 4.502000e+03 1.520900e+04 1.507039e+12 2.000000e+00 1.000000e+00 2.000000e+00 1.000000e+00 3.000000e+00 1.000000e+00 1.000000e+00 2.000000e+00 7.000000e+00 1.476077e+12 9.700000e+01
25% 7.934700e+04 1.239090e+05 1.507297e+12 4.000000e+00 1.000000e+00 2.000000e+00 1.000000e+00 1.300000e+01 1.000000e+00 2.000000e+00 4.000000e+00 2.500000e+02 1.507220e+12 1.700000e+02
50% 1.309670e+05 2.038900e+05 1.507596e+12 4.000000e+00 1.000000e+00 1.700000e+01 1.000000e+00 2.100000e+01 2.000000e+00 4.000000e+00 8.000000e+00 3.280000e+02 1.507553e+12 1.970000e+02
75% 1.704010e+05 2.777120e+05 1.507841e+12 4.000000e+00 3.000000e+00 1.700000e+01 1.000000e+00 2.500000e+01 2.000000e+00 8.000000e+00 1.600000e+01 4.100000e+02 1.507756e+12 2.280000e+02
99% 1.990788e+05 3.540860e+05 1.508197e+12 4.000000e+00 4.000000e+00 2.000000e+01 1.000000e+01 2.800000e+01 7.000000e+00 4.900000e+01 8.000000e+01 4.420000e+02 1.508171e+12 3.180000e+02
max 1.999990e+05 3.640460e+05 1.510603e+12 4.000000e+00 5.000000e+00 2.000000e+01 1.100000e+01 2.800000e+01 7.000000e+00 2.410000e+02 2.410000e+02 4.600000e+02 1.510666e+12 6.690000e+03
trn_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
columns=trn_click.columns.to_list()
len(columns)
14
fig=plt.figure(figsize=(80,60))
for i in range(14):
    plt.subplot(4,4,i+1)
    sns.boxplot(trn_click[columns[i]],orient='v',width=0.5)
    plt.ylabel(columns[i],fontsize=36)
plt.show()
#训练集中的用户数量为20w
trn_click["user_id"].nunique()
200000
trn_click.groupby('user_id')['click_article_id'].count().min()
# 训练集里面每个用户至少点击了两篇文章
2
trn_click.groupby('user_id')['click_article_id'].count()
user_id
0          2
1          2
2          2
3          2
4          2
          ..
199995     7
199996    13
199997     2
199998    40
199999    11
Name: click_article_id, Length: 200000, dtype: int64
trn_click['click_article_id'].value_counts().reset_index()[:10]
index click_article_id
0 234698 11886
1 123909 11438
2 336221 11290
3 96210 11146
4 183176 10487
5 336223 10186
6 168623 9882
7 331116 9369
8 336245 7851
9 124749 7264
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()
<Figure size 432x288 with 0 Axes>

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

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

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

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

tst_click = tst_click.merge(item_df, how='left', on=['click_article_id'])
tst_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
tst_click.describe([0.01,0.25,0.5,0.75,0.99]).T
count mean std min 1% 25% 50% 75% 99% max
user_id 518010.0 2.273424e+05 1.461391e+04 2.000000e+05 2.004640e+05 2.149260e+05 2.291090e+05 2.401820e+05 2.495860e+05 2.499990e+05
click_article_id 518010.0 1.938038e+05 8.827939e+04 1.370000e+02 1.612900e+04 1.285510e+05 1.991970e+05 2.721430e+05 3.536720e+05 3.640430e+05
click_timestamp 518010.0 1.507387e+12 3.706127e+08 1.506959e+12 1.506961e+12 1.507026e+12 1.507308e+12 1.507666e+12 1.508184e+12 1.508832e+12
click_environment 518010.0 3.947300e+00 3.239161e-01 1.000000e+00 2.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00 4.000000e+00
click_deviceGroup 518010.0 1.738285e+00 1.020858e+00 1.000000e+00 1.000000e+00 1.000000e+00 1.000000e+00 3.000000e+00 4.000000e+00 5.000000e+00
click_os 518010.0 1.362847e+01 6.625564e+00 2.000000e+00 2.000000e+00 1.200000e+01 1.700000e+01 1.700000e+01 2.000000e+01 2.000000e+01
click_country 518010.0 1.348209e+00 1.703524e+00 1.000000e+00 1.000000e+00 1.000000e+00 1.000000e+00 1.000000e+00 1.000000e+01 1.100000e+01
click_region 518010.0 1.825025e+01 7.060798e+00 1.000000e+00 4.000000e+00 1.300000e+01 2.100000e+01 2.500000e+01 2.800000e+01 2.800000e+01
click_referrer_type 518010.0 1.819614e+00 1.082657e+00 1.000000e+00 1.000000e+00 1.000000e+00 2.000000e+00 2.000000e+00 7.000000e+00 7.000000e+00
rank 518010.0 1.552179e+01 3.395770e+01 1.000000e+00 1.000000e+00 4.000000e+00 8.000000e+00 1.800000e+01 1.000000e+02 9.380000e+02
click_cnts 518010.0 3.004359e+01 5.686802e+01 1.000000e+00 1.000000e+00 1.000000e+01 1.900000e+01 3.500000e+01 1.630000e+02 9.380000e+02
category_id 518010.0 3.053250e+02 1.104115e+02 1.000000e+00 7.000000e+00 2.520000e+02 3.230000e+02 3.990000e+02 4.420000e+02 4.600000e+02
created_at_ts 518010.0 1.506883e+12 5.816668e+09 1.265812e+12 1.501765e+12 1.506970e+12 1.507249e+12 1.507630e+12 1.508156e+12 1.509949e+12
words_count 518010.0 2.109663e+02 8.304006e+01 0.000000e+00 1.140000e+02 1.760000e+02 1.990000e+02 2.320000e+02 8.580000e+02 3.082000e+03
#测试集中的用户数量为5w
tst_click.user_id.nunique()
50000
tst_click.groupby('user_id')['click_article_id'].count().min()
# 注意测试集里面有只点击过一次文章的用户
1

新闻文章信息数据表¶

#新闻文章数据集浏览
item_df.head().append(item_df.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
item_df['words_count'].value_counts()
176     3485
182     3480
179     3463
178     3458
174     3456
        ... 
845        1
710        1
965        1
847        1
1535       1
Name: words_count, Length: 866, dtype: int64
print(item_df['category_id'].nunique())     # 461个文章主题
item_df['category_id'].hist()
461
<matplotlib.axes._subplots.AxesSubplot at 0x21fb84d4248>

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

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

新闻文章embedding向量表示¶

item_emb_df.head()
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

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_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[user_click_count['count']>7]
user_id click_article_id count
311242 86295 74254 10
311243 86295 76268 10
393761 103237 205948 10
393763 103237 235689 10
576902 134850 69463 13
user_click_count['count'].unique()
array([ 1,  2,  4,  3,  6,  5, 10,  7, 13], dtype=int64)
#用户点击新闻次数
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 = 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(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)
<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

<Figure size 432x288 with 0 Axes>

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

user_click_item_count = sorted(user_click_merge.groupby('user_id')['click_article_id'].count(), reverse=True)
plt.plot(user_click_item_count)
[<matplotlib.lines.Line2D at 0x21fc0b4e3c8>]

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

#点击次数在前50的用户
plt.plot(user_click_item_count[:50])
[<matplotlib.lines.Line2D at 0x21fc0b15308>]

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

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

#点击次数排名在[25000:50000]之间
plt.plot(user_click_item_count[25000:50000])
[<matplotlib.lines.Line2D at 0x21fc0ae2f48>]

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

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

新闻点击次数分析

item_click_count = sorted(user_click_merge.groupby('click_article_id')['user_id'].count(), reverse=True)
plt.plot(item_click_count)
[<matplotlib.lines.Line2D at 0x21f0f68a9c8>]

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

plt.plot(item_click_count[:100])
[<matplotlib.lines.Line2D at 0x21f0f716948>]

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

plt.plot(item_click_count[:20])
[<matplotlib.lines.Line2D at 0x21f0f620d08>]

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

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

plt.plot(item_click_count[3500:])
[<matplotlib.lines.Line2D at 0x21f9be4a988>]

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

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

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

将以用户分组的文章id向上移动一位表示为下一条推荐的文章,shift函数(-1)

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()
count
count 433597.000000
mean 3.184139
std 18.851753
min 1.000000
25% 1.000000
50% 1.000000
75% 2.000000
max 2202.000000
#由统计数据可以看出,平均共现次数2.88,最高为1687。
#说明用户看的新闻,相关性是比较强的。
#画个图直观地看一看
x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x21f0fedad88>

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

plt.plot(union_item['count'].values[40000:])
[<matplotlib.lines.Line2D at 0x21f0ff1eb08>]

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

新闻文章信息¶

#不同类型的新闻出现的次数
plt.plot(user_click_merge['category_id'].value_counts().values)
[<matplotlib.lines.Line2D at 0x21f0dda5808>]

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

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

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

#新闻字数的描述性统计
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)
[<matplotlib.lines.Line2D at 0x21f5ad068c8>]

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

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

plt.plot(sorted(user_click_merge.groupby('user_id')['category_id'].nunique(), reverse=True))
[<matplotlib.lines.Line2D at 0x21f5ad08708>]

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

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

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

plt.plot(sorted(user_click_merge.groupby('user_id')['words_count'].mean(), reverse=True))
[<matplotlib.lines.Line2D at 0x21fb99c5b88>]

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

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

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

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

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

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

#更加详细的参数
user_click_merge.groupby('user_id')['words_count'].mean().reset_index().describe()
user_id words_count
count 250000.000000 250000.000000
mean 124999.500000 205.830189
std 72168.927986 47.174030
min 0.000000 8.000000
25% 62499.750000 187.500000
50% 124999.500000 202.000000
75% 187499.250000 217.750000
max 249999.000000 3434.500000

用户点击新闻的时间分析¶

#为了更好的可视化,这里把时间进行归一化操作
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()
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 = 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'].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)

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

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

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

最后本文如有错误,望联系本人会立马改正。本人是使用jupyter编写代码部分上传,可以直接下载。 另外本文可能太长给 您带来不便,望理解。

相关文章
|
2天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1517 4
|
29天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
5天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
492 19
|
2天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
179 1
|
8天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
9天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
448 5
|
7天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
313 2
|
23天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
25天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2608 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析