ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

网易云音乐情感分类全流程:从数据集到模型实战

网易云音乐情感分类全流程:从数据集到模型实战 简介这份资源是面向情感分析、文本挖掘与音乐推荐等方向研究者的网易云音乐情感分类数据集。数据约含39.5万条音乐情感标签记录每条都包含歌曲ID、歌单ID与歌曲情感标签三个核心字段可用于构建情感分类模型、开展音乐情绪分析及数据挖掘实验。压缩包共8个文件以3个jsonl格式的训练、校验与测试数据为主体辅以2个json格式的数据集配置与描述文件并附带md说明文档整体体积仅3.06MB轻量易用。目前已有479人学习下载特别适合高校学生、算法工程师及数据科学爱好者作为入门级情感分析实战数据。借助该数据集读者可直接加载划分好的样本开展分类任务也可基于情感标签分布做探索性统计或结合歌单信息研究不同场景下的音乐情绪偏好能有效缩短数据预处理时间聚焦模型设计与结果验证。1. 网易云音乐情感分类数据集.rar不是一份“拿了就能用”的数据做文本情感分类的人手里多少都攒过几个数据集可网易云音乐评论这个方向有点特殊它不像 IMDB 或豆瓣那样有现成的评分兜底评论情感全靠内容本身去推断。你拿到的这个 .rar 压缩包里面大概率是爬下来的歌曲评论带歌曲信息、评论内容、点赞数、时间戳或许还有人工标注的情感标签。它解决的问题很直接——你想训练一个能判断“这条评论是开心、难过还是愤怒”的模型却苦于没有贴合中文互联网语境的训练数据。这份数据真正值钱的地方在于语料的口语化程度。网易云评论里有大量网络用语、缩写、歌词引用和情绪化表达比新闻语料和电商评论更接近真实用户情绪。但别高兴太早这类爬虫数据集通常带三个隐患标签口径不统一、文本噪声大、字段冗余。我用这份数据做过两版情感分类模型踩了不少坑下面把从解压到跑通基线模型的完整路径拆给你看。2. 拆开 .rar 看数据压缩包结构与中文文件名乱码排查拿到 .rar 文件第一反应当然是解压。但如果你在 Windows 上双击用自带工具解压很可能遇到中文文件名乱码。这个压缩包如果是在 Linux 服务器上用rar命令打的包文件名编码可能是 UTF-8而 Windows 的资源管理器默认按 GBK 解码两边对不上就变成一串乱码。更麻烦的是有的压缩包做了分卷缺一个分卷就解压失败。2.1 解压 .rar 的跨平台套路Windows、Linux、macOS 三条命令先看 Windows 下的操作。我一般不依赖右键解压而是用命令行工具这样能看到完整的解压日志方便排查哪个文件出了问题。# Windows 下用 WinRAR 自带的命令行工具 C:\Program Files\WinRAR\UnRAR.exe x -o 网易云音乐情感分类数据集.rar D:\datasets\netease\ # 或者用 7-Zip 的命令行版 C:\Program Files\7-Zip\7z.exe x 网易云音乐情感分类数据集.rar -oD:\datasets\netease\ -yx表示保留完整目录结构解压-o是覆盖已有文件-y是跳过确认提示。如果你用的是 7-Zip注意-o后面直接跟路径不能有空格。这个细节经常让人翻车写脚本批量解压的时候路径带空格就会报“系统找不到指定的路径”。Linux 和 macOS 上没有 WinRAR要么装unrar要么用unar处理编码问题。# Ubuntu / Debian sudo apt-get install unrar unrar x -o 网易云音乐情感分类数据集.rar ./netease/ # macOS 上 unar 对中文编码的兼容更好 brew install unar unar -o ./netease/ 网易云音乐情感分类数据集.rar这里有个值得注意的点unrar是专有格式的解压工具和unzip不是一个东西Linux 默认不一定装了装的时候认准unrar而不是rar。rar是压缩工具不带解压功能很多人装错后就报Unknown option: x。如果解压后文件名还是乱码解决思路不是改代码而是先确认压缩包的编码格式。用ls -l看文件名如果显示的是ж—¶й—ґ这种说明是 UTF-8 被当成了 GBK 显示。macOS 下用unar会自动检测编码Windows 下可以用 7-Zip 的-mcp参数指定编码。不过我见过最省事的办法是把压缩包传到 Linux 服务器上解压然后用convmv批量转文件名编码。2.2 解压之后先别急着训识别数据文件的字段结构与规模解压只是开胃菜。我习惯先用一两个命令摸清目录结构和文件大小再决定从哪个文件开始。# 看目录结构避免文件散落一地 find netease/ -type f | head -50 # 看文件大小和数据行数心里有个底 du -sh netease/*.csv netease/*.json 2/dev/null wc -l netease/*.csv 2/dev/null这段命令的价值在于让你在写代码之前就知道这份数据大概是什么量级。如果只有一个几十 MB 的 CSV说明可能是纯文本评论如果有一堆 JSON 切片说明可能是按歌曲或按用户分块的。wc -l对 JSON 文件没意义但能帮你快速定位 CSV 的行数。接下来是核心动作用 Python 看一下字段结构。我看数据第一眼永远先跑这一段import pandas as pd # 先读前 5 行字段名和数据样例一眼就能看完 df pd.read_csv(netease/comments.csv, nrows5) print(df.columns.tolist()) print(df.head()) # 再统计缺失值和数据类型 df_full pd.read_csv(netease/comments.csv, low_memoryFalse) print(df_full.info()) print(df_full.isnull().sum())这段代码有两个关键参数nrows5是快速预览low_memoryFalse表示一次性全读入内存避免 Pandas 因为类型推断不一致而警告。df.info()里的Dtype列能告诉你哪些字段是整数、哪些是字符串如果评论内容那一列被识别成了float64说明里面有大量空值清洗时要重点处理。字段结构搞清楚了你手里就有了完整的“地图”。评论数据的常见字段无外乎comment_id、user_id、comment_text、like_count、reply_count、created_at、song_name、artist以及最重要的sentiment_label。如果标签列存在你要检查它的取值集合如果不存在这份数据就只是一个无监督语料库得自己想办法打标。检查取值集合用一行df[sentiment_label].value_counts()就够了能直接看出标签分布是否失衡。3. 从评论到标签数据清洗、标注口径与基线模型选择数据解压完、字段看清楚之后真正的技术活才开始。情感分类的难点从来不在模型选型而在于你怎么定义“情感”这件事本身。网易云评论里“我哭了”这句词可能是在感慨歌词感人也可能是在讽刺编曲拉胯同一个词在不同上下文里完全是相反的情感极性。所以先定标注口径再谈模型。3.1 三分类还是五分类标注口径决定模型上限常见的标注方案有两种。三分类是“正向 / 负向 / 中性”简单实用标注一致性高人工标注时最容易达成共识。五分类则是在此基础上拆出“喜欢、感动、悲伤、愤怒、无感”这样的细粒度情感更细致但也更主观。我在实际项目里用过一套四分类的折中方案“正向 / 负向 / 中性 / 歌词引用”——网易云评论里大量用户在刷歌词歌词本身的情感经常和用户想要表达的情绪是两回事把它单独拎出来能让模型学得更干净。标注口径一旦定错后面所有工作都是在垃圾上盖楼。比如“哈哈哈哈哈哈哈”和“哈哈”到底算正向还是中性“呵呵”算负向还是中性这些边界案例在标注指南里必须提前写好。我自己经历过一次惨痛教训标注员把“好听”标为正向把“好听”标为中性但模型看到“好听”后面跟个问号就被判错了原因是训练时根本没把标点符号纳入清洗流程。情感分类的数据清洗比通用文本清洗严格得多。中文不擅长分词但更头疼的是那些无意义的字符。我建议的清洗顺序是去 HTML 实体、去 用户、去 URL、去连续重复标点、表情符号统一转文字。表情符号这个动作很重要“”在中文语境里几乎可以当作情感标签的强特征直接删掉太可惜转成[笑]这样的占位符反而有帮助。3.2 用 Python 跑通最小可用的情感分类线从 TF-IDF 到预训练模型清洗做完第一版基线模型不需要上 BERT先用 TF-IDF 加逻辑回归跑通全流程。这个组合的好处是训练快、可解释性强、方便排查数据问题。import jieba import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report df pd.read_csv(netease/comments_clean.csv) # 分词 停用词过滤TF-IDF 的特征空间会小很多 def tokenize(text): return [w for w in jieba.lcut(text) if w.strip() and w not in stopwords] vectorizer TfidfVectorizer(tokenizertokenize, max_features20000, ngram_range(1, 2)) X vectorizer.fit_transform(df[comment_text]) y df[sentiment_label] # 切分时设置 stratify保持训练集和测试集的标签分布一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) clf LogisticRegression(max_iter1000, C1.0, class_weightbalanced) clf.fit(X_train, y_train) y_pred clf.predict(X_test) print(classification_report(y_test, y_pred))这里三个参数值得单独说。max_features20000是 TF-IDF 特征量的上限网易云评论的词汇量大设太大会导致稀疏矩阵爆炸、模型训练变慢设太小又丢失低频关键词。ngram_range(1, 2)让模型同时看单个词和相邻词组合对“不好听”“太顶了”这类短语尤其有效。class_weightbalanced处理类别不均衡如果你的数据里“愤怒”评论只有“正向”的十分之一这个参数能自动加大少数类的惩罚权重防止模型把什么都预测成多数类。跑完看classification_report里的 F1 值。一个合理的情感分类基线宏平均 F1 应该在 0.7 以上如果你连 0.6 都不到大概率不是模型问题而是标签噪声太大或者特征清洗有问题。这时候返回去重新看数据不要调参硬扛。基线跑通之后升级到 BERT 系模型是水到渠成的事。常见做法是用transformers库加载一个中文预训练模型然后做序列分类微调。from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments import torch from torch.utils.data import Dataset tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) model AutoModelForSequenceClassification.from_pretrained( bert-base-chinese, num_labels3 ) class CommentDataset(Dataset): def __init__(self, texts, labels, tokenizer, max_len128): self.texts texts self.labels labels self.tokenizer tokenizer self.max_len max_len def __len__(self): return len(self.texts) def __getitem__(self, idx): encoded self.tokenizer( self.texts[idx], truncationTrue, max_lengthself.max_len, paddingmax_length, return_tensorspt ) return { input_ids: encoded[input_ids].squeeze(0), attention_mask: encoded[attention_mask].squeeze(0), labels: torch.tensor(self.labels[idx], dtypetorch.long), } train_dataset CommentDataset(X_train_texts, y_train.values, tokenizer)max_len128是评论场景的惯用值网易云评论很少超过 50 个字设太长浪费显存设太短切掉语义。paddingmax_length让 batch 内所有序列长度一致这是 Trainer 处理 batch 的必要条件。如果显存不够把max_len降到 64效果通常不会差太多因为评论的核心信息往往集中在前半句。4. 训练与评估中的 4 个避坑点数据泄漏、类别不均衡、文本清洗与标签噪声模型能跑通只是第一步真正决定项目能不能落地的是这些坑你有没有绕过去。我在这份数据上踩过的坑比顺利跑通的部分多得多。4.1 数据泄漏清洗和编码放在切分之后现象训练时准确率接近 95%测试集表现也不错但一到真实场景就全面崩盘准确率掉到 60% 以下。原因我在切分训练集和测试集之前就做了 TF-IDF 向量化导致测试集的信息在训练时已经被模型看到了。具体来说fit_transform是在全量数据上做的fit阶段学到的词表包含测试集的词汇分布这相当于考试时把答案带进了考场。解决把向量化拆成两步先在训练集上fit再用同一个模型转换测试集。X_train, X_test train_test_split(df[comment_text], test_size0.2, random_state42) vectorizer.fit(X_train) # 只用训练集学词表 X_train_vec vectorizer.transform(X_train) X_test_vec vectorizer.transform(X_test) # 测试集不参与 fit同理适用于文本清洗如果你根据全量数据的统计结果决定“要把数字全部删掉”这也算一种泄漏。正确做法是清洗规则一经确定便不再改动比如“去数字”这个规则是从训练集统计出来的就要原封不动应用到测试集和之后的真实数据上。4.2 类别不均衡准确率骗人F1 和混淆矩阵才说实话现象模型准确率 0.86看起来很优秀看 confusion matrix 才发现“愤怒”这一类被完全忽略所有样本都预测成了“中性”。准确率 0.86 是因为“中性”在数据集中本来就占了 86%。原因我最初只看准确率没看分类报告里的 recall 和 F1。在类别不均衡的数据集上准确率是一个几乎没意义的指标模型只要永远预测多数类就能拿到高分。解决换成宏平均 F1 作为主要评估指标同时强制打印混淆矩阵。from sklearn.metrics import confusion_matrix, f1_score cm confusion_matrix(y_test, y_pred) print(cm) macro_f1 f1_score(y_test, y_pred, averagemacro) print(fMacro F1: {macro_f1:.4f})调参时优先用class_weightbalanced或者对少数类做上采样而不是简单把重复样本拼进训练集。上采样会让模型见过更多相同样本但也容易过拟合效果不如直接用class_weight来得稳定。这个经验是我多轮实验后排掉imbalanced-learn库的 SMOTE 之后才确定的——评论这种高维稀疏文本数据SMOTE 生成的是近邻插值词向量空间里插出来的“新文本”语义不成立。4.3 文本清洗翻车表情、用户、HTML 实体和“地域黑”式的脏词现象模型在新数据上频繁把含表情符号的评论判为负向而实际上表情表达的是正向情绪。原因清洗正则写得过于粗暴把所有非中英文数字的字符全部删掉了包括“”“❤️”这类强情感信号。我最初图省事用re.sub([^\u4e00-\u9fa5a-zA-Z0-9], , text)一刀切后果是模型只能看到纯文字。网易云的评论文化里表情是情绪表达的主体删掉它们等于把测试题答案涂掉了。解决单独把表情符号抓出来转成文字占位符再删掉标点import re emoji_map { : 大笑, : 大哭, ❤: 爱心, : 点赞, : 愤怒, : 祈祷, } def clean_text(text): # 按顺序处理先转表情再删其他符号 for emoji, word in emoji_map.items(): text text.replace(emoji, f {word} ) text re.sub(r\w, , text) text re.sub(rhttps?://\S, , text) text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9\s], , text) return re.sub(r\s, , text).strip()里面re.sub(r\w, , text)是去 用户后跟的用户名这个写法对中文用户名也能生效因为它匹配的是后面连续的字母数字下划线。https?://\S是 URL 的常用匹配\S吃掉所有非空白字符避免 URL 在文本里留一半残渣。清洗规则按“保留信息”而不是“删干净”的原则写这是我从这次翻车里学到的血泪经验。4.4 标签噪声训练集损失不降反升的隐形元凶现象训练过程中无论是 TF-IDF 还是 BERT训练损失在高位震荡验证集 F1 卡在 0.5 左右上不去。原因数据里的“中性”标签很多是标注员偷懒打的或者爬虫抓取的原始数据里根本没有标签有人拿关键词匹配粗暴生成了 label。比如“心情不好”被匹配成“负向”但“心情不好所以来听歌”实际是“中性偏正向”——这种标签矛盾会让模型无所适从。解决先算每条样本的预测置信度把低置信度的样本抽出来人工复核。prob clf.predict_proba(X_train_vec) confidence prob.max(axis1) low_conf_idx confidence 0.6 # 导出低置信度样本人工复核标签 low_conf_samples df.loc[low_conf_idx, [comment_text, sentiment_label]] low_conf_samples[confidence] confidence[low_conf_idx] low_conf_samples.to_csv(low_conf_review.csv, indexFalse)predict_proba返回每个类别的概率矩阵max(axis1)取最大概率作为置信度。我把 0.6 作为阈值低于这个值的样本要么是边界文本、要么是标签标错。人工复核完这些低置信度样本修正错标数据后再重新训练F1 通常能涨 2 到 5 个点。这个过程我在好几个文本分类项目里反复验证过比换模型架构值钱得多。5. 验证这份数据到底行不行留出验证集与置信度抽检法讲一个管理和验证这类数据集的技巧。我拿到任何一份情感分类数据第一件事永远是切一个“封存验证集”——从全量数据里随机抽出 1000 条直接存成holdout.csv不参与任何训练和调参只在模型最终交付时跑一次。别急着用这份封存集去调参一旦它影响了你的决策它就不干净了这就是后悔药留不住的原因。验证分三步走。第一步看整体指标宏平均 F1 和加权 F1 都要看。第二步打开混淆矩阵找系统性错误如果“愤怒”经常被误判成“悲伤”说明这两个类别的训练样本在标注时就混杂了需要回看原始标注规则。第三步做标签级抽检——从每个类别里随机取 20 条预测结果一条一条人工读。这一步最费时间但它是唯一能确认“模型学到了情感而不是学到了词语关联”的办法。很多做文本分类的人习惯只盯着验证集 F1 不断调参直到模型“看起来很完美”。但我经历过太多次验证集高分、上线即翻车的案例根源都在数据本身。所以我会在工具链里固化这个小流程每次训练完自动导出低置信度样本每周花半小时人工复核把修正后的标签重新喂回模型。这份网易云音乐情感分类数据集本身的质量决定了你的模型上限而你把不把数据当回事决定了你能触及上线之后的天花板。希望这份思路能帮到你。本文还有配套的精品资源点击获取
返回列表