文章目录

赛题背景

Task1:比赛报名与数据读取

  • 比赛报名
  • 数据读取
  • 数据查看
  • Task2:比赛数据分析
  • 预处理
  • 数据浏览
  • 用户点击日志文件
  • 新闻文章信息表
  • 新闻文章embedding向量表示表
  • 数据分析
  • 用户国家和地区分布
  • 用户点击文章数
  • 用户重复点击
  • 用户点击环境变化
  • 用户点击文章的次数
  • 用户点击新闻类型偏好
  • 用户点击文章的长度
  • 新闻文章点击的次数
  • 用户行为时间戳分析
  • 新闻共现频次
  • 新闻文章信息
  • 文章嵌入向量
  • 总结

赛题背景

赛题地址:https://tianchi.aliyun.com/competition/entrance/531842/information 赛题以预测用户未来点击新闻文章为任务,数据集报名后可见并可下载,该数据来自某新闻APP平台的用户交互数据,包括30万用户,近300万次点击,共36万多篇不同的新闻文章,同时每篇新闻文章有对应的embedding向量表示。为了保证比赛的公平性,将会从中抽取20万用户的点击日志数据作为训练集,5万用户的点击日志数据作为测试集A,5万用户的点击日志数据作为测试集B。

Task1:比赛报名与数据读取

比赛报名

python新闻联播数据分析_python

数据读取

# 原始读入时间
time_start = time.time()
articles = pd.read_csv('articles.csv')
articles_emb = pd.read_csv('articles_emb.csv')

train_click = pd.read_csv('train_click_log.csv')
test_click = pd.read_csv('testA_click_log.csv')

print('load time: ',time.time() - time_start)

python新闻联播数据分析_python新闻联播数据分析_02

由于数据量比较大,读取占用内存和时间都比较多,考虑对其进行优化。

优化代码:

# 优化内存
def reduce_mem(df):
    start_mem = df.memory_usage().sum() / 1024 ** 2
    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))

    ## Reference from: https://www.kaggle.com/arjanso/reducing-dataframe-memory-size-by-65
    for col in df.columns:
        col_type = df[col].dtype
        if col_type != object:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
        else:

            df[col] = df[col].astype('category')

    end_mem = df.memory_usage().sum() / 1024 ** 2
    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))

    return df

看下优化后内存占用:

articles = reduce_mem(articles)
articles_emb = reduce_mem(articles_emb)

train_click = reduce_mem(train_click)
test_click = reduce_mem(test_click)

python新闻联播数据分析_python_03

可见节省了很多内存。我们把它存储下来以便以后使用,这里使用hdf5存储。

# 保存数据以免每次都重新读取
data_store_1 = pd.HDFStore('articles.h5')
# Store object in HDFStore
data_store_1.put('preprocessed_df', articles, format='table')
data_store_1.close()

data_store_2 = pd.HDFStore('articles_emb.h5')
# Store object in HDFStore
data_store_2.put('preprocessed_df', articles_emb, format='table')
data_store_2.close()

data_store_3 = pd.HDFStore('train_click.h5')
# Store object in HDFStore
data_store_3.put('preprocessed_df', train_click, format='table')
data_store_3.close()

data_store_4 = pd.HDFStore('test_click.h5')
# Store object in HDFStore
data_store_4.put('preprocessed_df', test_click, format='table')
data_store_4.close()

测试一下读取优化后数据的速度:

# 读取优化数据时间
time_start = time.time()
store_data = pd.HDFStore('articles.h5')
# 通过key获取数据
articles = store_data['preprocessed_df']
store_data.close()

store_data = pd.HDFStore('articles_emb.h5')
# 通过key获取数据
articles_emb = store_data['preprocessed_df']
store_data.close()

store_data = pd.HDFStore('train_click.h5')
# 通过key获取数据
train_click = store_data['preprocessed_df']
store_data.close()

store_data = pd.HDFStore('test_click.h5')
# 通过key获取数据
test_click = store_data['preprocessed_df']
store_data.close()


print('load time:',time.time() - time_start)

python新闻联播数据分析_数据挖掘_04

比原来快了很多。

数据查看

articles.describe()
articles_emb.describe()
train_click.describe()
test_click.describe()

python新闻联播数据分析_数据挖掘_05

python新闻联播数据分析_pandas_06

python新闻联播数据分析_pandas_07

python新闻联播数据分析_pandas_08

Task2:比赛数据分析

参考来源: https://tianchi.aliyun.com/notebook/144451

预处理

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

将用户点击日志表和文章内容表做一个合并。

articles = articles.rename(columns={'article_id': 'click_article_id'})  #重命名,方便后续match
train_click = train_click.merge(articles, how='left', on=['click_article_id'])
train_click.head(3)

test_click = test_click.merge(articles, how='left', on=['click_article_id'])
test_click.head(3)

使train_click表中的点击文章id和articles表中的文章id一一对应。

python新闻联播数据分析_python新闻联播数据分析_09

数据浏览

用户点击日志文件

train_click.info()
test_click.info()

python新闻联播数据分析_python新闻联播数据分析_10

python新闻联播数据分析_python新闻联播数据分析_11

每个用户id唯一且不重复,所以我们通过查看user_id来判断用户数量。unique()方法返回的是不重复值,nunique()方法返回不同值的个数。

# user_id

train_click['user_id'].nunique(), test_click['user_id'].nunique()

python新闻联播数据分析_python新闻联播数据分析_12

可以看到训练集中有200000个用户,测试集中有50000个用户。

然后来看一下训练集和测试集中用户是否发生交叉,set()函数返回不重复元素集:

set(train_click['user_id']) & set(test_click['user_id'])

python新闻联播数据分析_python新闻联播数据分析_13

说明训练集中的用户不会在测试集中出现。因此,也就是我们在训练时,需要把测试集的数据也包括在内,称为全量数据。

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

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

python新闻联播数据分析_数据挖掘_14

新闻文章信息表

articles.info()

python新闻联播数据分析_pandas_15

articles.head().append(articles.tail())

python新闻联播数据分析_推荐算法_16

文章字数统计:

articles['words_count'].value_counts().reset_index()

python新闻联播数据分析_推荐算法_17

文章主题数:

print(articles['category_id'].nunique())
articles['category_id'].hist()

python新闻联播数据分析_数据挖掘_18

新闻文章embedding向量表示表

articles_emb.head()

python新闻联播数据分析_推荐算法_19

数据分析

用户国家和地区分布

# click country

train_click['click_country'].nunique(), test_click['click_country'].nunique()

python新闻联播数据分析_python新闻联播数据分析_20

训练集和测试集的用户国家都有11个。查看具体分布:

plt.figure(figsize=(10,5), dpi=80)
plt.subplot(121)
train_click['click_country'].value_counts().sort_index().plot(kind='bar')
plt.xlabel('click_country')

plt.subplot(122)
test_click['click_country'].value_counts().sort_index().plot(kind='bar')
plt.tight_layout()
plt.xlabel('click_country')

python新闻联播数据分析_数据挖掘_21

可以看到训练集和测试集的用户国家分布一致,都是1、10、11,集中在1。

# click region

train_click['click_region'].nunique(), test_click['click_region'].nunique()

python新闻联播数据分析_pandas_22

训练集和测试集的用户地区都是28个,查看具体分布:

plt.figure(figsize=(10,5),dpi=100)
plt.subplot(121)
train_click['click_region'].value_counts().sort_index().plot(kind='bar')
plt.xlabel('click_region')

plt.subplot(122)
test_click['click_region'].value_counts().sort_index().plot(kind='bar')
plt.xlabel('click_region')

python新闻联播数据分析_推荐算法_23

可以看到训练集和测试集的用户地区分布基本一致。

用户点击文章数

查看用户点击文章的数目,groupby函数用来对用户分组。

plt.figure(figsize=(10,5),dpi=120)
plt.subplot(121)
train_click.groupby('user_id')['click_article_id'].nunique().plot(kind='box')

plt.subplot(122)
test_click.groupby('user_id')['click_article_id'].nunique().plot(kind='box')

python新闻联播数据分析_python新闻联播数据分析_24

可以看到训练集和测试集分布基本一致,用户点击文章数多在100以内。

# 查看每个用户最少点击文章
train_click.groupby('user_id')['click_article_id'].count().min(), test_click.groupby('user_id')['click_article_id'].count().min()

python新闻联播数据分析_推荐算法_25

训练集中每个用户最少点击两篇文章,测试集中每个用户最少点击一篇文章。

用户重复点击

合并训练集和测试集:

# 合并训练集和测试集
user_click_merge = train_click.append(test_click)
# 用户重复点击
user_click_count = user_click_merge.groupby(['user_id', 'click_article_id'])['click_timestamp'].agg({'count'}).reset_index()
user_click_count[:10]

python新闻联播数据分析_python新闻联播数据分析_26

重复点击超过7的用户和文章:

user_click_count[user_click_count['count']>7]

python新闻联播数据分析_数据挖掘_27

重复点击次数:

user_click_count['count'].unique()

python新闻联播数据分析_python新闻联播数据分析_28

user_click_count['count'].value_counts()

python新闻联播数据分析_数据挖掘_29

可以看出有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_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)

python新闻联播数据分析_python_30

python新闻联播数据分析_数据挖掘_31

python新闻联播数据分析_推荐算法_32

python新闻联播数据分析_推荐算法_33

python新闻联播数据分析_pandas_34

python新闻联播数据分析_推荐算法_35

python新闻联播数据分析_pandas_36

python新闻联播数据分析_python新闻联播数据分析_37

python新闻联播数据分析_python_38

python新闻联播数据分析_python新闻联播数据分析_39

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

用户点击文章的次数

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

python新闻联播数据分析_python新闻联播数据分析_40

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

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

python新闻联播数据分析_python_41

可以看出点击次数排前50的用户的点击次数都在100次以上。由此有一个判断用户活跃度的思路:我们可以定义点击次数大于等于100次的用户为活跃用户。这是一种简单的处理思路,更加全面的是结合上点击时间。

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

python新闻联播数据分析_推荐算法_42

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

查看对每一篇文章不同来源下用户对应的点击次数。

click_referrer_type_count = pd.pivot_table(train_click, 
                                            index='click_article_id',
                                            columns='click_referrer_type',
                                            values='user_id',
                                            aggfunc='nunique',
                                            fill_value=0)
click_referrer_type_count

python新闻联播数据分析_python新闻联播数据分析_43

查看每一个来源的点击平均次数。

click_referrer_type_count.mean(0).plot(kind='bar')

python新闻联播数据分析_python_44

可以看到来源1、2、5的文章点击次数比较高。

查看文章来源之间的相关性:

click_referrer_type_count.corr()

python新闻联播数据分析_python新闻联播数据分析_45

观察发现来源1和来源7,来源2和来源7都是相关性比较大的。

用户点击新闻类型偏好

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

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

python新闻联播数据分析_pandas_46

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

用户点击文章的长度

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

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

python新闻联播数据分析_python新闻联播数据分析_47

可以发现有一小部分人看的文章平均词数非常高,也有一小部分人看的非常低。大多数人偏好于阅读字数在200-400字之间的新闻。

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

python新闻联播数据分析_python_48

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

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

python新闻联播数据分析_推荐算法_49

新闻文章点击的次数

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

python新闻联播数据分析_推荐算法_50

点击次数最多的前100篇新闻:

plt.plot(item_click_count[:100])

python新闻联播数据分析_python新闻联播数据分析_51

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

plt.plot(item_click_count[:30])

python新闻联播数据分析_数据挖掘_52

点击次数最多的前20篇新闻,点击次数大于8000。简单思路:可以定义这些新闻为热门新闻。

plt.plot(item_click_count[3500:])

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

统计文章点击人数和文章单词数是否存在关系:

plt.scatter(
    train_click.groupby(['click_article_id'])['user_id'].nunique(),
    train_click.groupby(['click_article_id'])['words_count'].mean()
)

python新闻联播数据分析_数据挖掘_53

大部分点击人数比较多的文章单词数都在2000以下。

对文章的点击时间和创建时间做一个差值,统计差值与点击人数的关系:

train_click['click_ts2created'] = train_click['click_timestamp'] - train_click['created_at_ts']

plt.scatter(
    train_click.groupby('click_article_id')['user_id'].nunique(),
    train_click.groupby('click_article_id')['click_ts2created'].mean()
)

python新闻联播数据分析_python新闻联播数据分析_54

可以发现文章创建的时间越短,被点击的概率越大。

用户行为时间戳分析

对每一个用户点击的时间戳前后做一个差值,相同的舍弃:

clicks_ts_diff = train_click.groupby('user_id')['click_timestamp'].diff(1).dropna()
clicks_ts_diff

python新闻联播数据分析_数据挖掘_55

对差值做一个统计:

clicks_ts_diff.describe().astype(int)

python新闻联播数据分析_python_56

从平均值看出大部分点击时间差都在一小时以内。

筛选user_id为199999的用户信息:

train_click[train_click['user_id']==199999]

python新闻联播数据分析_pandas_57

发现文章id为161191和42223的时间戳间隔很近,应该有某种关系。看一下它们的信息:

articles[articles['article_id'].isin([161191, 42223])]

python新闻联播数据分析_python_58

可以看到这两篇文章的创建时间也是很接近的。

具体而言,它们相隔时间在一小时以内。

(1507646579000 - 1507648195000) /1000 /3600

python新闻联播数据分析_推荐算法_59

#为了更好的可视化,这里把时间进行归一化操作
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新闻联播数据分析_推荐算法_60

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新闻联播数据分析_推荐算法_61

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

# 前后点击文章的创建时间差的平均值
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新闻联播数据分析_推荐算法_62

可以发现用户点击文章的创建时间也是有差异的。

新闻共现频次

新闻共现频次就是两篇新闻连续出现的次数。

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新闻联播数据分析_python新闻联播数据分析_63

由统计数据可以看出,平均共现次数3.18,最高为2202。说明用户看的文章相关性是比较强的。

画图直观看:

x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)

python新闻联播数据分析_数据挖掘_64

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

python新闻联播数据分析_推荐算法_65

大概有75000个pair至少共现一次。

新闻文章信息

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

python新闻联播数据分析_数据挖掘_66

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

python新闻联播数据分析_python新闻联播数据分析_67

# 新闻字数统计
plt.plot(user_click_merge['words_count'].values)

python新闻联播数据分析_推荐算法_68

文章嵌入向量

将文章嵌入向量进行降维可视化。

from sklearn.decomposition import PCA
pca = PCA(n_components=2)
articles_emb_2d = pca.fit_transform(articles_emb.values[:, 1:])
plt.scatter(articles_emb_2d[:,0], articles_emb_2d[:, 1], 
            s = 1, c=articles['category_id'].iloc[:], alpha=0.7)

python新闻联播数据分析_数据挖掘_69

from gensim.models import Word2Vec
import logging, pickle

# 需要注意这里模型只迭代了一次
def trian_item_word2vec(click_df, embed_size=16, save_name='item_w2v_emb.pkl', split_char=' '):
    click_df = click_df.sort_values('click_timestamp')
    # 只有转换成字符串才可以进行训练
    click_df['click_article_id'] = click_df['click_article_id'].astype(str)
    # 转换成句子的形式
    docs = click_df.groupby(['user_id'])['click_article_id'].apply(lambda x: list(x)).reset_index()
    docs = docs['click_article_id'].values.tolist()

    # 为了方便查看训练的进度,这里设定一个log信息
    logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.INFO)

    # 这里的参数对训练得到的向量影响也很大,默认负采样为5
    w2v = Word2Vec(docs, vector_size=16, sg=1, window=5, seed=2020, workers=24, min_count=1, epochs=10)
    
    # 保存成字典的形式
    item_w2v_emb_dict = {k: w2v.wv[k] for k in click_df['click_article_id']}
    
    return item_w2v_emb_dict

item_w2v_emb_dict = trian_item_word2vec(user_click_merge)

# 随机选择5个用户,查看这些用户前后查看文章的相似性
sub_user_ids = np.random.choice(user_click_merge.user_id.unique(), size=5, replace=False)
sub_user_info = user_click_merge[user_click_merge['user_id'].isin(sub_user_ids)]

sub_user_info.head()

python新闻联播数据分析_python新闻联播数据分析_70

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_w2v_emb_dict[str(item_list[i])] # 需要注意的是word2vec训练时候使用的是str类型的数据
        emb2 = item_w2v_emb_dict[str(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新闻联播数据分析_推荐算法_71

总结

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

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