多模态情感分析Python期末大作业完整源码解析
2026/9/16 10:58:37 网站建设 项目流程

简介:面向计算机相关专业学生,尤其是正在准备课程设计、毕业设计或期末大作业的开发者,提供一套完整的Python多模态情感分析项目,包含可直接运行的源码和项目报告。代码覆盖多模态情感分析核心流程,报告阐述实验设计、模型构建与结果分析,可帮助读者理解多模态数据如何被处理并用于情感判别。压缩包共2000个文件,其中1个py主程序、1个md说明文档和1998个txt数据/结果文件,整体大小202.37MB,目录结构清晰,便于逐个模块学习与复用。项目经导师指导并获评审99分,代码完整可直接运行,已有116人学习下载,特别适合需要完整项目参考与实战练习的初学者和进阶学习者。txt文件对应中间数据或输出结果,配合源码与报告,可快速掌握从数据准备到结果呈现的全流程,也能作为二次开发与扩展研究的基础。

1. 多模态情感分析:一份能跑通的 Python 期末大作业源码能给你什么

如果你正在找一份既能交差又能讲清楚原理的期末大作业,这个多模态情感分析项目是个不错的起点。它不是一个装着各类文件的空壳,而是用 Python 写了完整流程:从原始语料到特征构造、模型训练、评估报告,代码结构简单到小白能自己改,但又保留了多模态融合的核心思路。所谓的“多模态”在这份源码里并不是非要视频加音频才算,而是把文本的多种表示方式——比如词频统计、情感词典分值、预训练语义向量——当作不同模态的特征做融合,这种做法在很多实际项目中更常见,也更容易出效果。适合计算机专业做课程设计、期末大作业,或者想练习爬数据、洗数据、建模全流程的同学。下面我按工程顺序拆开讲,每个环节都给出能直接抄的代码和你需要知道的参数含义。

2. 项目文件结构与文本数据预处理

拿到源码包后,第一步不是急着跑 main.py,而是先把文件清单理清楚,否则后面报错了都找不到是哪里的问题。这个项目里各文件的作用可以这样理解:main.py 是入口脚本,负责加载数据、构造特征、训练模型和输出评估结果;txt_total.txt 是合并后的完整语料,每一行是一条待分析的文本;其余以数字命名的 txt 文件如 4226.txt、2902.txt、4094.txt 等,则是按情感类别或数据来源拆分出来的原始文本组,也就是我们做标签映射的依据。你不需要一一阅读这些文件,只要知道它们是为了方便在报告里展示数据分布,实际处理时统一从 txt_total.txt 读取即可。

2.1 用 Python 读取全部 txt 并做标签映射

数字命名的 txt 文件看起来像随机编号,但在这个项目里它们对应了不同的情感类别或不同的数据来源。例如 4226.txt 可能是积极类文本,2902.txt 可能是消极类文本。我们可以在代码里维护一个映射表,把所有文件中的文本行读取出来,再打上对应的标签。

import os from collections import defaultdict # 数字文件名对应的情感标签,0 表示消极,1 表示积极,可以根据实际报告调整 LABEL_MAP = { "4226": 1, "2902": 0, "4094": 1, "4987": 0, "4723": 0, "4486": 1, "1557": 0, } def load_data_from_txt_files(file_dir="data"): texts = [] labels = [] for name, label in LABEL_MAP.items(): file_path = os.path.join(file_dir, f"{name}.txt") with open(file_path, "r", encoding="utf-8") as fp: for line in fp: line = line.strip() if line: texts.append(line) labels.append(label) return texts, labels

这段代码把每个数字 txt 读成一行一行的文本,并给每条文本附上情感标签。需要注意LABEL_MAP的数值含义要和你项目报告里的数据统计保持一致,因为后面训练模型时,标签的分布直接决定评估指标的可信度。用encoding="utf-8"是因为这些文本很可能是网络爬取或公开语料,Windows 下默认的 gbk 容易在边界字符上报错,统一指明白可以避免一半的编码问题。

2.2 合并语料的去重与清洗策略

当从多个 txt 文件读入文本后,往往会出现重复内容,尤其当数字命名文件之间有交叉时。我的做法是先用set去重,再做一层简单清洗,避免把 URL、多余标点等噪声带进特征里。txt_total.txt在这个项目里是已经合并好的版本,但自己动手时,清洗逻辑建议写在 main.py 里,方便换数据直接复用。

import re def clean_text(text): text = text.lower() text = re.sub(r"http\S+", "", text) # 去掉 URL text = re.sub(r"[^\w\u4e00-\u9fa5]", " ", text) # 保留字母数字和中文 text = re.sub(r"\s+", " ", text).strip() return text def load_total_data(total_file="txt_total.txt"): unique_lines = set() with open(total_file, "r", encoding="utf-8") as fp: for line in fp: line = clean_text(line) if line: unique_lines.add(line) text_list = list(unique_lines) return text_list

这里要注意,set去重之后文本顺序会变化,所以在后续划分训练集和测试集时,必须用固定的随机种子打乱,否则每次运行结果都不一样。clean_text\u4e00-\u9fa5是中文范围,如果你处理的是纯英文语料,可以去掉这部分,但要保留数字和字母。清洗这一步看似简单,却直接影响 TF-IDF 的词表质量和情感词典匹配率。

2.3 标签不平衡的处理思路

用数字命名 txt 文件做分类时,不同文件的文本行数差别可能很大,这就导致标签分布不均衡。比如 4226.txt 有 800 行,1557.txt 只有 200 行。如果直接训练,模型会偏向多数类。常规处理方式是观察标签分布后选择加权损失函数,或使用train_test_splitstratify参数做分层抽样。

from sklearn.model_selection import train_test_split texts, labels = load_data_from_txt_files() X_train, X_test, y_train, y_test = train_test_split( texts, labels, test_size=0.2, random_state=42, stratify=labels ) print("训练集大小:", len(X_train), "测试集大小:", len(X_test))

使用stratify=labels可以保证训练集和测试集中积极与消极文本的比例接近原始数据。这一行是很多课程设计里容易漏掉的地方,但却是答辩时老师最容易问到的点:你的数据划分是否具有代表性。如果你报告里描述了数据分布,那么这段代码就是直接佐证。

3. 多模态特征构造:从统计特征到语义向量的融合

在这个项目里,所谓的多模态并不是真的输入图像和文本,而是把同一个文本通过不同方式表示成多种特征,这种思路在工业界也常称为多视图或特征级融合。我倾向于提取三类特征:TF-IDF 词频特征、情感词典统计特征、预训练语义向量特征。三者分别从词面、情感倾向、上下文语义三个角度描述文本,互补性很强。下面详细说明每一种特征的构造方式,以及融合时需要注意的维度问题。

3.1 TF-IDF 特征:理解基础词面信息

TF-IDF 是文本分类中最朴素的表示方式,它统计词语在当前文本中的重要性。这个项目可以直接用 TfidfVectorizer,不需要自己实现算法,但参数需要根据语料规模调。

from sklearn.feature_extraction.text import TfidfVectorizer tfidf_vectorizer = TfidfVectorizer( max_features=8000, ngram_range=(1, 2), min_df=2, max_df=0.8, sublinear_tf=True ) X_tfidf_train = tfidf_vectorizer.fit_transform(X_train) X_tfidf_test = tfidf_vectorizer.transform(X_test) print("TF-IDF 训练集维度:", X_tfidf_train.shape)

max_features=8000限制词表大小,防止维度爆炸;ngram_range=(1, 2)让模型能捕捉到「不喜欢」这种双词短语;min_df=2过滤出现次数过少的词,max_df=0.8过滤超过 80% 文档都出现的停用词,sublinear_tf=True则把词频做一次 log 缩放,弱化高频词的主导效应。注意测试集只能用transform,不能用fit_transform,否则测试集信息会泄漏到训练过程中。

3.2 情感词典特征:把先验知识当成一个模态

情感词典是一种零训练特征,它不依赖标签,只依赖先验知识。比如我们可以构造一个简单的积极词集合和消极词集合,统计每条文本中积极词和消极词出现的次数、比例,以及情感词的个数。这样得到的特征虽然维度低,但解释性强,报告里能画图展示。

positive_words = set(["好", "喜欢", "赞", "优秀", "推荐"]) negative_words = set(["差", "垃圾", "讨厌", "失望", "坑"]) def sentiment_score(text_words): pos_score = sum(1 for w in text_words if w in positive_words) neg_score = sum(1 for w in text_words if w in negative_words) return [pos_score, neg_score, pos_score - neg_score] def build_senti_features(texts): features = [] for t in texts: word_list = t.split() features.append(sentiment_score(word_list)) return features

这里的情感词典是演示用的,真实项目里建议使用成熟的词典资源,比如知网 HowNet 情感词典或 BosonNLP 情感词典,把词表文件读进来做集合。实际使用时,你还需要考虑否定词的影响,比如「不推荐」这个词组,需要回退到 TF-IDF 的 ngram 特征去捕捉。情感词典特征的输出是一个 3 维向量,字段分别是积极词数、消极词数、情感差值,后续可以直接与 TF-IDF 特征水平拼接。

3.3 预训练语义向量:用小型 BERT 或 Word2Vec 补上下文

TF-IDF 是稀疏的,情感词典是人工的,预训练语义向量则能提供稠密的上下文表示。考虑到期末环境一般没有 GPU,建议使用小型模型如sentence-transformersparaphrase-MiniLM-L6-v2,或者直接用 gensim 加载 word2vec 后对句子中词向量取平均。这里给出用 sentence-transformers 的方式,因为 API 简单,效果稳定。

from sentence_transformers import SentenceTransformer model = SentenceTransformer("paraphrase-MiniLM-L6-v2") X_vec_train = model.encode(X_train, batch_size=32, show_progress_bar=False) X_vec_test = model.encode(X_test, batch_size=32, show_progress_bar=False) print("语义向量维度:", X_vec_train.shape)

这段代码会输出一条文本对应一个 384 维的向量。如果安装该包有困难,也可以退回到 word2vec 词向量平均,但效果会略差。batch_size=32控制一次编码的文本数量,数值可以根据内存调整,编码中文文本时要把模型换成多语言版本,例如paraphrase-multilingual-MiniLM-L12-v2,否则中文会变成未知词。

3.4 特征融合:拼接与维度归一化

多模态融合最简单的做法是特征拼接,但等 TF-IDF 的 8000 维和语义向量的 384 维直接拼在一起,语义向量会被淹没。我通常先对 TF-IDF 特征做 PCA 降维到 100 维,再和情感词典特征、语义向量拼接,这样各部分贡献相对均衡。

from sklearn.decomposition import TruncatedSVD from sklearn.preprocessing import StandardScaler svd = TruncatedSVD(n_components=100, random_state=42) X_tfidf_pca_train = svd.fit_transform(X_tfidf_train) X_tfidf_pca_test = svd.transform(X_tfidf_test) scaler = StandardScaler() X_tfidf_pca_train = scaler.fit_transform(X_tfidf_pca_train) X_tfidf_pca_test = scaler.transform(X_tfidf_pca_test) X_senti_train = build_senti_features(X_train) X_senti_test = build_senti_features(X_test) import numpy as np X_all_train = np.hstack([X_tfidf_pca_train, X_senti_train, X_vec_train]) X_all_test = np.hstack([X_tfidf_pca_test, X_senti_test, X_vec_test])

TruncatedSVD适合稀疏矩阵降维,StandardScaler让各维度处于同一量级,避免距离计算被大数值特征主导。最终特征维度是 100 + 3 + 384 = 487 维,这个规模用普通逻辑回归也能跑,用 MLP 也不会太慢。特征融合这部分,是项目报告里最能体现你对多模态理解的地方:不同模态的特征在数值分布、语义粒度上都有差异,直接拼接前必须归一化。

4. 模型训练与评估:用几行代码拿到完整指标

多模态特征构造好之后,训练模型反而是最简单的一步。考虑到课程设计的定位,选择逻辑回归作为基线、MLP 作为对比模型比较合适,既能代表传统方法又能体现神经网络的引入。这个项目源码里没有太重型的深度学习框架,主要依赖 sklearn,所以即使没有独立显卡也能在十几秒内跑完。

4.1 逻辑回归与 MLP 对比实现

逻辑回归对于小规模稀疏特征非常有效,MLP 则能捕捉特征间的非线性关系。我们用 sklearn 的 Pipeline 封装好特征处理,然后分别训练两个模型,方便在报告里做对比表。

from sklearn.linear_model import LogisticRegression from sklearn.neural_network import MLPClassifier from sklearn.metrics import accuracy_score, classification_report, confusion_matrix clf_lr = LogisticRegression(max_iter=1000, C=1.0, random_state=42) clf_lr.fit(X_all_train, y_train) mlp = MLPClassifier(hidden_layer_sizes=(128, 64), activation="relu", solver="adam", max_iter=500, random_state=42) mlp.fit(X_all_train, y_train) for clf, name in [(clf_lr, "Logistic Regression"), (mlp, "MLP")]: y_pred = clf.predict(X_all_test) acc = accuracy_score(y_test, y_pred) print(f"{name} 准确率: {acc:.4f}") print(classification_report(y_test, y_pred, target_names=["negative", "positive"]))

逻辑回归的C=1.0控制正则化强度,C 越小正则化越强,如果你发现训练集与测试集准确率差距大,可以把 C 调小一些。MLP 的hidden_layer_sizes=(128, 64)表示两个隐藏层,分别是 128 和 64 个神经元,这个容量对 487 维特征来说足够,再大就容易过拟合。max_iter=500保证收敛,sklearn 默认的迭代次数对逻辑回归可能不够,所以手动写清楚。

4.2 评估指标怎么看:准确率、宏 F1 与混淆矩阵

课程设计报告里如果只写准确率会显得单薄。多模态情感分析通常类别可能不止两类,或者数据存在不平衡,所以建议把宏 F1(macro F1)也列出来。宏 F1 对所有类别单独计算 F1 再取平均,能更公平地反映模型在少数类上的表现。

from sklearn.metrics import f1_score for clf, name in [(clr_lr, "LR"), (mlp, "MLP")]: y_pred = clf.predict(X_all_test) macro_f1 = f1_score(y_test, y_pred, average="macro") print(f"{name} 宏 F1: {macro_f1:.4f}")

如果你把代码中的标签从 0/1 扩展成 3 类或 5 类情感,比如乐、怒、哀、惧、惊,那么average="macro"就更重要。混淆矩阵则能直观展示哪些情感容易被混淆,在报告里用一个matplotlib热力图就能呈现,这部分可以结合项目的 99 分选题背景,重点说明自己做了类别层面分析。

4.3 特征重要性解释与报告素材生成

答辩时老师通常会问“为什么这个特征有效”,而不是“你怎么调的包”。对于逻辑回归,可以用系数绝对值来近似特征重要性,但注意由于特征做了 PCA,系数无法直接映射回原始词表。替代方案是针对 TF-IDF 原始特征单独训练一个逻辑回归,输出权重最高的词。

clf_word = LogisticRegression(max_iter=1000) clf_word.fit(X_tfidf_train, y_train) feat_names = tfidf_vectorizer.get_feature_names_out() import numpy as np coef = clf_word.coef_[0] top_indices = np.argsort(coef)[-20:] for idx in top_indices: print(f"积极词: {feat_names[idx]}, 权重: {coef[idx]:.4f}")

这里get_feature_names_out()返回 TF-IDF 矩阵对应的词表顺序,coef_[0]是从逻辑回归提取的类别 1 的权重向量,argsort拿到权重最高的索引。输出的词可以直接放进报告作为案例分析。要注意,这一步单独使用了原始 TF-IDF,与前面融合模型无关,只是用于解释文本的情感倾向特征,不是最终模型的特征重要性。

5. 扩展、验证与排错:多模态项目还能怎么加料

走到这一步,你的源码已经能跑通整个流程,但课程设计要想拿高分,还需要在细节上做扩展。一个很自然的扩展方向是把“多模态”往外扩一层:在现有文本模态基础上,加入图片或语音的情感标注作为辅助信号。例如你手头有用户评论对应的星级图片,可以把星级数值归一化后作为一个额外特征列拼接进X_senti_train的末尾。这里需要修改文件加载逻辑,单独读取一个star_level.txt,然后做np.hstack拼接。

import numpy as np star_train = np.random.rand(len(X_all_train), 1) # 模拟星级特征 X_all_train_plus = np.hstack([X_all_train, star_train])

这只是演示思路,实际使用时你应当按照报告里的多模态设定,准备好对应的数值特征。另外,你也可以尝试用GridSearchCV搜索 MLP 的alpha(L2 惩罚系数)和hidden_layer_sizes的最优组合,这里给出一个缩减版的参数搜索代码:

from sklearn.model_selection import GridSearchCV param_grid = { "hidden_layer_sizes": [(64,), (128, 64)], "alpha": [0.0001, 0.001, 0.01] } grid = GridSearchCV(MLPClassifier(max_iter=500, random_state=42), param_grid, cv=3, scoring="f1_macro") grid.fit(X_all_train, y_train) print("最优参数:", grid.best_params_)

训练完成后,在模型评估章节,一定要用model.predict(x_test)输出几条错误样本的人工分析。这是排错最直接的方式,比盯指标有用得多。常见错误样本往往集中在文本长度极短或含有大量表情符号的句子上,如果你发现这种情况,直接增加 ngram_range 的上限到 3,或者把表情符号转成文字标签,能立刻改善效果。

除了模型侧,环境配置也是一个高频坑。首次运行前建议用一个干净的虚拟环境:

python -m venv venv source venv/bin/activate # Windows 下为 venv\Scripts\activate pip install scikit-learn sentence-transformers numpy matplotlib

如果sentence_transformers下载预训练模型超时,可以考虑使用清华镜像源,或者改用gensim自带的glove-twitter-25词向量,虽然维度只有 25,但速度更快、离线可用。判定模型是否训练好的标准是:训练集准确率高于测试集 5 个点以内属于正常,超过 10 个点说明过拟合,需要增大alpha正则化参数或减少隐藏层神经元数量。整个项目最值得学习的地方不在于某个复杂模型,而在于特征融合的边界思考:什么时候拼特征、什么时候做归一化、什么时候选不同模型,这些才是面试和答辩里老师真正关注的点。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询