小白推荐系统扫盲记——数据分析
这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
第一章 天池新闻推荐入门赛持续跟进——First one
(https://blog.csdn.net/qq_45068574/article/details/110088943)]
第二章 小白推荐系统扫盲记——数据分析
文章目录
前言
以下内容篇幅较长,思想内容不局限于单一数据,可以应用于普遍数据的处理与分析。代码可以参考。
以下是本篇文章正文内容,下面案例可供参考
一、数据分析是什么?
数据分析有极广泛的应用范围。典型的数据分析可能包含以下三个步:
1、探索性数据分析:当数据刚取得时,可能杂乱无章,看不出规律,通过作图、造表、用各种形式的方程拟合,计算某些特征量等手段探索规律性的可能形式,即往什么方向和用何种方式去寻找和揭示隐含在数据中的规律性。
2、模型选定分析,在探索性分析的基础上提出一类或几类可能的模型,然后通过进一步的分析从中挑选一定的模型。
3、推断分析:通常使用数理统计方法对所定模型或估计的可靠程度和精确程度作出推断。
数据分析往往是开始一个竞赛或着手一个项目的第一步探索性步骤,在使用数据之前,必要的了解和分析在后面的实践和应用中是很加分的。
二、使用python进行分析
1.导入库
代码如下(示例):
# 导入相关包
%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")
PS
%matplotlib inline是一个魔法函数,有他的存在,,图像将会自动显示而不用输入plt.show()
2.读入数据
分别导入训练集相关数据以及测试集A的数据。代码如下:
path = 'F:/data/DataWhale_data/'
#####train
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')
3.数据预处理
计算用户点击的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')
4.查看数据
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 | 用户点击文章时,文章的来源 |
查看用户点击日志信息
trn_click.info()
查看各个字段的基本信息
trn_click.describe()
训练集中的用户数量为20w
trn_click.user_id.nunique()
训练集里面每个用户至少点击了两篇文章
trn_click.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 = 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()
可以看出,大部分属性的分布是比较均匀的。个别属性,如click_environment超过90%的用户使用的是4;在click_deviceGroup中可以看出1和3占大多比例;click_country基本全部为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()
tst_click.groupby('user_id')['click_article_id'].count().min() # 注意测试集里面有只点击过一次文章的用户
1
新闻文章数据集浏览
item_df.head().append(item_df.tail())
得出点击次数用用户数量之间的关系:
item_df['words_count'].value_counts()
得出文章主题的点击信息并做直方图(共有461个文章主题)
print(item_df['category_id'].nunique()) # 461个文章主题
item_df['category_id'].hist()
查看词向量信息
item_emb_df.head()
数据分析
查看用户的重复点击
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['count'].unique()
用户点击新闻次数
user_click_count.loc[:,'count'].value_counts()
自定义环境分析函数
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()
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=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)
可以看出绝大多数数的用户的点击环境是比较固定的。思路:可以基于这些环境的统计特征来代表该用户本身的属性
用户点击新闻数量的分布
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])
#点击次数排名在[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[:100])
plt.plot(item_click_count[:20])
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()
#画个图直观地看一看
x = union_item['click_article_id']
y = union_item['count']
plt.scatter(x, y)
plt.plot(union_item['count'].values[40000:])
#不同类型的新闻出现的次数
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()
plt.plot(sorted(user_click_merge.groupby('user_id')['category_id'].nunique(), reverse=True))
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))
#挑出大多数人的区间仔细看看
plt.plot(sorted(user_click_merge.groupby('user_id')['words_count'].mean(), reverse=True)[1000:45000])
#更加详细的参数
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'))
# 用户前后点击文章的相似性分布
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)