人民网2022赛题3-微博流行度预测

摘要:

合集:AI案例-NLP-传媒
赛题:人民网2022人工智能算法大赛-赛题三:微博流行度预测
主办方:人民网
官网:https://app.people.cn/h5/detail/normal/5015943150896128
AI问题:回归预测问题
数据集:166万条微博传播数据集
数据集价值:预测微博的流行度包括评论数、转发数和点赞数。
解决方案:LightGBM算法支持多目标预测、特征工程。

一、赛题描述

简介

为推进人工智能领域的学术交流、人才培养、技术发展,鼓励广大学生积极学习和研发符合我国主流价值观的优秀算法,2022年11-12月举办“2022人民网人工智能算法大赛”,赛事由人民网股份有限公司主办,传播内容认知全国重点实验室承办。

  • 赛题一:对话生成
  • 赛题二:微博话题识别
  • 赛题三:微博流行度预测
  • 赛题四:微博转发行为预测
  • 赛题五:社交媒体机器人识别

赛题三:微博流行度预测

互联网新媒体,特别是微博的兴起,极大地促进了信息的广泛传播。对微博信息的流行度规模作出精准预测,有利于对互联网舆情态势作出准确研判。本次比赛提供微博传播数据集,包括一批微博数据,每条微博数据附带用户在当时的基本信息数据。参赛选手需要预测微博在指定时间的流行度。其中,流行度由微博的转发量、评论量、点赞量三者共同决定。

二、数据集内容

数据规模为约 166 万条,每条数据包含 15 个属性。训练集:train.data.csv,每个字段以\t划分。其中输出变量包括:微博的评论数(commentNum)、转发数(retweetNum)和点赞数(likeNum)。

userid          用户Id(字段加密)
verified       是否微博认证
uservip         用户类别
userLocation   用户所在地
userCreatetime 用户创建时间
gender         性别
statusesCount   用户历史发微博数
followersCount 丝数
weiboid         微博Id(字段加密)
content         微博文字内容
pubtime         发布时间
ObserveTime     采集时间
retweetNum     微博在采集时间的转发数量
likeNum         微博在采集时间的点赞数量
commentNum     微博在采集时间的评论数量

数据样例:

weiboid                                   1019021
userid                                     19367
content           小孩:你慢点,最近头变大了#燃夏快乐争霸赛# 搞笑旺的微博视频
uservip                                         0
pubtime                       2022-07-03 23:59:57
userLocation                                    
userCreatetime                                  
followersCount                                 0
statusesCount                                   0
verified                                       1
gender                                          
ObserveTime                   2022-07-04 00:00:00
commentNum                                     0
retweetNum                                     0
likeNum                                         0
Name: 0, dtype: object

测试集:infer.data.csv,共有12个字段,每个字段以\t划分,用于客观测试。测试集合中没有输出变量:微博的评论数(commentNum)、转发数(retweetNum)和点赞数(likeNum)。

userid          用户Id(字段加密)
verified       是否微博认证
uservip         用户类别
userLocation   用户所在地
userCreatetime 用户创建时间
gender         性别
statusesCount   用户历史发微博数
followersCount 丝数
weiboid         微博Id(字段加密)
content         微博文字内容
pubtime         发布时间
ObserveTime     采集时间

数据集版权许可协议

GPL2

三、解决方案样例

解决方案

源码:Weibo_Popularity_Prediction.ipynb

这个Python脚本实现了微博流行度预测功能,主要使用LightGBM算法来预测微博的评论数(commentNum)、转发数(retweetNum)和点赞数(likeNum)。这是一多目标预测:脚本分别训练了三个独立的LightGBM回归模型,每个模型预测一个指标(评论、转发、点赞)。

其中输入特征包括用户属性(如粉丝数、VIP状态)、内容属性(如文本长度、发布时间)和历史行为特征(如用户/内容的历史平均表现)。输出变量是连续数值型变量,因此采用回归模型而非分类模型。

导入相关系统库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

from lightgbm import LGBMRegressor
from sklearn.metrics import mean_absolute_percentage_error

import joblib

工作流程如下:

1. 数据加载与预处理

  • 从CSV文件读取训练数据(train.data.csv)和测试数据(infer.data.csv),使用制表符分隔
  • 对微博内容(content)进行去空格处理
  • 将时间字段(ObserveTimepubtime)转换为datetime格式
  • 计算微博展示时间(ShowTime)和展示分钟数(ShowTime_minute)
  • 提取发布时间和观测时间的小时部分
train_data = pd.read_csv('./data/train.data.csv', sep='\t')
test_data = pd.read_csv('./data/infer.data.csv', sep='\t')

train_data['content'] = train_data['content'].apply(lambda x: x.strip())
test_data['content'] = test_data['content'].apply(lambda x: x.strip())

train_data.head(5)

2. 数据探索分析

脚本进行了多方面的数据分析:

  • 时间分析:分析发布时间、观测时间的小时分布与流行度的关系
  • 内容分析:检查内容唯一性,分析特定内容的平均评论数
  • 用户分析:
    • 用户VIP状态与流行度的关系
    • 用户地理位置分布及其与流行度的关系
    • 粉丝数(followersCount)、历史微博数(statusesCount)与流行度的关系
    • 认证状态(verified)和性别(gender)对流行度的影响

分析数据集概况:

train_data.shape, train_data['weiboid'].nunique()
train_data['content'].nunique()
train_data['content'].value_counts()

输出:((1665955, 15), 1665954)。说明:数据规模为约 166 万条,每条数据包含 15 个属性(如 weiboid、content、commentNum 等)

3. 特征工程

将数据分为训练集和验证集(最后25000条作为验证集)。train_data.sample(frac=1.0)将 train_data 数据框随机打乱。frac=1.0 表示抽取全部数据,即打乱整个数据集。打乱后,重新赋值给 train_data,这样原始的数据顺序就被打乱了。

划分训练集和验证集:

  • np.arange(train_data.shape[0])[:-25000]:生成一个从 0 到 train_data.shape[0] – 1 的数组,然后去掉最后 25000 个元素,作为训练集的索引。
  • np.arange(train_data.shape[0])[-25000:]:生成一个从 train_data.shape[0] – 25000 到 train_data.shape[0] – 1 的数组,作为验证集的索引。
train_data = train_data.sample(frac=1.0)
train_idx = np.arange(train_data.shape[0])[:-25000]
valid_idx = np.arange(train_data.shape[0])[-25000:]

构建了多个重要特征:

  • 用户特征:基于用户ID的历史平均评论、转发、点赞数
# userid
userid_feature = train_data.iloc[train_idx].groupby(['userid'])[['commentNum', 'retweetNum', 'likeNum']].mean().reset_index()

history_count = train_data.iloc[train_idx]['userid'].value_counts().to_dict()
userid_feature['userid_history_count'] = userid_feature['userid'].map(history_count)

userid_feature.loc[
   userid_feature['userid_history_count'] < 3,
  ['commentNum', 'retweetNum', 'likeNum']
] = train_data.iloc[train_idx][['commentNum', 'retweetNum', 'likeNum']].mean().values

userid_feature.columns = [userid_feature.columns[0]] + [x + '_userid_mean' for x in userid_feature.columns[1:]]
  • 内容特征:相同内容的历史平均表现
# content
content_feature = train_data.iloc[train_idx].groupby(['content'])[['commentNum', 'retweetNum', 'likeNum']].mean().reset_index()

history_count = train_data.iloc[train_idx]['content'].value_counts().to_dict()
content_feature['content_history_count'] = content_feature['content'].map(history_count)

content_feature.loc[
   content_feature['content_history_count'] < 3,
  ['commentNum', 'retweetNum', 'likeNum']
] = train_data.iloc[train_idx][['commentNum', 'retweetNum', 'likeNum']].mean().values

content_feature.columns = [content_feature.columns[0]] + [x + '_content_mean' for x in content_feature.columns[1:]]
  • 内容特征:内容长度、是否全中文、是否包含中文
# 检验是否全是中文字符
def str_isall_chinese(str):
   for ch in str:
       if not u'\u4e00' <= ch <= u'\u9fa5':
           return False
   return True

# 判断字符串是否包含中文
def str_contain_chinese(str):
   for ch in str:
       if u'\u4e00'<=ch<=u'\u9fff':
           return True
   return False

train_data['content_charcount'] = train_data['content'].apply(len)
train_data['content_all_ch'] = train_data['content'].apply(str_isall_chinese)
train_data['content_contain_ch'] = train_data['content'].apply(str_contain_chinese)
  • VIP特征:不同VIP等级的平均流行度
# uservip
train_data['uservip'] = train_data['uservip'].str.strip().replace('', 0).astype(int)

uservip_feature = train_data.iloc[train_idx].groupby(['uservip'])[['commentNum', 'retweetNum', 'likeNum']].mean().reset_index()
uservip_feature.columns = [uservip_feature.columns[0]] + [x + '_vip_mean' for x in uservip_feature.columns[1:]]
  • 时间特征:不同发布小时的平均流行度
  • 其他特征:发布时间分钟数是否为0、用户创建时间是否为空等
# pubtime
train_data['pubtime_minute'] = train_data['pubtime'].dt.minute
train_data['pubtime_minute_is0'] = (train_data['pubtime_minute'] == 0)

train_data.drop(
  ['ObserveTime', 'ObserveTime_hour', 'pubtime', 'pubtime_minute', 'ShowTime'],
   axis=1, inplace=True
)
  • 位置特征:不同地理位置的平均流行度
# userLocation
train_data['userLocation'] = pd.factorize(train_data['userLocation'])[0]

location_feature = train_data.iloc[train_idx].groupby(['userLocation'])[['commentNum', 'retweetNum', 'likeNum']].mean().reset_index()
history_count = train_data.iloc[train_idx]['userLocation'].value_counts().to_dict()
location_feature['location_history_count'] = location_feature['userLocation'].map(history_count)

location_feature.loc[
   location_feature['location_history_count'] < 3,
  ['commentNum', 'retweetNum', 'likeNum']
] = train_data.iloc[train_idx][['commentNum', 'retweetNum', 'likeNum']].mean().values

location_feature.columns = [location_feature.columns[0]] + [x + '_location_mean' for x in location_feature.columns[1:]]

合并特征:使用 pandas 的 merge 函数将 train_data 数据框与 userid_feature 数据框按照 userid 列进行左连接(left join):

  • pd.merge: pandas 中用于合并两个数据框的函数。
  • train_data: 主数据框,包含您的主要训练数据。
  • userid_feature: 要合并的特征数据框,包含与 userid 相关的特征。
  • on=’userid’: 指定按照 userid 列进行合并。
  • how=’left’: 指定使用左连接,这意味着 train_data 中的所有行都会保留,即使在 userid_feature 中没有匹配的行。对于 userid_feature 中没有匹配的行,结果中的相应列将填充为 NaN。
# 特征合并
train_data = pd.merge(train_data, userid_feature, on='userid', how='left')
train_data = pd.merge(train_data, content_feature, on='content', how='left')
train_data = pd.merge(train_data, uservip_feature, on='uservip', how='left')
train_data = pd.merge(train_data, time_feature, on='pubtime_hour', how='left')
train_data = pd.merge(train_data, location_feature, on='userLocation', how='left')

4. 模型训练与评估

  • 使用LightGBM回归模型分别预测评论数、转发数和点赞数
  • 评估指标使用平均绝对百分比误差(MAPE)
  • 展示了特征重要性图
  • 保存训练好的模型
model = LGBMRegressor(max_depth=10,                  # 设置树的最大深度为10,防止过拟合
                     n_estimators=100,              # 设置树的数量为100
                     # min_data_in_leaf=10,           # 根据数据情况调整
                     # min_sum_hessian_in_leaf=0.01, # 根据数据情况调整
                     # min_gain_to_split=0.0         # 允许任何正增益的分裂
)

model.fit(
   # 使用 train_idx 索引从 train_data 中选择训练样本
   train_data.iloc[train_idx].drop(['weiboid', 'content', 'commentNum', 'retweetNum', 'likeNum'], axis=1),
   train_commentNum  # 目标变量,即微博的评论数量
)

# 移除不需要的列后,进行预测,将结果存储在 pred_commentNum 中
pred_commentNum = model.predict(train_data.iloc[valid_idx].drop(['weiboid', 'content', 'commentNum', 'retweetNum', 'likeNum'], axis=1))
# 计算预测值与实际值之间的平均绝对百分比误差(MAPE)
print('commentNum MAPE:', mean_absolute_percentage_error(pred_commentNum, valid_commentNum))

运行结果展示:

[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.049962 seconds.
You can set `force_row_wise=true` to remove the overhead.
And if memory is not enough, you can set `force_col_wise=true`.
[LightGBM] [Info] Total Bins 4485
[LightGBM] [Info] Number of data points in the train set: 1640955, number of used features: 33
[LightGBM] [Info] Start training from score 4.297288
commentNum MAPE: 1.7407553603481845
[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.042826 seconds.
You can set `force_row_wise=true` to remove the overhead.
And if memory is not enough, you can set `force_col_wise=true`.
[LightGBM] [Info] Total Bins 4485
[LightGBM] [Info] Number of data points in the train set: 1640955, number of used features: 33
[LightGBM] [Info] Start training from score 2.687703
retweetNum MAPE: 1.6721913125430474
[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.055600 seconds.
You can set `force_row_wise=true` to remove the overhead.
And if memory is not enough, you can set `force_col_wise=true`.
[LightGBM] [Info] Total Bins 4485
[LightGBM] [Info] Number of data points in the train set: 1640955, number of used features: 33
[LightGBM] [Info] Start training from score 16.691268
likeNum MAPE: 1.1931618603502967

5. 保存模型

# 保存模型
joblib.dump(model, 'lgbm_comment_num_model.pkl')

# 加载模型
# loaded_model = joblib.load('lgbm_comment_num_model.pkl')

关键点

  1. 多目标预测:分别预测评论、转发和点赞三个指标
  2. 特征丰富:充分利用了用户属性、内容特征和时间特征
  3. 数据分桶:对低频用户和内容进行了均值填充处理
  4. 模型选择:使用LightGBM这种高效的梯度提升框架
  5. 评估指标:采用MAPE来衡量预测误差百分比

四、获取案例套装

需要登录后才允许下载文件包。登录 需要登录后才允许下载文件包。登录

发表评论