查看原文
其他

数据分析 | 使用决策树分析小红书帖子数据(含代码)

huzujun 大邓和他的Python
2024-09-09

安装相关库

!pip install dtreeviz==1.3.3
!pip install emoji
!pip install plotly



一、导入数据

import pandas as pd
import warnings
warnings.filterwarnings("ignore")

df = pd.read_csv('xiaohongshu.csv')

#print(len(df))
#df.head()



二、数据预处理

列是series类型数据, 使用apply方法(应用lambda函数)对列进行批处理。

这里可以做很多事情,例如

  • desc的文本长度、表情数量
  • title标题的长度
  • 几点发文(24小时制的)
  • ...
import emoji

#desc中的表情数量
df['emoji_nums'] = df['desc'].apply(lambda desc: len(emoji.emoji_list(desc)))

#话题tag数量
df['hashTag_nums'] = df['desc'].str.count('#')

#标题title的文本长度
df['title_len'] = df['title'].str.len()
df['desc_len'] = df['desc'].str.len()
#几点发文
df['time'] = pd.to_datetime(df['time'], errors='coerce')
df['hours'] = df['time'].dt.hour

#把文本数字转为数值型数字
df['image_nums'] = df['image_nums'].astype('int')
df['liked_count'] = df['liked_count'].astype('int')

#显示前5行
df[['emoji_nums''hashTag_nums''title_len''desc_len''hours''image_nums''liked_count']].head()



三、数据分析

3.1 处理点赞数

看一下点赞数的数据分布

df.liked_count.describe()

Run

    count     5928.000000
    mean       157.174764
    std        713.708655
    min          0.000000
    25%          2.000000
    50%         15.000000
    75%         69.000000
    max      22265.000000
    Name: liked_count, dtype: float64

import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
import platform
import matplotlib_inline
matplotlib_inline.backend_inline.set_matplotlib_formats('png''svg')

system = platform.system()  # 获取操作系统类型

if system == 'Windows':
    font = {'family''SimHei'}
elif system == 'Darwin':
    font = {'family''Arial Unicode MS'}
else:
    # 如果是其他系统,可以使用系统默认字体
    font = {'family''sans-serif'}
matplotlib.rc('font', **font)  # 设置全局字体


sns.distplot(df.liked_count)
plt.xlabel('点赞数')
plt.ylabel('分布')
plt.title('liked_count核密度分布图')


print(df.liked_count.min())
print(df.liked_count.median())
print(df.liked_count.max())
0
15.0
22265

这里可以看出一个问题,点赞数具有很强的长尾效应,也就是说一半的文章点赞数小于15,而热门的文章点赞数可以上千上万,因此如果直接分析点赞数的数值,用回归之类的算法去分析,一定是灾难,所以我们不妨简单处理,在这里我先人为定义点赞数>=50为热帖,其它的不是热帖,通过这个方式把笔记分成了两类

df["heat"] = pd.cut(df["liked_count"], bins=[-15022266], labels=['凉帖''热帖'])



3.2 分析热帖比例和小时的关系

import plotly
import plotly.graph_objs as go
plotly.offline.init_notebook_mode()

heats = []
for i in range(24):
    hour_df = df[df['hours'] == i]
    heats.append(len(hour_df[hour_df['heat'] == '热帖'])/len(hour_df))

layout = {'title''24小时随时间热帖图'}
fig = go.Figure(data=[{'x': list(range(024)), 'y': heats}], layout = layout)
plotly.offline.iplot(fig)



3.3 分析热帖比例和表情数的关系

df["emoji_nums"].describe()

Run

    count    5928.000000
    mean        6.824055
    std         9.996283
    min         0.000000
    25%         0.000000
    50%         3.000000
    75%        10.000000
    max       103.000000
    Name: emoji_nums, dtype: float64

sns.distplot(df.emoji_nums)
plt.xlabel('表情数')
plt.ylabel('分布')
plt.title('emoji表情数核密度分布图')


import plotly.offline as py
import plotly.graph_objs as go

df["emoji_level"] = pd.cut(df["emoji_nums"], bins=[-1490], labels=['表情少''表情多'])

emoji_levels = []
for i in ['表情少''表情多']:
    emoji_df = df[df['emoji_level'] == i]
    emoji_levels.append(len(emoji_df[emoji_df['heat'] == '热帖'])/len(emoji_df))

import plotly.express as px
colors = ['blue''red']
fig = go.Figure(data=[go.Bar(
    x=['表情数<=4''表情数>4'],
    y=emoji_levels,
    marker_color=colors # marker color can be a single color value or an iterable
)])
fig.update_layout(title_text='表情数-热帖占比')
plotly.offline.iplot(fig)



3.4 分析热帖比例和标签的关系

我原本以为的是“适当的标签最好,不是越多越好”,结果推翻了我的猜想

df["hashTag_nums"].describe([i/10 for i in range(111)])

Run

    count    5928.000000
    mean        3.638327
    std         4.077919
    min         0.000000
    10%         0.000000
    20%         0.000000
    30%         1.000000
    40%         2.000000
    50%         3.000000
    60%         3.000000
    70%         4.000000
    80%         6.000000
    90%         9.000000
    100%       49.000000
    max        49.000000
    Name: hashTag_nums, dtype: float64

df["hashTags_level"] = pd.cut(df["hashTag_nums"], bins=[-112346949], labels=[1234567])

emoji_levels = []
for i in range(18):
    con = df[df['hashTags_level'] == i]
    emoji_levels.append(len(con[con['heat'] == '热帖'])/len(con))

import plotly.express as px
fig = go.Figure(data=[go.Bar(
    x=['<= 1 hashTags''1 < hashTags <= 2''2 < hashTags <= 3''3 < hashTags <= 4''4 < hashTags <= 6',
      '6 < hashTags <= 9''9 < hashTags <= 49'],
    y=emoji_levels, # marker color can be a single color value or an iterable
)])
fig.update_layout(title_text='话题数-热帖占比')
plotly.offline.iplot(fig)


df[df['hashTag_nums'] > 9].describe()



3.5 决策树模型

这里我们尝试用这些因子去预测帖子是否热门,我挑选的是决策树,虽然别的模型可能会搞出几个百分点的准确率,但是必要性不是很大,在这里我更想要看到可解释性强的结果,而不是黑盒模型,这是决策数的优点,因为预测是否热帖这个事情不是我们的目的。

df['liked_count'].describe()

Run

    count     5928.000000
    mean       157.174764
    std        713.708655
    min          0.000000
    25%          2.000000
    50%         15.000000
    75%         69.000000
    max      22265.000000
    Name: liked_count, dtype: float64

决策树模型要求种类要平衡,这里有两种解决方法:- 对不平衡的种类重新取样 - 这里因为数据本来就不算很多,我就人为重新定义了中位数作为热帖的分水岭df["heat"] = pd.cut(df["liked_count"], bins=[-11522266], labels=[12])
print(len(df[df["heat"] == 1]), len(df[df["heat"] == 2]))
2982 2946

决策树模型根据尝试,在最大深度为3时近似就能取到很好的准确率了

from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

df["heat"] = pd.cut(df["liked_count"], bins=[-11522266], labels=[12])
df["emoji_level"] = pd.cut(df["emoji_nums"], bins=[-1490], labels=[12])

cols = ['image_nums',  'desc_len''title_len''hashTags_level' ,'emoji_level''hours']
X = df[cols]
scaler = StandardScaler()
scaler.fit(X)
X = scaler.transform(X)
y = df['heat']

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

print(len(X_train), len(y_test))

clf = DecisionTreeClassifier(max_depth = 3)

clf.fit(X_train, y_train)

print(accuracy_score(clf.predict(X_test), y_test))

Run

    4446 1482
    0.699055330634278

70%的准确率意味着比乱猜的50%要好不少,在我们完全没有去关注帖子内容,仅仅只根据图片数、文本长度来预测是否热帖已经有这个准确率,已经是非常好了。我们可视化决策树

from dtreeviz.trees import dtreeviz # remember to load the package

viz = dtreeviz(clf, X_test, y_test,
                target_name="target",
                feature_names=cols,
                class_names=['unpopular''popular'])
viz.save("viz.svg")
viz


可视化决策树的结论:一般来说,越多的图片、越长的标题、越长的正文能显著获得更高的热贴机会,这是根据决策树的结果得到的。不过如果图片和标题信息量足够了,正文不用特别长也可以了。

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

forest = RandomForestClassifier(random_state=888, max_depth = 4)
forest.fit(X_train, y_train)

print(accuracy_score(forest.predict(X_test), y_test))
0.7031039136302294

import matplotlib.pyplot as plt
from sklearn.inspection import permutation_importance

result = permutation_importance(forest, X_test, y_test, 
                                n_repeats=10, random_state=42, n_jobs=2)

forest_importances = pd.Series(result.importances_mean, index=col)

fig, ax = plt.subplots()
forest_importances.plot.bar(yerr=result.importances_std, ax=ax)
ax.set_title("模型中特征重要性排序")
ax.set_ylabel("平均精度下降")
fig.tight_layout()
plt.show()



代码下载

https://textdata.cn/blog/2023-03-11-xiaohongshu-data-analysis/


资料整理自

https://www.kaggle.com/code/huzujun/xiaohongshu-data-mining/notebook




精选文章

管理世界 | 使用文本分析词构建并测量短视主义

管理世界 | 使用 经营讨论与分析 测量 企业数字化指标

管理世界 | 用正则表达式、文本向量化、线性回归算法从md&a数据中计算 「企业融资约束指标

可视化 | 词嵌入模型用于计算社科领域刻板印象等信息(含代码)

转载 | 基于词嵌入技术的心理学研究: 方法及应用

赶快收藏 | 社会科学文本挖掘技术资料汇总

B站社会科学文本分析视频合集

词嵌入技术在社会科学领域进行数据挖掘常见39个FAQ汇总

文本分析 | 中国企业高管团队创新注意力(含代码)

文本分析 | MD&A 信息含量指标构建代码实现

金融研究 | 使用Python构建「关键审计事项信息含量」

支持开票 | Python实证指标构建与文本分析

金融研究 | 文本相似度计算与可视化

转载 | 社会计算驱动的社会科学研究方法

推荐 | 社科(经管)文本分析快速指南

视频分享 | 文本分析在经管研究中的应用

转载 | 金融学文本大数据挖掘方法与研究进展

转载 | 大数据驱动的「社会经济地位」分析研究综述

使用 Word2Vec 和 TF-IDF 计算五类企业文化

如何用「图嵌入」将企业、高管职业经历表征为向量数据

JM2022综述 | 黄金领域: 为营销研究(新洞察)采集网络数据

可视化 | 绘制《三体》人物关系网络图

MS | 使用网络算法识别创新的颠覆性与否

认知的测量 | 向量距离vs语义投影

Asent库 | 英文文本数据情感分析

PNAS | 文本网络分析&文化桥梁Python代码实现

PNAS | 使用语义距离测量一个人的创新力(发散思维)得分

tomotopy | 速度最快的LDA主题模型

数据集 | cctv新闻联播文稿数据

数据集 | 睡前消息文稿数据集

EDGAR | 25年数据的预训练词向量模型(含代码)

2G数据集 | 80w知乎用户问答数据

继续滑动看下一个
大邓和他的Python
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存