免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

基于DNN的社交媒体用户性格分析:TensorFlow实现大五人格分类

基于DNN的社交媒体用户性格分析:TensorFlow实现大五人格分类 简介基于DNN深层神经网络的社交媒体用户性格分析项目面向具备一定Python基础的人工智能与深度学习学习者以TensorFlow为框架实现大五人格分类任务覆盖数据预处理、网络构建、训练与评估全流程。压缩包共52个文件包括20个Python脚本、22个NumPy数据、4个txt说明、4个Markdown文档及2个CSV标注文件整体大小18.35MB目录按数据、特征、模型、工具等模块划分便于按需查阅。目前已有280人学习。资源在特征处理环节引入TF-IDF、Doc2Vec、情感词典等方法可结合批量归一化、Dropout、学习率调优等训练技巧快速复现实验并掌握用深度学习完成文本分类和用户画像的完整实践路径。 如果你手头有一批社交媒体文本数据想判断某个用户是偏外向还是内向、是随性还是自律传统做法是发问卷但问卷回收率低、样本量小根本撑不起规模化运营。基于DNN深层神经网络的社交媒体用户性格分析可以直接拿用户公开发布的文本当输入借助TensorFlow框架训练一个大五人格分类模型把用户自动归入开放性、尽责性、外向性、宜人性、神经质五个维度的倾向。这套方案在工业界的典型场景是用户画像冷启动产品初期没有行为数据但用户的微博、帖子、评论是摆在那里的。适合刚接触深度学习、想完整走一遍从数据清洗到模型上线的同学也适合社交产品团队做人群分层摸底。我在一个社区产品项目里完整实践过这条链路今天把数据清洗、特征工程、网络结构、调参和踩坑全过程拆开讲代码和思路都可以直接抄。1. 为什么DNN是社交文本性格分类里的性价比选手性格分析不是常规的文本分类任务很多人一上来就上BERT结果训练时间翻了几倍效果还没跑赢一个结构简单的DNN。想搞清楚为什么得先看任务本身长什么样。1.1 大五人格任务到底在预测什么大五人格模型OCEAN把人的性格拆成五个连续维度开放性、尽责性、外向性、宜人性、神经质。注意这五个维度不是互斥的标签而是连续谱系。一个用户可以同时高外向、高宜人这和图文分类里一篇帖子要么是科技类要么是娱乐类的逻辑完全不同。实际落地时我们通常把连续分数转成二分类每个维度取高分段和低分段预测用户在该维度上属于哪一端。社交文本能反映性格是因为人的语言使用习惯存在稳定个体差异。高外向的人更爱用社会性词汇和人称代词高神经质的人负面情感词密度明显更高高尽责性的人在文本里展现出更强的条理性和因果句式。这些信号虽然弱但在用户级聚合文本里是可统计的。1.2 为什么不是Transformer也不是SVM做文本分类绕不开两个极端传统机器学习和预训练大模型。我的选择是折中的DNN理由非常务实。方案非线性能力特征工程成本小数据表现训练/部署成本SVM/LR弱高靠人工特征中上极低DNN强低自动学特征组合中上配合正则化低BERT等预训练模型极强极低差万级样本容易过拟合高公开的性格分析数据集普遍在万条以内比如经典的Mypersonality数据集用户量不到一万。这个量级去微调BERT基本是送死——预训练模型参数太多小数据上训练集loss降得飞快验证集却一动不动。而SVM这类线性模型又太依赖特征工程你要手动设计大量心理语言学特征工作量大不说泛化也一般。DNN介于两者之间Keras高层API几十行代码能搞定CPU就能训练配合Dropout和早停能有效控制过拟合是这类中等规模表格化文本数据的甜点区。2. 数据侧决定天花板文本清洗、特征表示与标签构造模型结构再花哨数据侧没做对结果一定烂。这块我踩的坑最多逐一说。2.1 数据粒度一条帖子还是一个人最关键的决策是样本的粒度问题。性格是人的稳定属性不是单条帖子的属性。如果你把每一条状态更新当成独立样本同一个用户的十几条帖子会被拆成十几个样本训练集和验证集之间会出现严重的用户重叠模型学到的是这个用户的口癖而不是这类性格的共性表达评估指标虚高一大截。正确做法是以用户为粒度把一个用户的所有文本拼接成一份用户级文档一份文档对应一个样本、一组五维标签。我第一次没注意这个问题验证AUC跑到了0.85换成用户级切分后直接掉到0.74那才是真实水平。这是性格分析任务里最容易骗自己的地方。2.2 特征表示与预处理细节文本预处理没有统一答案但要遵守一条原则凡是这个用户是谁的强线索都要尽量抹掉。URL、用户名、数字、无意义表情符号这些和性格无关却可能被模型当成偷懒特征直接利用。按用户聚合后我的清洗流水线是去掉URL、提及、转发标记、 HTML 实体。统一小写中文场景要分词英文场景按空格切分即可。过滤掉长度小于20个字符的帖子这类短文本大多是哈哈、转发微博之类没有有效性格信号。停用词按任务决定去不去情感词、人称代词反而对性格预测有用只删高频虚词和标点符号。特征上我对比过两种方案。一是TF-IDFngram_range设为(1,2)max_features取10000配合sublinear_tfTrue做词频压缩效果稳定且完全可解释。二是Word2Vec平均池化训练一个100维的 skip-gram 词向量把用户文档中所有词的向量取平均。实测TF-IDF配DNN在小数据上表现更稳词向量平均会丢失词序和强调信息只有在数据量更大时才显优势。另外用任意预训练模型导出文本embedding再喂给DNN也是可行的本质上还是DNN框架只是特征来源换了。2.3 标签的构造决定了任务边界标签是整个项目最贵的部分。Mypersonality这类数据集自带用户填写的大五问卷结果而自采数据时你只能自己做标注。实用做法是发BFI-10这类10题版大五量表让用户自评再把每个维度的均分按中位数切成高低两组。切分阈值直接决定类别平衡程度。这里有个隐形坑高低分组的标准。如果样本整体偏外向你按中位数切得到的是一个相对外向的低外向组而不是真正意义上的内向群体。如果你想要绝对阈值就得先做一轮预调查确认人群基线。我自己实操时采用中位数切分但会在项目文档里明确标注此标签为相对高低适用于排序场景避免下游业务误读成绝对人格诊断。3. TensorFlow搭建DNN的建模细节与关键代码数据准备好之后网络设计其实就剩几个决策点。但每个决策点背后都有讲究尤其是输出层设计新手特别容易做错。3.1 输出层设计5个sigmoid而不是5分类softmax先说最容易错的地方。大五人格有五个维度有些同学想当然地写成5分类softmax这从任务建模上就是错的。softmax要求所有类别互斥且概率和为1而大五人格五个维度是可共存的一个人完全可能高开放又高尽责。softmax强行把这个问题拧成五选一等于把性格模型硬生生改成了星座模型语义完全跑偏。正确做法是输出层放5个神经元每个用sigmoid独立输出0到1的概率表示该用户在每个维度上属于高分组或低分组的概率。损失函数用binary_crossentropy而不是categorical_crossentropy。这就是多标签二分类和多分类的区别决定了整个任务的定义是否正确。3.2 正则化策略与训练回调社交文本特征有两个特点维度高、噪声大。TF-IDF特征动辄上万维但很多维度是稀疏的文本表达又千变万化模型非常容易记住训练集里的个别表达方式。所以正则化不是可选项是必需品。我在每一层Dense后面依次加了L2权重衰减、BatchNormalization和Dropout三层保护效果明显。BatchNormalization会把每层输出拉回标准分布让深层网络训练更稳定。Dropout在每次训练迭代中随机丢弃一部分神经元的连接强迫网络学习冗余的分布式特征而不是依赖少数几个强特征。这两者的顺序不能错我习惯放在激活函数之后、下一层之前。EarlyStopping按验证集AUC来触发patience设为5个epoch防止最后一轮验证集还没收敛就停掉。3.3 核心代码与项目文件组织用TensorFlow的Keras接口实现代码量非常精简。这里贴出核心网络构建代码特征工程部分略过因为不同数据源差异较大。import tensorflow as tf from tensorflow.keras import layers, models, callbacks def build_dnn(feature_dim, hidden_units(256, 128), dropout_rate0.4): model models.Sequential(namednn_bigfive) model.add(layers.Input(shape(feature_dim,))) for units in hidden_units: model.add(layers.Dense(units, activationrelu, kernel_regularizertf.keras.regularizers.l2(1e-4))) model.add(layers.BatchNormalization()) model.add(layers.Dropout(dropout_rate)) model.add(layers.Dense(5, activationsigmoid)) model.compile( optimizertf.keras.optimizers.Adam(learning_rate5e-4), lossbinary_crossentropy, metrics[tf.keras.metrics.AUC(nameauc), tf.keras.metrics.Precision(nameprecision), tf.keras.metrics.Recall(namerecall)] ) return model early_stop callbacks.EarlyStopping( monitorval_auc, modemax, patience5, restore_best_weightsTrue ) reduce_lr callbacks.ReduceLROnPlateau( monitorval_auc, modemax, factor0.5, patience2 ) model build_dnn(feature_dimX_train.shape[1]) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs50, batch_size64, callbacks[early_stop, reduce_lr] )最终交付的项目里我习惯把文件拆成四个模块preprocess.py负责清洗和特征化train.py负责训练和保存权重predict.py加载模型对单用户文本做预测evaluate.py输出各个维度的AUC、F1和混淆矩阵。模型权重用model.save(bigfive_dnn.keras)存成独立文件README里写清楚每列的字段含义和切分阈值。这样别人拿到zip包不用看超过十分钟就能跑通。4. 训练调参实录从loss不动到宏F1稳定在0.78调参过程不是一次到位的我把整个决策链路记录下来这部分对你自己训练类似模型最有参考价值。4.1 第一版全连接网络的表现与问题第一版我用了单隐藏层512个神经元learning_rate设1e-2batch_size取32dropout设为0.3。训练5个epoch后训练loss下降得很快但验证集AUC基本在0.7附近横盘训练集和验证集差距越拉越大。这个现象非常典型模型容量偏大而有效训练样本只有几千条模型开始背诵训练样本。网络容量大本身不是错错的是容量和数据量不匹配。我后来把隐藏层改成256加128两层dropout提到0.4learning_rate降到5e-4验证AUC开始稳步上升。这说明在社交文本这种高噪声输入上窄而深的网络比宽而浅的网络更抗过拟合因为窄层迫使网络学习更抽象、更可泛化的特征压缩表示。4.2 学习率、批量大小与模型容量的调整链路调参要一次只动一个变量否则出了问题你根本不知道是谁干的。我的调整顺序是先降模型容量再动正则化强度然后调学习率最后动批次大小。学习率从1e-2降到5e-4看起来跨度大但配合Adam优化器和小批量模型收敛更平稳。batch_size我试过16、32、64。batch_size太小时梯度噪声大训练曲线抖动明显太大则需要更多epoch才能收敛。32到64之间在这个任务上没有显著差异但64的训练时间明显更短。反过来在数据量很小的任务里大batch_size会让每个epoch的更新次数变少早停很容易在第20个epoch就触发反而浪费了模型容量。平衡点是64。4.3 评估指标的坑单标签准确率会骗人我见过太多人用准确率评估性格分类模型这是第二个大坑。假设五个维度里某维度高分组只占20%模型把所有样本都预测成低分组准确率也有80%。你会觉得效果不错实际上模型什么都没学会。正确的评估姿势是看每个维度的AUC和宏平均F1。AUC不依赖分类阈值能反映排序能力F1则结合了精确率和召回率能看出正类样本能不能被找出来。我的模型最终在验证集上五个维度的AUC落在0.71到0.79之间宏平均F1稳定在0.78这个水平在人格预测领域属于可用的中上水平。你要记住性格预测天花板本身是有限的文本线索再强也只是间接信号别拿它和意图识别那种任务的标准去比。5. 真实场景下的踩坑复盘与改进方向模型跑通只是第一步。真正落地到业务场景里还有几个坑必须提前想清楚。5.1 类别不平衡class_weight和采样策略我最终拿到的一个自采数据集里尽责性维度高分组只占18%而神经质维度高分组占39%。如果直接用原始分布训练模型会倾向于把所有样本预测成多数类。一个通用解法是class_weight。你给少数类一个更高的权重让模型在计算loss时对少数类的错误更敏感。维基百科和Keras文档都说得很清楚代码实现也不复杂from sklearn.utils.class_weight import compute_class_weight import numpy as np # 按维度依次计算 class_weights {} for i in range(5): classes np.unique(y_train[:, i]) weights compute_class_weight(balanced, classesclasses, yy_train[:, i]) class_weights[i] {classes[j]: weights[j] for j in range(len(classes))}另一种思路是过采样少数类样本到接近多数类水平但因为我们的样本是用户级文档过采样会产生重复样本增加过拟合风险我实测下来效果不如class_weight稳定。如果时间充裕可以两种都跑一遍对比验证集AUC。5.2 无效文本与用户级文档的噪声聚合用户文档时有另一个隐蔽问题不是所有文本都是用户自己写的。转发内容、营销推广语、歌词、影视台词这些占了大头时用户的真实表达被稀释了。我的清洗策略是在聚合前先按类型过滤一次性内容超过两个URL的帖子直接删除转发标记明显的删除纯标签内容如#xx话题#删除。保留用户自己写的生活化、口语化内容。如果一份用户文档经过过滤后剩余内容少于200字直接丢掉这个样本因为统计信号不足硬塞进去只会变成噪声。5.3 后续扩展方向这套DNN框架最大的价值是它留了清晰的演进路径。如果你后续拿到了更大规模的数据可以保留现有网络结构只把输入特征从TF-IDF换成预训练模型的文本Embedding网络尾部完全不用改。如果希望进一步利用五个维度之间的相关性比如尽责性和神经质之间存在稳定的负相关趋势可以把输出层改造成共享表示的多任务结构底层共用一个DNN每个维度单独接一个输出头。我实际使用中的体会是不要试图用DNN去硬刚超大规模语料上的Transformer这不是它的战场。DNN在这类任务里的正确打开方式是快速验证、轻量部署、方便解释。对一个用户量千万级的产品用BERT跑全量用户画像的成本是惊人的而一个TF-IDF加DNN的模型在普通单机上半小时就能跑完全量预测。算这笔账你就知道自己该在什么时候掏出这个方案了。本文还有配套的精品资源点击获取
返回列表