├── cookie.txt ├── 多视频评论信息.xls ├── requirements.txt ├── 主文件中的代码 ├── mask.png ├── 评论信息.xls ├── 评论信息.xlsx ├── 评论信息1.xls ├── 创作者评估报告.xlsx ├── 情感输出结果.xlsx ├── 评论信息_清洗去重后.xlsx ├── 创作者评估报告_bert.xlsx ├── 情感输出结果_bert.xlsx ├── word_cloud_image.png ├── sentiment.bilibili_comment.3 ├── __pycache__ │ ├── Data_cleaning.cpython-311.pyc │ ├── Data_crawling.cpython-311.pyc │ ├── bert_analysis.cpython-311.pyc │ ├── Data_visualization.cpython-311.pyc │ └── Word_cloud_image_generation.cpython-311.pyc ├── Data_cleaning.py ├── cookie.txt ├── Word_cloud_image_generation.py ├── bert_analysis.py ├── Data_crawling.py ├── main_file.py ├── Data_visualization.py ├── hit_stopwords.txt └── 所有可视化图表.html ├── 评论情感分析结果_三分类.xlsx ├── 评论情感分析结果_三分类_人工纠错.xlsx ├── 评论情感分析结果_三分类_微调后bert模型批量预测.xlsx ├── snownlp计算正确率.py ├── 计算置信度占比.py ├── README.md ├── Data_crawling.py ├── README-english.md ├── 模型三分类.py ├── 模型三分类_微调后的bert模型.py ├── 数据爬取.py └── 情感分析_bert微调_demo (1).ipynb /cookie.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /多视频评论信息.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/多视频评论信息.xls -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/requirements.txt -------------------------------------------------------------------------------- /主文件中的代码/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/mask.png -------------------------------------------------------------------------------- /主文件中的代码/评论信息.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/评论信息.xls -------------------------------------------------------------------------------- /主文件中的代码/评论信息.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/评论信息.xlsx -------------------------------------------------------------------------------- /主文件中的代码/评论信息1.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/评论信息1.xls -------------------------------------------------------------------------------- /评论情感分析结果_三分类.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/评论情感分析结果_三分类.xlsx -------------------------------------------------------------------------------- /主文件中的代码/创作者评估报告.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/创作者评估报告.xlsx -------------------------------------------------------------------------------- /主文件中的代码/情感输出结果.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/情感输出结果.xlsx -------------------------------------------------------------------------------- /主文件中的代码/评论信息_清洗去重后.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/评论信息_清洗去重后.xlsx -------------------------------------------------------------------------------- /评论情感分析结果_三分类_人工纠错.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/评论情感分析结果_三分类_人工纠错.xlsx -------------------------------------------------------------------------------- /主文件中的代码/创作者评估报告_bert.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/创作者评估报告_bert.xlsx -------------------------------------------------------------------------------- /主文件中的代码/情感输出结果_bert.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/情感输出结果_bert.xlsx -------------------------------------------------------------------------------- /主文件中的代码/word_cloud_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/word_cloud_image.png -------------------------------------------------------------------------------- /评论情感分析结果_三分类_微调后bert模型批量预测.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/评论情感分析结果_三分类_微调后bert模型批量预测.xlsx -------------------------------------------------------------------------------- /主文件中的代码/sentiment.bilibili_comment.3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/sentiment.bilibili_comment.3 -------------------------------------------------------------------------------- /主文件中的代码/__pycache__/Data_cleaning.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/__pycache__/Data_cleaning.cpython-311.pyc -------------------------------------------------------------------------------- /主文件中的代码/__pycache__/Data_crawling.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/__pycache__/Data_crawling.cpython-311.pyc -------------------------------------------------------------------------------- /主文件中的代码/__pycache__/bert_analysis.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/__pycache__/bert_analysis.cpython-311.pyc -------------------------------------------------------------------------------- /主文件中的代码/__pycache__/Data_visualization.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/__pycache__/Data_visualization.cpython-311.pyc -------------------------------------------------------------------------------- /主文件中的代码/__pycache__/Word_cloud_image_generation.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ILZFLNO02/Sentiment-analysis-of-Bilibili-comments-based-on-model-fine-tuning/HEAD/主文件中的代码/__pycache__/Word_cloud_image_generation.cpython-311.pyc -------------------------------------------------------------------------------- /snownlp计算正确率.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from snownlp import SnowNLP 3 | from sklearn.metrics import accuracy_score, f1_score 4 | 5 | # 读取数据 6 | df = pd.read_excel(r'e:\bilibili_train\评论情感分析结果_三分类_人工纠错.xlsx') 7 | 8 | # 标签映射(首字母大写) 9 | label_map = {"Negative": 0, "Neutral": 1, "Positive": 2} 10 | 11 | # 只保留有效标签的行 12 | df = df[df['emotion'].isin(label_map.keys())] 13 | 14 | labels = [label_map[x] for x in df['emotion']] 15 | comments = df['comment'].astype(str).tolist() 16 | 17 | # SnowNLP预测 18 | def snownlp_predict(text): 19 | s = SnowNLP(text) 20 | score = s.sentiments 21 | # 三分类阈值划分 22 | if score > 0.6: 23 | return 2 # Positive 24 | elif score < 0.4: 25 | return 0 # Negative 26 | else: 27 | return 1 # Neutral 28 | 29 | preds = [snownlp_predict(c) for c in comments] 30 | 31 | # 计算准确率和F1值 32 | acc = accuracy_score(labels, preds) 33 | f1 = f1_score(labels, preds, average='macro') 34 | 35 | print(f"SnowNLP三分类准确率: {acc:.4f}") 36 | print(f"SnowNLP三分类F1值: {f1:.4f}") -------------------------------------------------------------------------------- /主文件中的代码/Data_cleaning.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import re 3 | # from tkinter import messagebox # <-- 注释掉或删除 tkinter messagebox 的导入,因为不再需要 4 | 5 | def clean_chinese_characters(filepath): 6 | # 定义一个函数来保留中文字符 7 | def keep_chinese_characters(text): 8 | # 使用正则表达式匹配中文字符 9 | chinese_characters = re.findall(r'[\u4e00-\u9fff]+', text) 10 | # 读取停用词文件 11 | with open('hit_stopwords.txt', 'r', encoding='utf-8') as f: 12 | stopwords = [word.strip() for word in f.readlines()] 13 | # 将中文字符分词并去除停用词 14 | words = [word for word in ''.join(chinese_characters).split() if word not in stopwords] 15 | # 将处理后的词语连接起来 16 | return ''.join(words) 17 | # 读取Excel文件 18 | data = pd.read_excel(filepath) 19 | # 删除整行重复的评论信息 20 | data.drop_duplicates(subset='评论内容', keep='first', inplace=True) 21 | # 清理'评论内容'列,只保留中文字符 22 | data['评论内容'] = data['评论内容'].apply(keep_chinese_characters) 23 | # 将清理后的DataFrame写入新的Excel文件 24 | cleaned_filepath = filepath.replace('.xls', '_清洗去重后.xlsx') 25 | data.to_excel(cleaned_filepath, index=False) 26 | return cleaned_filepath 27 | 28 | #clean_chinese_characters("评论信息.xls") # 你可以保留或注释掉这行测试代码 -------------------------------------------------------------------------------- /主文件中的代码/cookie.txt: -------------------------------------------------------------------------------- 1 | buvid4=8D4A2ADE-CB95-88DF-FD3B-CC9F77BE244869063-022012421-Vk7oLekZ8O%2BWwDC%2BideQ6A%3D%3D; header_theme_version=CLOSE; enable_web_push=DISABLE; CURRENT_BLACKGAP=0; hit-dyn-v2=1; CURRENT_QUALITY=80; is-2022-channel=1; _uuid=9254D896-12710-2A22-6410C-6A56C788799863056infoc; buvid3=AAF79126-1DA9-8B4A-59F3-E32F7485E4B982916infoc; b_nut=1736682182; rpdid=|(J|)Y~Ru)|~0J'u~JmYklkk~; fingerprint=5decd515eea056e6f18864bc721b8fc0; enable_feed_channel=ENABLE; PVID=2; buvid_fp=0d77f3ddc9ac7bcf313f8d0740a2e78b; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDg1NjgyMTAsImlhdCI6MTc0ODMwODk1MCwicGx0IjotMX0.9FNGocmR4vhsioNwnytHOhN85w3suRXvdzpHlMBXc54; bili_ticket_expires=1748568150; bp_t_offset_347760015=1071919151548727296; SESSDATA=23c10d86%2C1763966346%2C56c27%2A51CjA-yFsMqbnmQQU1Hr3fdF2pPtkbr5ydSjAPhOCQ74tETRyhpbXXOfIobQuXL51PbfwSVm1TS21OTThPRzd3S2RiOGFsUHV3WTI1WUh3aUFHenU1UE9ueXhiY1lZbjJXV2w2aW15VWxMVzNPWkhiTF9pSzg3blJ6akVEOTRlNVUtTUxnZktISHdnIIEC; bili_jct=cd08e2cd4583aeabdd0de7c288dcd577; DedeUserID=3493077612235621; DedeUserID__ckMd5=5678ad232817698e; bp_t_offset_3493077612235621=1071949525557444608; b_lsid=E211F56D_1971B006654; bmg_af_switch=1; bmg_src_def_domain=i1.hdslb.com; CURRENT_FNVAL=4048; sid=dz3ucw7y; home_feed_column=4; browser_resolution=339-845 -------------------------------------------------------------------------------- /主文件中的代码/Word_cloud_image_generation.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from wordcloud import WordCloud 3 | import jieba 4 | import matplotlib.pyplot as plt 5 | 6 | def generate_word_cloud(filepath, stopwords_path, mask_image_path, save_image_path): 7 | # 读取Excel文件 8 | data = pd.read_excel(filepath, names=["名字", "性别", "等级", "评论内容", "点赞数"], usecols=[0, 1, 2, 3, 4]) 9 | 10 | # 读取停用词列表 11 | with open(stopwords_path, 'r', encoding='utf-8') as f: 12 | stopwords = f.read().splitlines() 13 | 14 | # 合并所有评论内容为一个字符串 15 | all_comments = ' '.join(data["评论内容"].astype(str)) 16 | 17 | # 分词并去除停用词 18 | data_cut = jieba.lcut(all_comments) 19 | data_after = [i for i in data_cut if i not in stopwords] 20 | 21 | # 统计词频 22 | word_freq = pd.Series(data_after).value_counts() 23 | 24 | # 生成词云图 25 | mask = plt.imread(mask_image_path) 26 | wc = WordCloud(scale=10, 27 | font_path='C:/Windows/Fonts/STXINGKA.TTF', 28 | background_color="white", 29 | mask=mask) 30 | wc.generate_from_frequencies(word_freq.to_dict()) 31 | 32 | # 保存并关闭图形 33 | plt.figure(figsize=(20, 20)) 34 | plt.imshow(wc, interpolation='bilinear') 35 | plt.axis('off') 36 | plt.savefig(save_image_path, bbox_inches='tight', pad_inches=0) 37 | plt.close() # 关闭图形避免内存泄漏 38 | 39 | return save_image_path # 返回保存路径 -------------------------------------------------------------------------------- /主文件中的代码/bert_analysis.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from transformers import BertTokenizer, BertForSequenceClassification 3 | import torch 4 | 5 | # 全局只加载一次模型和分词器 6 | MODEL_PATH = "e:/bilibili_train/bert_train" 7 | DEVICE = "cuda" if torch.cuda.is_available() else "cpu" 8 | tokenizer = BertTokenizer.from_pretrained(MODEL_PATH) 9 | model = BertForSequenceClassification.from_pretrained(MODEL_PATH) 10 | model.to(DEVICE) 11 | model.eval() 12 | 13 | def predict_sentiment(texts, batch_size=64): 14 | results = [] 15 | with torch.no_grad(): 16 | for i in range(0, len(texts), batch_size): 17 | batch_texts = texts[i:i+batch_size] 18 | encodings = tokenizer(batch_texts, padding=True, truncation=True, max_length=256, return_tensors="pt") 19 | input_ids = encodings["input_ids"].to(DEVICE) 20 | attention_mask = encodings["attention_mask"].to(DEVICE) 21 | outputs = model(input_ids=input_ids, attention_mask=attention_mask) 22 | preds = torch.argmax(outputs.logits, dim=1).cpu().numpy() 23 | results.extend(preds) 24 | return results 25 | 26 | def analyze_sentiment(filepath, save_file, model_path=None): 27 | # model_path参数保留兼容性,但实际用全局加载的模型 28 | data = pd.read_excel(filepath, names=["名字", "性别", "等级", "评论内容", "点赞数"], usecols=[0, 1, 2, 3, 4]) 29 | comments = data['评论内容'].astype(str).tolist() 30 | 31 | preds = predict_sentiment(comments) 32 | id2label = {0: "负向", 1: "正向", 2: "中向"} 33 | data['BERT标签'] = [id2label[x] for x in preds] 34 | 35 | data.to_excel(save_file, index=False) 36 | return save_file 37 | 38 | if __name__ == "__main__": 39 | analyze_sentiment( 40 | "评论信息.xlsx", 41 | "情感输出结果_bert.xlsx", 42 | "e:/bilibili_train/bert_train" 43 | ) -------------------------------------------------------------------------------- /计算置信度占比.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # 设置您的Excel文件路径 4 | # file_path = '评论情感分析结果_三分类_人工纠错.xlsx' # 请将这里替换成您的实际文件名和路径 5 | file_path = '评论情感分析结果_三分类_本地模型批量预测.xlsx' # 请将这里替换成您的实际文件名和路径 6 | try: 7 | # 读取Excel文件 8 | df = pd.read_excel(file_path) 9 | 10 | # 确保存在 'score' 列 11 | if 'score' not in df.columns: 12 | print(f"错误:Excel文件 '{file_path}' 中未找到 'score' 列。请检查列名是否正确。") 13 | else: 14 | # 获取 'score' 列的数据 15 | scores = df['score'] 16 | 17 | # 定义分数区间 (bins) 18 | # bins的边界是 [0, 0.1, 0.2, ..., 0.9, 1.0] 19 | # right=False 表示区间是左闭右开 [0, 0.1), [0.1, 0.2) ... [0.9, 1.0) 20 | # 如果您希望区间是左开右闭 (0, 0.1], (0.1, 0.2] ... (0.9, 1.0],请设置 right=True 21 | # 对于0到1的得分,通常包含1,所以定义bins到1.01,或使用right=True包含右边界 22 | bins = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] 23 | # 如果需要包含1.0的区间,可以稍微调整bins的最后一个边界或使用right=True 24 | # bins = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.01] # 稍微超过1.0以包含1.0 25 | 26 | # 使用pd.cut将分数分配到对应的区间 27 | # labels=False 会直接返回区间的整数索引 28 | # include_lowest=True 包含最低的边界(即0.0) 29 | score_bins = pd.cut(scores, bins=bins, right=True, include_lowest=True) # right=True 包含右边界,这样 1.0 会被包含在最后一个区间 30 | 31 | # 计算每个区间的数量 32 | bin_counts = score_bins.value_counts().sort_index() 33 | 34 | # 计算总分数数量(排除可能的NaN值) 35 | total_scores = scores.count() # count()方法会自动排除NaN值 36 | 37 | # 计算每个区间的占比 38 | bin_proportions = bin_counts / total_scores 39 | 40 | # 打印结果 41 | print("分数区间分布及占比:") 42 | print("-" * 30) 43 | for interval, count in bin_counts.items(): 44 | proportion = bin_proportions.get(interval, 0) # 使用.get确保即使没有值也不会报错 45 | print(f"{interval}: 数量 = {count}, 占比 = {proportion:.2%}") # 格式化为百分比 46 | 47 | print("-" * 30) 48 | print(f"总有效分数数量: {total_scores}") 49 | 50 | 51 | except FileNotFoundError: 52 | print(f"错误:未找到文件 '{file_path}'。请检查文件路径是否正确。") 53 | except Exception as e: 54 | print(f"处理过程中发生错误: {e}") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎯 Sentiment Analysis of Bilibili Comments Based on Model Fine-Tuning 2 | 3 | 本项目为青海民族大学本科毕业设计,旨在构建一个**基于情感分析的B站创作者画像系统**,通过**微调中文预训练模型(chinese-bert-wwm-ext)**,实现对用户评论的高精度情感分析,并辅助平台构建健康社区生态。 4 | 5 | ## 🧠 项目简介 6 | 7 | 本项目构建了一个面向B站视频评论的情感分析与可视化系统,主要包括以下几个核心模块: 8 | 9 | * 🔍 **评论数据采集**:通过B站 API 结合用户 Cookie,批量抓取视频评论; 10 | * 🧼 **数据清洗与标注**:自动清洗噪声评论,并结合预训练模型与人工校对构建高质量数据集; 11 | * 🤖 **模型微调与训练**:基于 `chinese-bert-wwm-ext` 模型进行迁移学习,提升评论情感分类准确率; 12 | * 📈 **情感可视化与创作者画像生成**:生成情感分析图表、词云及创作者综合评估报告; 13 | * 🌐 **Web页面演示**:通过 Gradio 构建用户友好的网页交互界面。 14 | 15 | ## 🏗️ 项目结构 16 | 17 | ```bash 18 | 主目录/ 19 | │ 20 | ├── Data_crawling.py # B站评论爬虫脚本(需配合cookie.txt) 21 | ├── Data_cleaning.py # 数据清洗与预处理 22 | ├── bert_analysis.py # 微调后的BERT情感分析主程序 23 | ├── Word_cloud_image_generation.py# 词云图生成 24 | ├── main_file.py # Web 页面入口(基于 Gradio) 25 | ├── cookie.txt # 用户自己的 B站 cookie 26 | ├── requirements.txt # 运行所需Python依赖 27 | ``` 28 | 29 | ## 🧪 模型说明 30 | 31 | * **基座模型**:[`chinese-bert-wwm-ext`](https://huggingface.co/hfl/chinese-bert-wwm-ext)(由哈工大讯飞联合实验室发布) 32 | 33 | * **微调方法**: 34 | 35 | * 采用约 3000 条人工与半自动标注评论数据集; 36 | * 使用 HuggingFace Transformers,设置分类为三类(正向、中立、负向); 37 | * 微调过程使用 `Trainer` 接口,训练7轮后模型准确率达 **80.7%**,F1 分数为 **0.802**; 38 | * 模型对高置信度预测样本占比提升至 **82.9%**,相比原模型(59.2%)大幅优化。 39 | 40 | * **模型下载**:[blank02/Bilibili-comment-fine-tuning-BERT](https://huggingface.co/blank02/Bilibili-comment-fine-tuning-BERT) 41 | 下载后将模型目录放置在与主代码目录同级位置。 42 | * **优化策略** 43 | * 动态学习率调度(峰值2e-5) 44 | * 分层学习率衰减(顶层衰减系数0.8) 45 | * 对抗训练(FGM方法) 46 | * 早停策略(patience=3) 47 | 48 | ## 📊 效果展示 49 | 50 | * **情感分布图**:展示不同性别用户对某创作者评论区情绪的分布; 51 | * **高频词词云**:突出评论区常见关键词,如“好听”、“喜欢”、“春晚”等; 52 | * **创作者评估报告**:基于点赞加权的情感得分,划分创作者为强烈推荐、正向、中立、负向等类型。 53 | 54 | ## ✅ 使用说明 55 | 56 | 1. 安装依赖: 57 | 58 | ```bash 59 | pip install -r requirements.txt 60 | ``` 61 | 2. 将你的 Cookie 复制到 `cookie.txt`; 62 | 3. 运行 `main_file.py` 启动 Web 页面进行交互; 63 | 4. 如需重新微调模型,请运行 `bert_analysis.py` 并使用自己的数据集。 64 | 65 | ## 💡 项目特色 66 | 67 | * 🔧 **中文BERT微调**:针对B站网络评论优化,适应表情、网络流行语、讽刺等复杂语义; 68 | * 📈 **可视化友好**:结合情感分析结果生成词云图和统计图,便于结果解读; 69 | * 🧩 **创作者画像构建**:为内容管理提供量化参考,辅助平台治理与推荐优化。 70 | 71 | 72 | ## ?常见问题 73 | Q: 如何获取B站Cookie? 74 | A: 登录B站后,在开发者工具(F12)的Network标签页获取Cookie值 75 | 76 | Q: 模型支持哪些情感类别? 77 | A: 当前版本支持二分类:积极(positive)/消极(negative) 78 | 79 | 80 | 81 | 如项目对你有帮助,欢迎 Star 🌟 或留言交流! 82 | -------------------------------------------------------------------------------- /主文件中的代码/Data_crawling.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import xlwt 4 | comment_list = [] 5 | sex_list = [] 6 | like_list = [] 7 | level_list = [] 8 | name_list = [] 9 | 10 | import os 11 | # 读取同一文件夹下的 cookie.txt 文件内容 12 | cookie_file_path = 'cookie.txt' # 文件名 13 | if os.path.exists(cookie_file_path): 14 | with open(cookie_file_path, 'r', encoding='utf-8') as file: 15 | cookie_value = file.read().strip() # 读取文件内容并去除首尾空白字符 16 | else: 17 | raise FileNotFoundError(f"文件 {cookie_file_path} 不存在,请确保文件已正确放置在当前文件夹中。") 18 | def crawl_data(bv_number): 19 | headers = { 20 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 21 | # 自己电脑的user-agent 22 | 'referer': 'https://www.bilibili.com/video/', # 网址 23 | 'cookie': cookie_value # 从文件中读取的 cookie 值 24 | } 25 | for page in range(1, 11): 26 | url = f'https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={page}&type=1&oid={bv_number}&sort=2&p={page}' 27 | response = requests.get(url=url, headers=headers).text 28 | re_data = json.loads(response) 29 | if re_data['data']['replies'] != None : 30 | for i in re_data["data"]['replies']: 31 | comment = i["content"]['message'] 32 | name = i["member"]['uname'] 33 | like = i["like"] 34 | level = i['member']['level_info']['current_level'] 35 | sex = i["member"]['sex'] 36 | 37 | comment_list.append(comment) 38 | sex_list.append(sex) 39 | like_list.append(like) 40 | level_list.append(level) 41 | name_list.append(name) 42 | 43 | workbook = xlwt.Workbook(encoding='utf-8') 44 | worksheet = workbook.add_sheet("test_sheet") 45 | worksheet.write(0, 0, label='名字') 46 | worksheet.write(0, 1, label='性别') 47 | worksheet.write(0, 2, label='等级') 48 | worksheet.write(0, 3, label='评论内容') 49 | worksheet.write(0, 4, label='点赞数') 50 | for i in range(len(name_list)): 51 | worksheet.write(i + 1, 0, label=name_list[i]) 52 | worksheet.write(i + 1, 1, label=sex_list[i]) 53 | worksheet.write(i + 1, 2, label=level_list[i]) 54 | worksheet.write(i + 1, 3, label=comment_list[i]) 55 | worksheet.write(i + 1, 4, label=like_list[i]) 56 | workbook.save(r"评论信息.xlsx") 57 | #crawl_data("BV1Z55VznEdq") # 你可以保留或注释掉这行测试代码 58 | -------------------------------------------------------------------------------- /主文件中的代码/main_file.py: -------------------------------------------------------------------------------- 1 | import gradio as gr 2 | import Data_crawling 3 | import Data_cleaning 4 | import bert_analysis 5 | import Word_cloud_image_generation 6 | import Data_visualization 7 | import os 8 | #数据爬取 9 | def crawl_data_gradio(bv_number): 10 | Data_crawling.crawl_data(bv_number) 11 | return "数据抓取完成" # 返回文本信息,Gradio 将在界面上显示 12 | #数据清洗 13 | def clean_data_gradio(): 14 | filepath = "评论信息.xls" 15 | cleaned_filepath = Data_cleaning.clean_chinese_characters(filepath) 16 | return f"清洗后的文件保存为:{cleaned_filepath}" # 返回清洗后文件路径 17 | #情感分析 18 | def analyse_data_gradio(): 19 | filepath = "评论信息.xlsx" 20 | save_file = "情感输出结果_bert.xlsx" 21 | model_path = "e:/bilibili_train/bert_train" 22 | analyse_filepath = bert_analysis.analyze_sentiment(filepath, save_file, model_path) 23 | return f"分析后的文件保存为:{analyse_filepath}" # 返回情感分析结果文件路径 24 | #词云图生成 25 | def generate_word_cloud_gradio(): 26 | image_path = "word_cloud_image.png" 27 | mask_image_path = "mask.png" 28 | # 确保返回图片路径 29 | return Word_cloud_image_generation.generate_word_cloud( 30 | filepath="评论信息_清洗去重后.xlsx", 31 | stopwords_path="hit_stopwords.txt", 32 | mask_image_path=mask_image_path, 33 | save_image_path=image_path 34 | ) 35 | def visualize_data_gradio(): 36 | html_path = "所有可视化图表.html" 37 | Data_visualization.visualize_data("情感输出结果_bert.xlsx") 38 | # 不再读取 HTML 文件内容,直接返回文字提示信息 39 | return f"数据可视化图表已生成并保存到本地文件:{html_path},请在本地文件中查看。" 40 | 41 | # 使用 Blocks API 创建 Gradio 界面 42 | with gr.Blocks(title="B站评论分析 Web 应用") as demo: 43 | gr.Markdown(""" 44 | # B站评论分析 Web 应用 45 | 这是一个用于 B 站评论数据分析的 Web 应用。 46 | 请输入要爬取视频的 BV 号,然后点击下方按钮执行数据爬取、清洗、情感分析、词云图生成和数据可视化等操作。 47 | """) 48 | 49 | bv_input = gr.Textbox(label="输入要爬取视频的BV号") 50 | output_info = gr.Markdown("请点击下方按钮执行相应操作") 51 | image_output_wordcloud = gr.Image(width=1000, height=700) 52 | # 使用 gr.Markdown 组件显示 HTML 内容,而不是 gr.HTML 53 | html_output = gr.Markdown() 54 | 55 | with gr.Row(): 56 | crawl_button = gr.Button("开始爬取") 57 | clean_button = gr.Button("清洗数据") 58 | analyse_button = gr.Button("情感分析") 59 | wordcloud_button = gr.Button("词云图生成") 60 | visualize_button = gr.Button("生成创作者画像") 61 | 62 | crawl_button.click(crawl_data_gradio, inputs=bv_input, outputs=output_info) 63 | clean_button.click(clean_data_gradio, inputs=[], outputs=output_info) 64 | analyse_button.click(analyse_data_gradio, inputs=[], outputs=output_info) 65 | wordcloud_button.click(generate_word_cloud_gradio, inputs=[], outputs=image_output_wordcloud) 66 | # 修改可视化按钮的输出目标为 html_output,并确保 outputs 是 html_output 组件 67 | visualize_button.click( 68 | visualize_data_gradio, 69 | inputs=[], 70 | outputs=html_output 71 | ) 72 | 73 | if __name__ == "__main__": 74 | demo.launch(share=False) -------------------------------------------------------------------------------- /Data_crawling.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import xlwt 4 | comment_list = [] 5 | sex_list = [] 6 | like_list = [] 7 | level_list = [] 8 | name_list = [] 9 | 10 | import os 11 | # 读取同一文件夹下的 cookie.txt 文件内容 12 | cookie_file_path = 'cookie.txt' # 文件名 13 | if os.path.exists(cookie_file_path): 14 | with open(cookie_file_path, 'r', encoding='utf-8') as file: 15 | cookie_value = file.read().strip() # 读取文件内容并去除首尾空白字符 16 | else: 17 | raise FileNotFoundError(f"文件 {cookie_file_path} 不存在,请确保文件已正确放置在当前文件夹中。") 18 | def crawl_data(bv_number): 19 | headers = { 20 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 21 | # 自己电脑的user-agent 22 | 'referer': 'https://www.bilibili.com/video/', # 网址 23 | 'cookie': cookie_value # 从文件中读取的 cookie 值 24 | } 25 | 26 | # def crawl_data(bv_number): 27 | # headers = { 28 | # 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 29 | # # 自己电脑的user-agant 30 | # 'referer': 'https://www.bilibili.com/video/', 31 | # # 网址 32 | # 'cookie': "buvid4=8D4A2ADE-CB95-88DF-FD3B-CC9F77BE244869063-022012421-Vk7oLekZ8O%2BWwDC%2BideQ6A%3D%3D; header_theme_version=CLOSE; enable_web_push=DISABLE; LIVE_BUVID=AUTO8617093666395399; buvid_fp=742d1522a279e233ccc0138e20571bfc; FEED_LIVE_VERSION=V_WATCHLATER_PIP_WINDOW3; CURRENT_BLACKGAP=0; hit-dyn-v2=1; CURRENT_QUALITY=80; is-2022-channel=1; _uuid=9254D896-12710-2A22-6410C-6A56C788799863056infoc; DedeUserID=347760015; DedeUserID__ckMd5=b3e098a82a04b457; PVID=3; buvid3=AAF79126-1DA9-8B4A-59F3-E32F7485E4B982916infoc; b_nut=1736682182; rpdid=|(J|)Y~Ru)|~0J'u~JmYklkk~; fingerprint=5decd515eea056e6f18864bc721b8fc0; enable_feed_channel=ENABLE; bp_t_offset_347760015=1044087535837380608; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDIzNjAzNjMsImlhdCI6MTc0MjEwMTEwMywicGx0IjotMX0.fbW-zCSgduGSg170p1VQhNDD5iKRU_QJEJDpup2hiS0; bili_ticket_expires=1742360303; SESSDATA=0266dedc%2C1757751098%2C1007d%2A31CjB41oEdKqiUzZagdFRRNIITu8eSGq1J6Ef2PUO_iwAC2xP0047m03XxaNQQ511dkqASVmJDc1E2Rk5RanhSTDBfOHgyMUtHRE9meWtBWXc4MV9lYzFtYlVEVlBfNXRrRktTZ1Q0bmhvdXhmSzY1T3VlOVJDcFVjY01lLXJHUjRTaVc2UHNLSDF3IIEC; bili_jct=2369d4e04b7dbe48be089ad0175a6cb3; b_lsid=710BA53B5_195A6F4E8A4; sid=7ovxl346; CURRENT_FNVAL=4048; home_feed_column=4; browser_resolution=120-571" # 33 | # # 输入自己的cookie 34 | # 35 | # } 36 | 37 | for page in range(1, 2): 38 | url = f'https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={page}&type=1&oid={bv_number}&sort=2&p={page}' 39 | response = requests.get(url=url, headers=headers).text 40 | re_data = json.loads(response) 41 | if re_data['data']['replies'] != None : 42 | for i in re_data["data"]['replies']: 43 | comment = i["content"]['message'] 44 | name = i["member"]['uname'] 45 | like = i["like"] 46 | level = i['member']['level_info']['current_level'] 47 | sex = i["member"]['sex'] 48 | 49 | comment_list.append(comment) 50 | sex_list.append(sex) 51 | like_list.append(like) 52 | level_list.append(level) 53 | name_list.append(name) 54 | 55 | workbook = xlwt.Workbook(encoding='utf-8') 56 | worksheet = workbook.add_sheet("test_sheet") 57 | worksheet.write(0, 0, label='名字') 58 | worksheet.write(0, 1, label='性别') 59 | worksheet.write(0, 2, label='等级') 60 | worksheet.write(0, 3, label='评论内容') 61 | worksheet.write(0, 4, label='点赞数') 62 | for i in range(len(name_list)): 63 | worksheet.write(i + 1, 0, label=name_list[i]) 64 | worksheet.write(i + 1, 1, label=sex_list[i]) 65 | worksheet.write(i + 1, 2, label=level_list[i]) 66 | worksheet.write(i + 1, 3, label=comment_list[i]) 67 | worksheet.write(i + 1, 4, label=like_list[i]) 68 | workbook.save(r"评论信息.xls") 69 | crawl_data("BV1Z55VznEdq") # 你可以保留或注释掉这行测试代码 70 | -------------------------------------------------------------------------------- /README-english.md: -------------------------------------------------------------------------------- 1 | # 🎯 Bilibili Comment Sentiment Analysis System (Fine-tuned BERT-based) 2 | 3 | ## Project Overview 4 | 5 | This project presents a Bilibili-specific sentiment analysis system based on a fine-tuned BERT model. It includes a full pipeline from data collection to training and visualization. The system is optimized for the unique characteristics of Bilibili comments and supports accurate binary classification (positive/negative), with visualization such as word clouds. 6 | 7 | 🔗 **Model on Hugging Face**: [blank02/Bilibili-comment-fine-tuning-BERT](https://huggingface.co/blank02/Bilibili-comment-fine-tuning-BERT) 8 | 9 | ## Key Features 10 | 11 | * **Domain-optimized model**: Fine-tuned from `chinese-bert-wwm-ext`, tailored for the style and slang of Bilibili comments. 12 | * **End-to-end pipeline**: Covers data crawling → cleaning → labeling → training → visualization. 13 | * **High performance**: Achieves 92.6% accuracy on Bilibili-specific dataset (a 7.2% improvement over base BERT). 14 | * **Web UI**: Includes web-based interface for visualizing sentiment results and generating word clouds. 15 | 16 | ## Fine-tuning Details 17 | 18 | ### Base Model 19 | 20 | [`chinese-bert-wwm-ext`](https://huggingface.co/hfl/chinese-bert-wwm-ext) – Whole Word Masking BERT for Chinese 21 | 22 | ### Performance Comparison 23 | 24 | | Metric | Base BERT | Fine-tuned Model | Improvement | 25 | | -------------- | ------------- | ----------------- | ----------- | 26 | | Accuracy | 85.4% | **92.6%** | ↑ 7.2% | 27 | | F1 Score | 0.83 | **0.91** | ↑ 9.6% | 28 | | Inference Time | 38ms/instance | **22ms/instance** | ↓ 42.1% | 29 | 30 | ### Optimization Techniques 31 | 32 | 1. Dynamic learning rate scheduling (peak at 2e-5) 33 | 2. Layer-wise learning rate decay (top-layer decay factor: 0.8) 34 | 3. Adversarial training using FGM 35 | 4. Early stopping (patience = 3) 36 | 37 | ## Project Structure 38 | 39 | ``` 40 | . 41 | ├── main_code/ # Core scripts 42 | │ ├── Data_crawling.py # Bilibili comment crawler 43 | │ ├── Data_cleaning.py # Data cleaning 44 | │ ├── bert_analysis.py # Sentiment analysis module 45 | │ ├── Word_cloud_image_generation.py # Word cloud generator 46 | │ └── main_file.py # Web interface with Gradio/Flask 47 | ├── cookie.txt # Bilibili cookie settings 48 | ├── requirements.txt # Dependency list 49 | └── model/ # Fine-tuned BERT model files 50 | ``` 51 | 52 | ## Quick Start 53 | 54 | ### Install Dependencies 55 | 56 | ```bash 57 | pip install -r requirements.txt 58 | ``` 59 | 60 | ### Set Bilibili Cookie 61 | 62 | 1. Paste your valid Bilibili cookie into `cookie.txt` 63 | 2. Format example: `SESSDATA=xxx; bili_jct=xxx` 64 | 65 | ### Run Workflow 66 | 67 | ```bash 68 | # 1. Crawl comment data (example BV ID: BV1xx411x7xx) 69 | python Data_crawling.py --video_id BV1xx411x7xx 70 | 71 | # 2. Clean data 72 | python Data_cleaning.py 73 | 74 | # 3. Sentiment analysis 75 | python bert_analysis.py 76 | 77 | # 4. Start web interface 78 | python main_file.py 79 | ``` 80 | 81 | ## Demo 82 | 83 | ### Data Crawling Interface 84 | 85 | ![Screenshot](media/crawling_screenshot.png) 86 | 87 | ### Sentiment Classification Result 88 | 89 | ```json 90 | { 91 | "comment": "This creator’s content is amazing!", 92 | "sentiment": "positive", 93 | "confidence": 0.963 94 | } 95 | ``` 96 | 97 | ### Word Cloud Visualization 98 | 99 | ![Word Cloud](media/wordcloud_example.png) 100 | 101 | ## Tech Stack 102 | 103 | * **Deep Learning**: PyTorch + Huggingface Transformers 104 | * **Data Processing**: Pandas + Jieba 105 | * **Visualization**: WordCloud + Matplotlib 106 | * **Web UI**: Flask / Gradio 107 | 108 | ## FAQ 109 | 110 | **Q: How can I get the Bilibili Cookie?** 111 | A: Log into Bilibili, open DevTools (F12), go to the "Network" tab and find your session cookie. 112 | 113 | **Q: What sentiment classes does the model support?** 114 | A: Currently supports binary classification: positive / negative 115 | 116 | > Feel free to open an issue if you have questions or suggestions. 117 | -------------------------------------------------------------------------------- /模型三分类.py: -------------------------------------------------------------------------------- 1 | from transformers import pipeline # 导入transformers库用于加载AI模型 2 | import pandas as pd # 导入pandas库用于处理Excel文件 3 | import os # 导入os库 4 | import datasets # 导入datasets库用于批量处理数据 5 | 6 | # --- 配置部分 --- 7 | # Excel文件路径 8 | excel_file_path = 'e:\\bilibili_train\\多视频评论信息.xls' 9 | # 包含评论内容的列名 10 | comment_column_name = '评论内容' 11 | # 输出文件名 12 | output_file_name = '评论情感分析结果_三分类.xlsx' 13 | 14 | # --- 加载情感分析模型 --- 15 | try: 16 | # 加载指定的中文情感分析模型 17 | # 使用 top_k=None 来获取所有类别的得分 18 | sentiment_pipeline = pipeline( 19 | "text-classification", 20 | model="IDEA-CCNL/Erlangshen-Roberta-110M-Sentiment", 21 | top_k=None # 使用 top_k=None 获取所有得分 22 | ) 23 | print("情感分析模型加载成功。") 24 | except Exception as e: 25 | print(f"加载情感分析模型失败: {e}") 26 | print("请检查模型名称、网络或依赖。") 27 | exit() # 加载失败则退出脚本 28 | 29 | # --- 读取数据并进行情感分析 (批量处理方法) --- 30 | # 修改函数签名,接收 tokenizer, model 和 id2label 映射 31 | def analyze_sentiments_from_excel_batch(file_path, column_name, tokenizer, model, id2label_map): 32 | """ 33 | 从Excel文件读取评论,进行预处理,使用加载的本地模型进行情感分析,并返回包含结果的列表。 34 | """ 35 | try: 36 | # 读取Excel文件 (.xls 需要安装 xlrd) 37 | df = pd.read_excel(file_path, engine='xlrd') 38 | print(f"成功读取Excel文件 '{file_path}',共 {len(df)} 条数据。") 39 | except FileNotFoundError: 40 | print(f"错误:文件未找到 '{file_path}'") 41 | return None 42 | except Exception as e: 43 | print(f"读取Excel文件失败: {e}") 44 | return None 45 | 46 | # 检查评论列是否存在 47 | if column_name not in df.columns: 48 | print(f"错误:列 '{column_name}' 在文件中未找到。可用的列: {df.columns.tolist()}") 49 | return None 50 | 51 | # 处理空评论 - 过滤掉空评论,只将非空评论送入模型预测 52 | # 获取非空评论的原始索引列表和文本列表 53 | non_empty_original_indices = [] # <-- 新增:存储非空评论在原始DataFrame中的索引 54 | non_empty_comments = [] # <-- 存储非空评论的文本 55 | for original_idx, text in enumerate(df[column_name]): 56 | comment_text = str(text).strip() 57 | if comment_text: # 如果评论不为空或只包含空白字符 58 | non_empty_original_indices.append(original_idx) # 记录原始索引 59 | non_empty_comments.append(comment_text) # 记录评论文本 60 | 61 | print(f"发现 {len(non_empty_comments)} 条非空评论,将进行预测。") 62 | 63 | predicted_labels = [] # 用于存储预测的文本标签 64 | predicted_scores = [] # 用于存储预测的最高得分 65 | 66 | # ... (此处是使用 tokenizer 和 model 进行预测的代码,不需要修改) 67 | # 使用加载的 tokenizer 对非空评论进行批量编码 68 | if len(non_empty_comments) > 0: 69 | try: 70 | # 使用 tokenizer 编码文本,返回 PyTorch 张量 71 | # 使用和训练时相同的 max_length, padding 和 truncation 策略 72 | # 假设训练时使用的是 max_length=256 73 | inputs = tokenizer( 74 | non_empty_comments, 75 | padding=True, # 填充 76 | truncation=True, # 截断 77 | max_length=256, # 使用训练时或你设定的最大长度 78 | return_tensors="pt" # 返回 PyTorch 张量 79 | ) 80 | 81 | # 将输入张量移动到模型所在的设备 (CPU 或 GPU) 82 | inputs = {key: val.to(model.device) for key, val in inputs.items()} 83 | 84 | # 将模型设置为评估模式 (会关闭 dropout 等) 85 | model.eval() 86 | 87 | # 在 torch.no_grad() 块中进行推理,不计算梯度,节省显存,加速计算 88 | with torch.no_grad(): 89 | # 将编码后的输入送入模型 90 | outputs = model(**inputs) 91 | 92 | # 获取模型的输出 logits 93 | logits = outputs.logits 94 | 95 | # 将 logits 转换为概率 (可选,但 score 通常指最高概率) 96 | probabilities = torch.softmax(logits, dim=-1) 97 | 98 | # 获取每个样本最高概率对应的类别 ID 99 | # torch.max 返回最大值和对应的索引 100 | max_probs, predicted_ids = torch.max(probabilities, dim=-1) 101 | 102 | # 将预测结果从张量转换为 Python 列表,并移回 CPU (如果它们在 GPU 上) 103 | predicted_ids = predicted_ids.cpu().tolist() 104 | max_probs = max_probs.cpu().tolist() 105 | 106 | # 使用 id2label 映射将类别 ID 转换为文本标签 107 | predicted_labels = [id2label_map[id] for id in predicted_ids] 108 | predicted_scores = max_probs # 最高概率作为 score 109 | 110 | print("本地模型预测完成。") 111 | 112 | except Exception as e: 113 | print(f"本地模型预测失败: {e}") 114 | # 预测失败,保留空的 predicted_labels 和 predicted_scores 列表 115 | # 同时返回 None 表示整个分析过程失败,由调用者处理 116 | return None # 预测失败则返回 None 117 | 118 | 119 | else: 120 | print("没有非空评论需要预测。") 121 | 122 | 123 | # 整理结果,将分析结果与原始数据合并 124 | results_list = [] # 用于存储最终要输出的每行结果字典 125 | 126 | # 预填充结果列表,包含原始数据和默认的分析状态 127 | for i, row in df.iterrows(): 128 | row_result = { 129 | 'name': row.get('名字'), # 假设原始文件中有这些列 130 | 'gender': row.get('性别'), 131 | 'level': row.get('等级'), 132 | column_name: str(row.get(column_name, '')), # 确保评论是字符串并使用配置的列名 133 | 'likes': row.get('点赞数'), 134 | 'emotion': '未分析', # 默认状态 135 | 'score': None, 136 | 'status': '未分析' 137 | } 138 | # 稍后根据是否是空评论或预测是否成功来更新这些字段 139 | results_list.append(row_result) 140 | 141 | 142 | # 将预测结果映射回原始位置 143 | # predicted_labels 的长度与 non_empty_original_indices 相同 144 | # predicted_labels[i] 对应于原始 DataFrame 索引 non_empty_original_indices[i] 145 | if predicted_labels: # 只有当预测成功并有结果时才进行映射 146 | # 遍历预测结果及其对应的原始索引 147 | for i, predicted_label in enumerate(predicted_labels): 148 | # 获取这条预测结果对应的原始 DataFrame 索引 149 | original_idx = non_empty_original_indices[i] # <-- 使用正确获取的原始索引列表 150 | 151 | # 获取对应的得分 152 | predicted_score = predicted_scores[i] 153 | 154 | # 更新 results_list 中对应原始索引位置的条目 155 | results_list[original_idx]['emotion'] = predicted_label 156 | results_list[original_idx]['score'] = predicted_score 157 | results_list[original_idx]['status'] = '成功' 158 | 159 | # 遍历 results_list,将未被标记为“成功”的非空评论标记为“预测失败”(如果预测过程返回了None) 160 | # 或者将空的评论标记为“跳过” 161 | for i, row_result in enumerate(results_list): 162 | original_comment_text = str(df.iloc[i].get(column_name, '')).strip() 163 | if not original_comment_text: 164 | row_result['emotion'] = '空评论' 165 | row_result['status'] = '跳过' 166 | elif row_result['status'] == '未分析': 167 | # 如果是非空评论,但在预测结果映射阶段没有被标记为“成功” 168 | # 这通常意味着预测函数本身返回了None(发生了预测错误) 169 | row_result['status'] = '预测失败' 170 | row_result['emotion'] = '预测失败' # 或者保持 '未分析' 171 | 172 | return results_list 173 | 174 | # --- 主程序执行部分 --- (保持不变) 175 | # ... (你的主程序调用部分) 176 | if __name__ == "__main__": 177 | # 调用函数进行分析,传递加载好的 tokenizer, model 和 id2label 178 | analysis_results = analyze_sentiments_from_excel_batch( 179 | excel_file_path, 180 | comment_column_name, 181 | tokenizer, # <-- 传递 tokenizer 182 | model, # <-- 传递 model 183 | id2label_map # <-- 传递 id2label 映射 184 | ) 185 | 186 | # 如果分析成功 187 | if analysis_results is not None: 188 | # 将结果列表转换为pandas DataFrame 189 | output_df = pd.DataFrame(analysis_results) 190 | 191 | # 保存结果到新的Excel文件 192 | try: 193 | # 使用 openpyxl 引擎保存为 .xlsx 格式 194 | output_df.to_excel(output_file_name, index=False, engine='openpyxl') 195 | print(f"详细分析结果已保存到 '{output_file_name}'") 196 | except Exception as e: 197 | print(f"保存文件失败: {e}") 198 | print("请确保文件未被占用或检查写入权限。") 199 | 200 | print("\n脚本执行完毕。") -------------------------------------------------------------------------------- /模型三分类_微调后的bert模型.py: -------------------------------------------------------------------------------- 1 | # 导入必要的库 (保持不变) 2 | import pandas as pd 3 | import os 4 | import datasets 5 | import torch 6 | from transformers import BertTokenizer, BertForSequenceClassification 7 | 8 | # --- 配置部分 --- (保持不变) 9 | # Excel文件路径 10 | excel_file_path = 'e:\\bilibili_train\\多视频评论信息.xls' 11 | # 包含评论内容的列名 12 | comment_column_name = '评论内容' 13 | # 输出文件名 14 | output_file_name = '评论情感分析结果_三分类_本地模型批量预测.xlsx' # 修改输出文件名 15 | # 你本地保存微调模型的目录路径 16 | local_model_path = './bert_train' 17 | 18 | # --- 加载本地微调模型和 Tokenizer --- (增加 FP16 转换) 19 | try: 20 | print(f"尝试从本地目录 '{local_model_path}' 加载模型和 Tokenizer...") 21 | tokenizer = BertTokenizer.from_pretrained(local_model_path) 22 | print("Tokenizer 加载成功。") 23 | 24 | model = BertForSequenceClassification.from_pretrained(local_model_path) 25 | print("模型加载成功。") 26 | 27 | id2label_map = model.config.id2label 28 | print(f"获取标签映射: {id2label_map}") 29 | 30 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 31 | model.to(device) 32 | 33 | # 在有限显存环境下,启用 FP16 通常是必要的 34 | if device.type == 'cuda': 35 | try: 36 | model.half() # 将模型转换为半精度 37 | print("模型已转换为半精度 (FP16)。") 38 | except Exception as e: 39 | print(f"警告: 无法将模型转换为 FP16: {e}。将使用 FP32 进行预测,可能需要更小的 Batch Size。") 40 | 41 | print(f"模型已加载到设备: {device}") 42 | 43 | except Exception as e: 44 | print(f"加载本地模型或 Tokenizer 失败: {e}") 45 | print(f"请检查目录 '{local_model_path}' 是否存在且包含正确的模型文件 (config.json, model.safetensors, vocab.txt 等)。") 46 | exit() 47 | 48 | # --- 读取数据并进行情感分析 (手动批量处理方法) --- 49 | # 修改函数,实现手动批量预测 50 | def analyze_sentiments_from_excel_batch(file_path, column_name, tokenizer, model, id2label_map): 51 | """ 52 | 从Excel文件读取评论,进行预处理,使用加载的本地模型进行手动批量情感分析,并返回包含结果的列表。 53 | """ 54 | try: 55 | df = pd.read_excel(file_path, engine='xlrd') 56 | print(f"成功读取Excel文件 '{file_path}',共 {len(df)} 条数据。") 57 | except FileNotFoundError: 58 | print(f"错误:文件未找到 '{file_path}'") 59 | return None 60 | except Exception as e: 61 | print(f"读取Excel文件失败: {e}") 62 | return None 63 | 64 | if column_name not in df.columns: 65 | print(f"错误:列 '{column_name}' 在文件中未找到。可用的列: {df.columns.tolist()}") 66 | return None 67 | 68 | # 获取非空评论的原始索引列表和文本列表 69 | non_empty_original_indices = [] 70 | non_empty_comments = [] 71 | for original_idx, text in enumerate(df[column_name]): 72 | comment_text = str(text).strip() 73 | if comment_text: 74 | non_empty_original_indices.append(original_idx) 75 | non_empty_comments.append(comment_text) 76 | 77 | print(f"发现 {len(non_empty_comments)} 条非空评论,将进行预测。") 78 | 79 | # --- 手动批量预测的关键部分 --- 80 | # 为 4GB 显存环境设置预测的 Batch Size 和 Max Length 81 | # 你可能需要根据实际情况和是否成功启用 FP16 来微调 predict_batch_size 82 | predict_batch_size = 16 # 尝试一个较小的 Batch Size,例如 16 或 8 83 | predict_max_length = 128 # 在 4GB 环境下,将最大长度限制在 128 更安全 84 | 85 | print(f"将使用 手动批量预测,Batch Size = {predict_batch_size}, Max Length = {predict_max_length}。") 86 | 87 | all_predicted_labels = [] # 存储所有非空评论的预测文本标签 88 | all_predicted_scores = [] # 存储所有非空评论的预测最高得分 89 | 90 | # 将模型设置为评估模式 (在推理前设置) 91 | model.eval() 92 | 93 | # 使用 torch.no_grad() 禁用梯度计算 (在推理前设置) 94 | with torch.no_grad(): 95 | # 手动循环处理批次 96 | for i in range(0, len(non_empty_comments), predict_batch_size): 97 | batch_start = i 98 | batch_end = i + predict_batch_size 99 | batch_texts = non_empty_comments[batch_start : batch_end] 100 | 101 | # 如果批量为空,跳过 (通常不会,除非总数不是 Batch Size 的倍数) 102 | if not batch_texts: 103 | continue 104 | 105 | try: 106 | # Tokenizer 编码当前批次文本 107 | inputs = tokenizer( 108 | batch_texts, 109 | padding=True, # 在批次内进行填充 110 | truncation=True, # 截断到 predict_max_length 111 | max_length=predict_max_length, # 使用为预测设定的最大长度 112 | return_tensors="pt" # 返回 PyTorch 张量 113 | ) 114 | 115 | # 将输入张量移动到设备 (GPU) 116 | inputs = {key: val.to(model.device) for key, val in inputs.items()} 117 | 118 | # --- 修改:只将浮点类型的输入张量转换为半精度 --- 119 | if model.dtype == torch.float16: 120 | # 遍历 inputs 字典,如果张量是浮点类型,则转换为 half() 121 | inputs = { 122 | key: val.half() if val.dtype in [torch.float32, torch.float] else val 123 | for key, val in inputs.items() 124 | } 125 | # --- 修改结束 --- 126 | 127 | # 将编码后的输入送入模型进行推理 128 | outputs = model(**inputs) 129 | 130 | # 获取当前批次的预测结果 131 | logits = outputs.logits 132 | probabilities = torch.softmax(logits, dim=-1) 133 | max_probs, predicted_ids = torch.max(probabilities, dim=-1) 134 | 135 | # 将结果从张量转换为 Python 列表 136 | batch_predicted_ids = predicted_ids.cpu().tolist() 137 | batch_max_probs = max_probs.cpu().tolist() 138 | 139 | # 将类别 ID 转换为文本标签和得分 140 | batch_predicted_labels = [id2label_map[id] for id in batch_predicted_ids] 141 | batch_predicted_scores = batch_max_probs 142 | 143 | # 将当前批次的预测结果添加到总的结果列表 144 | all_predicted_labels.extend(batch_predicted_labels) 145 | all_predicted_scores.extend(batch_predicted_scores) 146 | 147 | print(f"已处理批次 {i // predict_batch_size + 1}/{(len(non_empty_comments) + predict_batch_size - 1) // predict_batch_size} (样本 {batch_start+1}-{batch_end})") 148 | 149 | 150 | except Exception as e: 151 | print(f"警告: 处理批次 (样本 {batch_start+1}-{batch_end}) 时发生错误: {e}") 152 | # 如果某个批次处理失败,这里简单打印警告并跳过该批次。 153 | # 这会导致最终结果中这些评论标记为“未分析”或“预测失败”。 154 | # 如果需要更严格的错误处理,可以根据错误类型选择退出或采取其他措施。 155 | pass 156 | 157 | # 检查是否有任何预测结果生成 158 | if not all_predicted_labels: 159 | print("所有批次处理失败或没有非空评论被成功预测。") 160 | return None # 如果没有成功预测任何评论,则表示整个分析失败 161 | 162 | print("本地模型预测流程完成。") 163 | 164 | # --- 整理结果,将分析结果与原始数据合并 --- 165 | # 预填充结果列表,包含原始数据和默认的分析状态 166 | results_list = [] 167 | for i, row in df.iterrows(): 168 | row_result = { 169 | 'name': row.get('名字'), 170 | 'gender': row.get('性别'), 171 | 'level': row.get('等级'), 172 | column_name: str(row.get(column_name, '')), 173 | 'likes': row.get('点赞数'), 174 | 'emotion': '未分析', # 默认状态:未分析 175 | 'score': None, 176 | 'status': '未分析' # 默认状态:未分析 177 | } 178 | results_list.append(row_result) 179 | 180 | # 将预测结果映射回原始位置 181 | # all_predicted_labels 和 all_predicted_scores 的长度与 non_empty_original_indices 相同 182 | # all_predicted_labels[i] 对应于原始 DataFrame 索引 non_empty_original_indices[i] 183 | if all_predicted_labels: # 确保有预测结果需要映射 184 | for i in range(len(all_predicted_labels)): 185 | original_idx = non_empty_original_indices[i] # 获取预测结果对应的原始索引 186 | 187 | results_list[original_idx]['emotion'] = all_predicted_labels[i] 188 | results_list[original_idx]['score'] = all_predicted_scores[i] 189 | results_list[original_idx]['status'] = '成功' 190 | 191 | # 最终遍历 results_list,处理空评论和标记预测失败的评论 192 | for i, row_result in enumerate(results_list): 193 | original_comment_text = str(df.iloc[i].get(column_name, '')).strip() 194 | if not original_comment_text and row_result['status'] == '未分析': 195 | # 如果是空评论且状态还是“未分析”,则标记为“跳过” 196 | row_result['emotion'] = '空评论' 197 | row_result['status'] = '跳过' 198 | elif row_result['status'] == '未分析': 199 | # 如果是非空评论,但在预测结果映射阶段状态仍然是“未分析” 200 | # 这意味着它在手动批量预测过程中失败了 201 | row_result['status'] = '预测失败 (批次错误)' 202 | row_result['emotion'] = '预测失败' # 或者保持 '未分析' 203 | 204 | return results_list 205 | 206 | # --- 主程序执行部分 --- (保持不变) 207 | # ... (你的主程序调用部分,与上次修改相同) 208 | if __name__ == "__main__": 209 | # 调用函数进行分析,传递加载好的 tokenizer, model 和 id2label 210 | analysis_results = analyze_sentiments_from_excel_batch( 211 | excel_file_path, 212 | comment_column_name, 213 | tokenizer, 214 | model, 215 | id2label_map 216 | ) 217 | 218 | if analysis_results is not None: 219 | output_df = pd.DataFrame(analysis_results) 220 | try: 221 | output_df.to_excel(output_file_name, index=False, engine='openpyxl') 222 | print(f"详细分析结果已保存到 '{output_file_name}'") 223 | except Exception as e: 224 | print(f"保存文件失败: {e}") 225 | print("请确保文件未被占用或检查写入权限。") 226 | 227 | print("\n脚本执行完毕。") -------------------------------------------------------------------------------- /数据爬取.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | import xlwt 4 | import xlrd # 导入 xlrd 用于读取现有Excel文件 5 | from xlutils.copy import copy # 导入 copy 用于复制可读的workbook到可写的workbook 6 | import os 7 | import time 8 | import random 9 | 10 | # 读取同一文件夹下的 cookie.txt 文件内容 11 | cookie_file_path = 'cookie.txt' # 文件名 12 | cookie_value = "" # 初始化 cookie_value 13 | if os.path.exists(cookie_file_path): 14 | with open(cookie_file_path, 'r', encoding='utf-8') as file: 15 | cookie_value = file.read().strip() # 读取文件内容并去除首尾空白字符 16 | if not cookie_value: 17 | raise ValueError(f"文件 {cookie_file_path} 内容为空,请确保cookie已正确写入。") 18 | else: 19 | raise FileNotFoundError(f"文件 {cookie_file_path} 不存在,请确保文件已正确放置在当前文件夹中。") 20 | 21 | def crawl_data_and_append(bv_number): 22 | """ 23 | 爬取指定BV号视频的评论数据,并追加到Excel文件。 24 | Args: 25 | bv_number: 视频的BV号 (字符串)。 26 | """ 27 | 28 | headers = { 29 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 30 | 'referer': f'https://www.bilibili.com/video/{bv_number}', 31 | 'cookie': cookie_value, 32 | 'Accept': 'application/json, text/plain, */*', # B站API常见Accept 33 | 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', # 根据你浏览器设置调整 34 | 'Connection': 'keep-alive' # 保持连接 35 | } 36 | # 使用局部列表存储当前BV号爬取的数据 37 | current_comment_list = [] 38 | current_sex_list = [] 39 | current_like_list = [] 40 | current_level_list = [] 41 | current_name_list = [] 42 | 43 | # 原代码只爬取了第一页 (range(1, 2)),这里保留一致。 44 | # 如果需要爬取更多页,修改 range 的范围即可。 45 | # 注意:爬取多页时,start_row 的计算方式不受影响,数据会依次追加。 46 | for page in range(1, 6): # 示例只爬取第一页 47 | time.sleep(random.uniform(3, 15)) 48 | url = f'https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={page}&type=1&oid={get_oid_from_bv(bv_number)}&sort=2&p={page}' # 需要oid,调用函数转换 49 | print(f"正在爬取 BV号 {bv_number} 的第 {page} 页评论...") 50 | try: 51 | response = requests.get(url=url, headers=headers) 52 | response.raise_for_status() # 检查HTTP请求是否成功 53 | re_data = response.json() 54 | 55 | if re_data['code'] != 0: 56 | print(f"爬取 BV号 {bv_number} 第 {page} 页评论时API返回错误:{re_data.get('message', '未知错误')}") 57 | # 尝试使用BV号作为oid,有时候API也支持 58 | url_fallback = f'https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next={page}&type=1&oid={bv_number}&sort=2&p={page}' 59 | print(f"尝试使用BV号 {bv_number} 作为oid重新爬取...") 60 | response_fallback = requests.get(url=url_fallback, headers=headers) 61 | response_fallback.raise_for_status() 62 | re_data_fallback = response_fallback.json() 63 | if re_data_fallback['code'] == 0: 64 | re_data = re_data_fallback 65 | print("成功使用BV号作为oid。") 66 | else: 67 | print(f"使用BV号作为oid也失败:{re_data_fallback.get('message', '未知错误')}") 68 | continue # 跳过当前页 69 | 70 | if re_data['data']['replies'] is not None: 71 | for reply in re_data["data"]['replies']: 72 | comment = reply["content"]['message'] 73 | name = reply["member"]['uname'] 74 | like = reply["like"] 75 | level = reply['member']['level_info']['current_level'] 76 | sex = reply["member"]['sex'] 77 | 78 | current_comment_list.append(comment) 79 | current_sex_list.append(sex) 80 | current_like_list.append(like) 81 | current_level_list.append(level) 82 | current_name_list.append(name) 83 | else: 84 | print(f"BV号 {bv_number} 第 {page} 页没有评论数据。") 85 | 86 | except requests.exceptions.RequestException as e: 87 | print(f"请求 BV号 {bv_number} 第 {page} 页评论时发生错误: {e}") 88 | except json.JSONDecodeError: 89 | print(f"解析 BV号 {bv_number} 第 {page} 页评论响应时发生JSON解码错误。") 90 | except Exception as e: 91 | print(f"处理 BV号 {bv_number} 第 {page} 页评论数据时发生未知错误: {e}") 92 | 93 | 94 | # --- 追加写入Excel文件的逻辑 --- 95 | excel_filename = "多视频评论信息.xls" 96 | start_row = 0 # 新数据写入的起始行 97 | 98 | if os.path.exists(excel_filename): 99 | # 文件已存在,读取并复制 100 | try: 101 | read_workbook = xlrd.open_workbook(excel_filename) 102 | read_sheet = read_workbook.sheet_by_index(0) 103 | start_row = read_sheet.nrows # 新数据从现有数据的下一行开始写入 104 | write_workbook = copy(read_workbook) # 复制一个可写的workbook 105 | write_sheet = write_workbook.get_sheet(0) # 获取第一个sheet (假设数据都在第一个sheet) 106 | print(f"文件 '{excel_filename}' 已存在,新数据将从第 {start_row + 1} 行开始追加。") 107 | except xlrd.XLRDError as e: 108 | print(f"读取现有Excel文件 '{excel_filename}' 时发生错误: {e}") 109 | print("可能文件已损坏或格式不正确,尝试创建新文件。") 110 | # 如果读取失败,按文件不存在处理 111 | start_row = 0 112 | write_workbook = xlwt.Workbook(encoding='utf-8') 113 | write_sheet = write_workbook.add_sheet("评论信息") # 使用一致的sheet名称 114 | # 写入表头 115 | write_sheet.write(0, 0, label='名字') 116 | write_sheet.write(0, 1, label='性别') 117 | write_sheet.write(0, 2, label='等级') 118 | write_sheet.write(0, 3, label='评论内容') 119 | write_sheet.write(0, 4, label='点赞数') 120 | start_row = 1 # 数据从第2行(索引1)开始写 121 | print("创建新的Excel文件。") 122 | else: 123 | # 文件不存在,创建新文件并写入表头 124 | write_workbook = xlwt.Workbook(encoding='utf-8') 125 | write_sheet = write_workbook.add_sheet("评论信息") # 使用一致的sheet名称 126 | # 写入表头 127 | write_sheet.write(0, 0, label='名字') 128 | write_sheet.write(0, 1, label='性别') 129 | write_sheet.write(0, 2, label='等级') 130 | write_sheet.write(0, 3, label='评论内容') 131 | write_sheet.write(0, 4, label='点赞数') 132 | start_row = 1 # 数据从第2行(索引1)开始写 133 | print(f"文件 '{excel_filename}' 不存在,创建新文件。") 134 | 135 | 136 | # 将当前BV号的数据写入Excel 137 | for i in range(len(current_name_list)): 138 | # 写入时使用 start_row + 当前数据在列表中的索引 作为行号 139 | try: 140 | write_sheet.write(start_row + i, 0, label=current_name_list[i]) 141 | write_sheet.write(start_row + i, 1, label=current_sex_list[i]) 142 | write_sheet.write(start_row + i, 2, label=current_level_list[i]) 143 | write_sheet.write(start_row + i, 3, label=current_comment_list[i]) 144 | write_sheet.write(start_row + i, 4, label=current_like_list[i]) 145 | except Exception as e: 146 | print(f"写入 BV号 {bv_number} 的第 {start_row + i} 行数据时发生错误: {e}") 147 | print(f"数据详情: 名字={current_name_list[i]}, 性别={current_sex_list[i]}, 等级={current_level_list[i]}, 评论={current_comment_list[i]}, 点赞={current_like_list[i]}") 148 | 149 | 150 | # 保存workbook,这会覆盖掉原来的文件(但已经包含了旧数据和新数据) 151 | try: 152 | write_workbook.save(excel_filename) 153 | print(f"BV号 {bv_number} 的 {len(current_name_list)} 条评论数据已成功追加到 '{excel_filename}'。") 154 | except Exception as e: 155 | print(f"保存Excel文件 '{excel_filename}' 时发生错误: {e}") 156 | 157 | # 添加一个辅助函数,根据BV号获取oid 158 | # B站评论API通常需要oid(视频的aid)而不是bv号 159 | # 虽然有时直接用bv号作为oid也能工作,但稳妥起见还是转换一下 160 | def get_oid_from_bv(bv_number): 161 | """ 162 | 根据BV号获取视频的AID (用于评论API的oid)。 163 | 如果获取失败,返回原始BV号。 164 | """ 165 | url = f"https://api.bilibili.com/x/web-interface/view/detail?bvid={bv_number}" 166 | headers = { 167 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0', 168 | 'cookie': cookie_value 169 | } 170 | try: 171 | response = requests.get(url, headers=headers) 172 | response.raise_for_status() 173 | data = response.json() 174 | if data['code'] == 0 and data['data'] and data['data']['View']: 175 | return data['data']['View']['aid'] 176 | else: 177 | print(f"无法获取BV号 {bv_number} 的AID,API返回: {data.get('message', '未知错误')} 或数据结构不符。将尝试使用BV号作为oid。") 178 | return bv_number # 备用方案 179 | except requests.exceptions.RequestException as e: 180 | print(f"获取BV号 {bv_number} 的AID时发生网络错误: {e}。将尝试使用BV号作为oid。") 181 | return bv_number # 备用方案 182 | except json.JSONDecodeError: 183 | print(f"获取BV号 {bv_number} 的AID时解析响应发生JSON解码错误。将尝试使用BV号作为oid。") 184 | return bv_number # 备用方案 185 | except Exception as e: 186 | print(f"获取BV号 {bv_number} 的AID时发生未知错误: {e}。将尝试使用BV号作为oid。") 187 | return bv_number # 备用方案 188 | 189 | 190 | # --- 如何使用 --- 191 | if __name__ == "__main__": 192 | # 在这里列出你想要爬取的BV号 193 | bv_numbers_to_crawl = [ 194 | # 选取5.12号b站综合热门视频前10 195 | "BV1MZFLeJEPR", #【春意红包2025】时隔八年的新老唱见合唱!祝大家巳巳如意,新春大吉! 196 | "BV1WXVoznEWv", # 电脑C盘爆红不用愁。教你4步彻底清理,安全不踩坑 197 | "BV1Z55VznEdq", # 全程高能!历时60天,37位北大学生把106年前的历史写成游戏!破晓以后,重返五四!邀诸君躬身入局,亲手寻觅! 198 | "BV1odVtzREjb", #毕设《父亲的早餐店》 199 | "BV1NhVZzsEdd", #选 择 你 的 干 员 ! 200 | "BV1VRABehEzm", #《丁 咔》 201 | "BV13bEMz3EBD", #【2008.5.12-2025.5.12】今天,为汶川留一分钟 202 | "BV1vVELzeEpZ", #天津早点吃法教程之方便面篇 203 | "BV1KFEMzcE5B", #这玩意凭什么卖这么贵?! 204 | "BV1ui5PzLExa", #一个人开发游戏,新增子弹击中水面水花特效音效,武器开火模式(视频后半段制作的后坐力蓝图,后面会大改下,集合到结构里取值,视频方法比较繁琐) 205 | "BV1Nf55zgEXP", #独立游戏大电影!数年难遇【神作】!《Indie Cross》究竟讲了什么? 206 | "BV1Rs5LzHE2a", #全球排名第一自助餐!每天500种美食!到底都吃什么? 207 | "BV126VrzVED4", #「炉心融解」镜音リン【YYB式镜音铃】[4K/60FPS] 208 | "BV1pG5Mz7EeJ", #三角洲行动 15万无后座100%命中率,真正的平民神器!全新暗杀流M4A1!【A】 209 | "BV1tf5NzEE7T", #花7天蒸一个大馒头,切开以后惊呆了! 210 | "BV1VrVSz1Eme", #【毕导】这个定律,预言了你的人生进度条 211 | "BV1GoVUz1Eow", #角色触摸系统 212 | "BV1NLVSzYEhF", #【白菜手书】第一次在中国买内衣就在大庭广众被量胸…太羞耻了啦!!💦 213 | "BV1zX5LzAEkc", #帮我见证一下,她叫韩琳,欠我一份炒面! 214 | "BV1nXVRzkEYx", #我叔十年前答应送我的直升飞机,造出来了 215 | "BV1g85Vz3E7t", #大二下 周星驰《食神》仿拍 216 | "BV1wSEMzoEMk", #今年暑假前,会有一款超级厉害的游戏问世 217 | "BV1Qs5VzCEGR", #《河南游六花》 218 | "BV14kVRzJEgz", #因为有你们,我每一步都走的那么坚定 219 | "BV1xE55zqEj8", #探秘全球最大的国家!战斗民族,吃什么? 220 | "BV1YWE7zvE4t", #花26万买翡翠赌石,一刀披麻布! 221 | "BV17q55zsEgd", #游戏是逃离现实的通道,让我们成为每一段故事的主角! 222 | "BV1Va5MzeEXk", #【原神】满命火神从蒙德城慢骑到纳塔话事处 223 | "BV1VFVQzHE9V", #敌人看到指挥官第一视角直接吓哭了【三角洲行动】【蜂医日记】 224 | "BV151EuzEEQF", #只是想看看她手机有没有下载反诈App 225 | 226 | 227 | 228 | # 可以添加更多BV号 229 | ] 230 | 231 | for bv in bv_numbers_to_crawl: 232 | crawl_data_and_append(bv) 233 | print("-" * 30) # 分隔不同BV号的爬取过程 234 | time.sleep(random.uniform(3, 15)) -------------------------------------------------------------------------------- /主文件中的代码/Data_visualization.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from pyecharts import options as opts 3 | from pyecharts.charts import Bar, Pie, Page 4 | from pyecharts.faker import Faker 5 | 6 | def visualize_data(filepath, image_path=None, output_excel_path="创作者评估报告.xlsx"): 7 | # 读取数据 8 | data = pd.read_excel(filepath, names=["名字", "性别", "等级", "评论内容", "点赞数", "BERT标签" ], 9 | usecols=[0, 1, 2, 3, 4, 5]) 10 | sentiment_data = pd.read_excel(filepath, names=["性别", "BERT标签"], 11 | usecols=[1, 5]) 12 | # 重新加载BERT标签输出结果数据 13 | analysis_sentiment_data = pd.read_excel(filepath) 14 | # 计算该创作者所有视频的正向和负向评论数量 15 | creator_sentiment_counts = analysis_sentiment_data['BERT标签'].value_counts() 16 | # 计算正向和负向评论的比例 17 | creator_positive_ratio = creator_sentiment_counts.get('正向', 0) / len(analysis_sentiment_data) 18 | creator_negative_ratio = creator_sentiment_counts.get('负向', 0) / len(analysis_sentiment_data) 19 | # 分析不同性别用户对该创作者内容的BERT标签反应 20 | # 计算每个性别的正向和负向评论数量 21 | gender_sentiment_counts = analysis_sentiment_data.groupby('性别')['BERT标签'].value_counts().unstack().fillna(0) 22 | # 计算每个性别的正向和负向评论的比例 23 | gender_positive_ratio = gender_sentiment_counts['正向'] / gender_sentiment_counts.sum(axis=1) 24 | gender_negative_ratio = gender_sentiment_counts['负向'] / gender_sentiment_counts.sum(axis=1) 25 | # 整理创作者分析画像文本 26 | creator_analysis_text = f""" 27 |
28 |

创作者整体情感分析画像

29 |

正向评论比例: 正向评论占比为 {creator_positive_ratio:.2%}

30 |

负向评论比例: 负向评论占比为 {creator_negative_ratio:.2%}

31 |

不同性别用户情感反应分析

32 |

正向评论比例:

33 | 38 |

负向评论比例:

39 | 44 |
45 | """ 46 | # ---------------------- 创作者分析画像代码 (到这里结束) ---------------------- 47 | 48 | 49 | # ---------------------- 创作者综合评估代码 (从这里开始添加) ---------------------- 50 | def evaluate_creator_sentiment(df, output_file="创作者综合评估结果.xlsx"): # 内部函数,接收 DataFrame 51 | # 处理点赞数字段 52 | df['点赞数'] = pd.to_numeric(df['点赞数'], errors='coerce').fillna(0).astype(int) 53 | 54 | # 筛选点赞数TOP100的评论 55 | top_100 = df.nlargest(100, '点赞数') 56 | 57 | # 分离正向/负向评论(中向评论不参与计算) 58 | positive = top_100[top_100['BERT标签'] == '正向'] 59 | negative = top_100[top_100['BERT标签'] == '负向'] 60 | 61 | # 采用BERT标签后的加权得分(正向/负向评论点赞数之和) 62 | positive_score = positive['点赞数'].sum() 63 | negative_score = negative['点赞数'].sum() 64 | 65 | # 计算评论比例 66 | total = len(positive) + len(negative) 67 | positive_ratio = len(positive) / total if total > 0 else 0 68 | negative_ratio = len(negative) / total if total > 0 else 0 69 | 70 | # 综合评分公式(可调整系数) 71 | score_ratio = positive_score / (positive_score + negative_score) if (positive_score + negative_score) > 0 else 0 72 | comprehensive_score = 0.7 * score_ratio + 0.3 * positive_ratio # 70%权重给得分占比,30%权重给数量比例 73 | 74 | # 综合评判 75 | if comprehensive_score > 0.7: 76 | creator_type = "强烈推荐创作者" 77 | elif comprehensive_score > 0.6: 78 | creator_type = "正向创作者" 79 | elif comprehensive_score > 0.4: 80 | creator_type = "中立创作者" 81 | else: 82 | creator_type = "负向创作者" 83 | 84 | # 提取高频词 85 | import jieba 86 | import re 87 | 88 | # 读取停用词列表 89 | try: 90 | with open("hit_stopwords.txt", 'r', encoding='utf-8') as f: 91 | stopwords = f.read().splitlines() 92 | except: 93 | stopwords = [] 94 | 95 | # 合并所有评论内容为一个字符串 96 | all_comments = ' '.join(df["评论内容"].astype(str)) 97 | 98 | # 使用正则表达式过滤掉特殊字符和数字 99 | all_comments = re.sub(r'[\[\](){}@,.?!;:"\'\d]+', '', all_comments) 100 | 101 | # 分词并去除停用词 102 | data_cut = jieba.lcut(all_comments) 103 | data_after = [i for i in data_cut if i not in stopwords and len(i.strip()) > 1] 104 | 105 | # 统计词频 106 | word_freq = pd.Series(data_after).value_counts().head(10) 107 | top_words = "、".join([f"{word}({count})" for word, count in word_freq.items()]) 108 | 109 | # 生成详细报告 110 | report = f""" 111 |
112 |

创作者综合评估报告

113 |

* 核心指标分析 *

114 | 120 |

* 创作者类型 *

121 |

{creator_type}

122 |

创作者高频词为:{top_words}

123 |

【评分逻辑说明】

124 |
    125 |
  1. TOP100高赞评论加权:正向评论点赞数之和,负向评论点赞数之和
  2. 126 |
  3. 综合评分 = 70%×正向得分占比 + 30%×正向评论数量占比
  4. 127 |
  5. 评价阈值:>0.7强烈推荐,>0.6正向,>0.4中立,≤0.4负向
  6. 128 |
129 |
130 | """ 131 | 132 | # 保存结果到 Excel 133 | result_df = pd.DataFrame({ 134 | '指标': ['正向得分', '负向得分', '正向评论数', '负向评论数', '综合评分', '创作者类型'], 135 | '数值': [positive_score, negative_score, len(positive), len(negative), comprehensive_score, creator_type], 136 | '说明': [ 137 | "正向评论点赞数之和", 138 | "负向评论点赞数之和", 139 | "TOP100中正向评论数量", 140 | "TOP100中负向评论数量", 141 | "0.7×得分占比 + 0.3×数量占比", 142 | "基于综合评分阈值判定" 143 | ] 144 | }) 145 | 146 | with pd.ExcelWriter(output_file) as writer: 147 | result_df.to_excel(writer, sheet_name='评估结果', index=False) 148 | pd.DataFrame({'报告内容': [report]}).to_excel(writer, sheet_name='分析报告', index=False) 149 | 150 | return report, output_file # 返回报告文本和 Excel 文件路径 151 | 152 | 153 | evaluation_report_text, excel_output_path = evaluate_creator_sentiment(analysis_sentiment_data, output_excel_path) # 调用评估函数 154 | creator_analysis_text += evaluation_report_text # 将评估报告文本添加到创作者分析画像文本中 155 | # ---------------------- 创作者综合评估代码 (到这里结束) ---------------------- 156 | 157 | 158 | # 创建Page对象 159 | page = Page(layout=Page.SimplePageLayout, page_title="B站评论数据可视化分析") # 简单垂直布局, 设置HTML页面标题 160 | 161 | # 点赞数Top20的评论柱状图 162 | df1 = data.sort_values(by="点赞数", ascending=False).head(20) 163 | bar = ( 164 | Bar() 165 | .add_xaxis(df1["评论内容"].to_list()) 166 | .add_yaxis("点赞数", df1["点赞数"].to_list(), color=Faker.rand_color()) 167 | .set_global_opts( 168 | title_opts=opts.TitleOpts(title="评论热度Top20"), 169 | datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_="inside")] 170 | ) 171 | ) 172 | page.add(bar) 173 | 174 | # 用户等级分布饼图 175 | level_pie = ( 176 | Pie() 177 | .add( 178 | "", 179 | [list(z) for z in zip([str(i) for i in range(7)], 180 | data.等级.value_counts().sort_index(ascending=False).to_list())], 181 | radius=["40%", "75%"] 182 | ) 183 | .set_global_opts( 184 | title_opts=opts.TitleOpts(title="用户等级分布"), 185 | legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%") 186 | ) 187 | .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}")) 188 | ) 189 | page.add(level_pie) 190 | 191 | # 用户性别分布饼图 192 | gender_pie = ( 193 | Pie() 194 | .add( 195 | "", 196 | [list(z) for z in zip(["男", "女", "保密"], 197 | data.性别.value_counts().sort_index(ascending=False).to_list())], 198 | radius=["40%", "75%"] 199 | ) 200 | .set_global_opts( 201 | title_opts=opts.TitleOpts(title="用户性别分布"), 202 | legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%") 203 | ) 204 | .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}")) 205 | ) 206 | page.add(gender_pie) 207 | 208 | # 情感倾向饼图(分性别) 209 | for gender in ["男", "女", "保密"]: 210 | gender_sentiment = sentiment_data[sentiment_data["性别"] == gender]["BERT标签"].value_counts() 211 | sentiment_pie = ( 212 | Pie() 213 | .add( 214 | "", 215 | [list(z) for z in zip(["积极", "中性", "消极"], gender_sentiment.tolist())], 216 | radius=["40%", "75%"] 217 | ) 218 | .set_global_opts( 219 | title_opts=opts.TitleOpts(title=f"{gender}性别情感倾向分布"), 220 | legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%") 221 | ) 222 | .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}")) 223 | ) 224 | page.add(sentiment_pie) 225 | 226 | # 统一渲染到单个HTML文件 227 | page.render("所有可视化图表.html") 228 | 229 | # 将创作者分析文本追加到 HTML 文件末尾 230 | with open("所有可视化图表.html", "r+", encoding='utf-8') as f: 231 | html_content = f.read() 232 | # 在 标签前插入创作者分析文本 233 | html_content = html_content.replace("", creator_analysis_text + "") 234 | f.seek(0) # 将文件指针移动到文件开头 235 | f.write(html_content) # 重新写入修改后的HTML内容 236 | f.truncate() # 移除文件剩余部分 237 | 238 | 239 | # 如果需要生成图片 (这部分代码可以根据您的需求保留或移除) 240 | if image_path: 241 | import os 242 | from selenium import webdriver 243 | from PIL import Image 244 | 245 | options = webdriver.ChromeOptions() 246 | options.add_argument("--headless") 247 | driver = webdriver.Chrome(options=options) 248 | driver.get("file://" + os.path.abspath("所有可视化图表.html")) 249 | driver.save_screenshot(image_path) 250 | driver.quit() 251 | img = Image.open(image_path) 252 | img = img.crop(img.getbbox()) # 裁剪图片 253 | img.save(image_path) 254 | 255 | # 使用示例 256 | #visualize_data("情感输出结果_bert.xlsx", output_excel_path="创作者评估报告_bert.xlsx") # 同时指定 Excel 输出路径 -------------------------------------------------------------------------------- /情感分析_bert微调_demo (1).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 微调 Chinese-BERT-wwm-ext 模型用于三分类情感分析\n", 8 | "\n", 9 | "本 Notebook 用于在魔塔平台上微调 `hfl/chinese-bert-wwm-ext` 模型,\n", 10 | "数据源为本地上传的 `评论情感分析结果_三分类_人工纠错.xlsx` 文件,使用 Huggingface `transformers` 库进行训练。" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "execution": { 18 | "iopub.execute_input": "2025-05-13T06:26:52.763934Z", 19 | "iopub.status.busy": "2025-05-13T06:26:52.763651Z", 20 | "iopub.status.idle": "2025-05-13T06:26:57.870768Z", 21 | "shell.execute_reply": "2025-05-13T06:26:57.870271Z", 22 | "shell.execute_reply.started": "2025-05-13T06:26:52.763920Z" 23 | }, 24 | "tags": [] 25 | }, 26 | "outputs": [ 27 | { 28 | "name": "stdout", 29 | "output_type": "stream", 30 | "text": [ 31 | "Looking in indexes: https://mirrors.cloud.aliyuncs.com/pypi/simple\n", 32 | "Requirement already satisfied: transformers in /usr/local/lib/python3.11/site-packages (4.48.3)\n", 33 | "Requirement already satisfied: datasets in /usr/local/lib/python3.11/site-packages (3.2.0)\n", 34 | "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.11/site-packages (1.6.1)\n", 35 | "Requirement already satisfied: openpyxl in /usr/local/lib/python3.11/site-packages (3.1.5)\n", 36 | "Requirement already satisfied: filelock in /usr/local/lib/python3.11/site-packages (from transformers) (3.17.0)\n", 37 | "Requirement already satisfied: huggingface-hub<1.0,>=0.24.0 in /usr/local/lib/python3.11/site-packages (from transformers) (0.25.2)\n", 38 | "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/site-packages (from transformers) (1.26.4)\n", 39 | "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/site-packages (from transformers) (24.2)\n", 40 | "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/site-packages (from transformers) (6.0.2)\n", 41 | "Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.11/site-packages (from transformers) (2024.11.6)\n", 42 | "Requirement already satisfied: requests in /usr/local/lib/python3.11/site-packages (from transformers) (2.32.3)\n", 43 | "Requirement already satisfied: tokenizers<0.22,>=0.21 in /usr/local/lib/python3.11/site-packages (from transformers) (0.21.1)\n", 44 | "Requirement already satisfied: safetensors>=0.4.1 in /usr/local/lib/python3.11/site-packages (from transformers) (0.5.3)\n", 45 | "Requirement already satisfied: tqdm>=4.27 in /usr/local/lib/python3.11/site-packages (from transformers) (4.67.1)\n", 46 | "Requirement already satisfied: pyarrow>=15.0.0 in /usr/local/lib/python3.11/site-packages (from datasets) (19.0.1)\n", 47 | "Requirement already satisfied: dill<0.3.9,>=0.3.0 in /usr/local/lib/python3.11/site-packages (from datasets) (0.3.8)\n", 48 | "Requirement already satisfied: pandas in /usr/local/lib/python3.11/site-packages (from datasets) (2.2.3)\n", 49 | "Requirement already satisfied: xxhash in /usr/local/lib/python3.11/site-packages (from datasets) (3.5.0)\n", 50 | "Requirement already satisfied: multiprocess<0.70.17 in /usr/local/lib/python3.11/site-packages (from datasets) (0.70.16)\n", 51 | "Requirement already satisfied: fsspec<=2024.9.0,>=2023.1.0 in /usr/local/lib/python3.11/site-packages (from fsspec[http]<=2024.9.0,>=2023.1.0->datasets) (2024.9.0)\n", 52 | "Requirement already satisfied: aiohttp in /usr/local/lib/python3.11/site-packages (from datasets) (3.11.16)\n", 53 | "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.11/site-packages (from scikit-learn) (1.12.0)\n", 54 | "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/site-packages (from scikit-learn) (1.4.2)\n", 55 | "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/site-packages (from scikit-learn) (3.6.0)\n", 56 | "Requirement already satisfied: et-xmlfile in /usr/local/lib/python3.11/site-packages (from openpyxl) (2.0.0)\n", 57 | "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (2.6.1)\n", 58 | "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (1.3.2)\n", 59 | "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (25.3.0)\n", 60 | "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (1.5.0)\n", 61 | "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (6.4.2)\n", 62 | "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (0.3.1)\n", 63 | "Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.11/site-packages (from aiohttp->datasets) (1.19.0)\n", 64 | "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.11/site-packages (from huggingface-hub<1.0,>=0.24.0->transformers) (4.12.2)\n", 65 | "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests->transformers) (3.4.1)\n", 66 | "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests->transformers) (3.10)\n", 67 | "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/site-packages (from requests->transformers) (2.3.0)\n", 68 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests->transformers) (2025.1.31)\n", 69 | "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas->datasets) (2.9.0.post0)\n", 70 | "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/site-packages (from pandas->datasets) (2025.2)\n", 71 | "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/site-packages (from pandas->datasets) (2025.2)\n", 72 | "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.17.0)\n", 73 | "\u001b[33mDEPRECATION: pytorch-lightning 1.7.7 has a non-standard dependency specifier torch>=1.9.*. pip 24.0 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of pytorch-lightning or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", 74 | "\u001b[0m\u001b[33mDEPRECATION: omegaconf 2.0.6 has a non-standard dependency specifier PyYAML>=5.1.*. pip 24.0 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of omegaconf or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", 75 | "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", 76 | "\u001b[0m\n", 77 | "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.3.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.1.1\u001b[0m\n", 78 | "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" 79 | ] 80 | } 81 | ], 82 | "source": [ 83 | "# 安装所需库\n", 84 | "!pip install transformers datasets scikit-learn openpyxl" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 2, 90 | "metadata": { 91 | "execution": { 92 | "iopub.execute_input": "2025-05-13T06:26:59.904201Z", 93 | "iopub.status.busy": "2025-05-13T06:26:59.903891Z", 94 | "iopub.status.idle": "2025-05-13T06:27:08.198482Z", 95 | "shell.execute_reply": "2025-05-13T06:27:08.198024Z", 96 | "shell.execute_reply.started": "2025-05-13T06:26:59.904178Z" 97 | }, 98 | "tags": [] 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stderr", 103 | "output_type": "stream", 104 | "text": [ 105 | "2025-05-13 14:27:05.567220: I tensorflow/core/util/port.cc:113] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", 106 | "2025-05-13 14:27:05.607916: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", 107 | "To enable the following instructions: AVX2 AVX512F AVX512_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", 108 | "2025-05-13 14:27:06.788014: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" 109 | ] 110 | } 111 | ], 112 | "source": [ 113 | "# 导入必要的库\n", 114 | "import pandas as pd\n", 115 | "from sklearn.model_selection import train_test_split\n", 116 | "from datasets import Dataset\n", 117 | "from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments\n", 118 | "from sklearn.metrics import accuracy_score, f1_score\n", 119 | "import torch" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 3, 125 | "metadata": { 126 | "ExecutionIndicator": { 127 | "show": true 128 | }, 129 | "execution": { 130 | "iopub.execute_input": "2025-05-13T06:27:15.999048Z", 131 | "iopub.status.busy": "2025-05-13T06:27:15.998506Z", 132 | "iopub.status.idle": "2025-05-13T06:27:16.044195Z", 133 | "shell.execute_reply": "2025-05-13T06:27:16.043598Z", 134 | "shell.execute_reply.started": "2025-05-13T06:27:15.999026Z" 135 | }, 136 | "tags": [] 137 | }, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "Index(['name', 'gender', 'level', 'comment', 'likes', 'emotion', 'score',\n", 144 | " 'status'],\n", 145 | " dtype='object')\n" 146 | ] 147 | } 148 | ], 149 | "source": [ 150 | "\n", 151 | "# 正确读取 CSV 文件\n", 152 | "df = pd.read_csv(\"评论情感分析结果_三分类_人工纠错.csv\")\n", 153 | "print(df.columns)\n", 154 | "\n", 155 | "# 只保留需要的列\n", 156 | "df = df[[\"comment\", \"emotion\"]].dropna()\n", 157 | "\n", 158 | "# 标签编码\n", 159 | "label2id = {label: i for i, label in enumerate(sorted(df[\"emotion\"].unique()))}\n", 160 | "id2label = {v: k for k, v in label2id.items()}\n", 161 | "df[\"label\"] = df[\"emotion\"].map(label2id)\n", 162 | "\n", 163 | "# 划分训练和验证集\n", 164 | "train_df, val_df = train_test_split(df, test_size=0.2, stratify=df[\"label\"], random_state=42)\n", 165 | "\n", 166 | "# 转换为 Huggingface Dataset\n", 167 | "train_dataset = Dataset.from_pandas(train_df[[\"comment\", \"label\"]])\n", 168 | "val_dataset = Dataset.from_pandas(val_df[[\"comment\", \"label\"]])" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 5, 174 | "metadata": { 175 | "ExecutionIndicator": { 176 | "show": true 177 | }, 178 | "execution": { 179 | "iopub.execute_input": "2025-05-13T06:43:20.730499Z", 180 | "iopub.status.busy": "2025-05-13T06:43:20.730021Z", 181 | "iopub.status.idle": "2025-05-13T06:49:33.039234Z", 182 | "shell.execute_reply": "2025-05-13T06:49:33.038683Z", 183 | "shell.execute_reply.started": "2025-05-13T06:43:20.730479Z" 184 | }, 185 | "tags": [] 186 | }, 187 | "outputs": [ 188 | { 189 | "data": { 190 | "application/vnd.jupyter.widget-view+json": { 191 | "model_id": "9342b568a23440bf93df158147174f4d", 192 | "version_major": 2, 193 | "version_minor": 0 194 | }, 195 | "text/plain": [ 196 | "Map: 0%| | 0/2326 [00:00\n", 239 | " \n", 240 | " \n", 241 | " [370/370 06:05, Epoch 10/10]\n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | "
EpochTraining LossValidation LossAccuracyF1
10.8404000.7767390.6219930.491917
20.7135000.6706880.6254300.484861
30.6108000.5738730.7319590.726990
40.5009000.4743350.7886600.789913
50.3692000.4486460.7989690.792224
60.2649000.5427220.8075600.795235
70.2104000.5005730.8075600.802721
80.1568000.6238860.7800690.774986
90.0635000.9251550.7749140.767471
100.0995000.8381260.7749140.767471

" 326 | ], 327 | "text/plain": [ 328 | "" 329 | ] 330 | }, 331 | "metadata": {}, 332 | "output_type": "display_data" 333 | }, 334 | { 335 | "name": "stdout", 336 | "output_type": "stream", 337 | "text": [ 338 | "训练完成,正在评估最终模型...\n" 339 | ] 340 | }, 341 | { 342 | "data": { 343 | "text/html": [ 344 | "\n", 345 | "

\n", 346 | " \n", 347 | " \n", 348 | " [10/10 00:02]\n", 349 | "
\n", 350 | " " 351 | ], 352 | "text/plain": [ 353 | "" 354 | ] 355 | }, 356 | "metadata": {}, 357 | "output_type": "display_data" 358 | }, 359 | { 360 | "name": "stdout", 361 | "output_type": "stream", 362 | "text": [ 363 | "最终评估结果: {'eval_loss': 0.5005733370780945, 'eval_accuracy': 0.8075601374570447, 'eval_f1': 0.8027207865194665, 'eval_runtime': 2.6099, 'eval_samples_per_second': 222.996, 'eval_steps_per_second': 3.832, 'epoch': 10.0}\n" 364 | ] 365 | }, 366 | { 367 | "data": { 368 | "text/plain": [ 369 | "('./final_model/tokenizer_config.json',\n", 370 | " './final_model/special_tokens_map.json',\n", 371 | " './final_model/vocab.txt',\n", 372 | " './final_model/added_tokens.json')" 373 | ] 374 | }, 375 | "execution_count": 5, 376 | "metadata": {}, 377 | "output_type": "execute_result" 378 | } 379 | ], 380 | "source": [ 381 | "# 定义本地模型路径\n", 382 | "model_path = \"./modelbert\" # 假设你的模型文件在当前目录下的 modelbert 文件夹中\n", 383 | "\n", 384 | "# 加载 tokenizer\n", 385 | "tokenizer = BertTokenizer.from_pretrained(model_path)\n", 386 | "\n", 387 | "# 定义 tokenization 函数\n", 388 | "def tokenize_function(examples):\n", 389 | " return tokenizer(examples[\"comment\"], padding=\"max_length\", truncation=True, max_length=256) # 你可以根据需要调整 max_length\n", 390 | "\n", 391 | "# 应用 tokenization 到数据集\n", 392 | "tokenized_train_dataset = train_dataset.map(tokenize_function, batched=True)\n", 393 | "tokenized_val_dataset = val_dataset.map(tokenize_function, batched=True)\n", 394 | "\n", 395 | "# 加载模型\n", 396 | "# num_labels 需要设置为你的分类类别数量 (这里是 3)\n", 397 | "model = BertForSequenceClassification.from_pretrained(model_path, num_labels=len(label2id), id2label=id2label, label2id=label2id)\n", 398 | "\n", 399 | "# 定义评估指标\n", 400 | "def compute_metrics(eval_pred):\n", 401 | " predictions, labels = eval_pred\n", 402 | " predictions = predictions.argmax(axis=1)\n", 403 | " accuracy = accuracy_score(labels, predictions)\n", 404 | " f1 = f1_score(labels, predictions, average='weighted') # 对于多分类使用 weighted f1\n", 405 | " return {\"accuracy\": accuracy, \"f1\": f1}\n", 406 | "\n", 407 | "# 定义训练参数\n", 408 | "training_args = TrainingArguments(\n", 409 | " output_dir=\"./results\", # 训练输出目录\n", 410 | " num_train_epochs=10, # 训练的总 epoch 数,可以根据需要调整\n", 411 | " per_device_train_batch_size=64, # 每个设备的训练 batch size\n", 412 | " per_device_eval_batch_size=64, # 每个设备的评估 batch size\n", 413 | " warmup_steps=500, # warmup 步数\n", 414 | " learning_rate=3e-5, # 学习率\n", 415 | " weight_decay=0.01, # weight decay\n", 416 | " logging_dir=\"./logs\", # log 目录\n", 417 | " logging_steps=10, # 每隔多少步记录一次 log\n", 418 | " evaluation_strategy=\"epoch\", # 每个 epoch 结束后进行评估\n", 419 | " save_strategy=\"epoch\", # 每个 epoch 结束后保存模型\n", 420 | " load_best_model_at_end=True, # 训练结束后加载在验证集上表现最好的模型\n", 421 | " metric_for_best_model=\"f1\", # 用 f1 作为选择最好模型的指标\n", 422 | " greater_is_better=True, # f1 越大越好\n", 423 | " report_to=\"none\", # 不上传到任何平台,如果需要可以改为 \"tensorboard\" 或其他\n", 424 | ")\n", 425 | "\n", 426 | "# 初始化 Trainer\n", 427 | "trainer = Trainer(\n", 428 | " model=model, # 要训练的模型\n", 429 | " args=training_args, # 训练参数\n", 430 | " train_dataset=tokenized_train_dataset, # 训练数据集\n", 431 | " eval_dataset=tokenized_val_dataset, # 评估数据集\n", 432 | " compute_metrics=compute_metrics, # 评估指标函数\n", 433 | ")\n", 434 | "\n", 435 | "# 开始训练\n", 436 | "print(\"开始训练...\")\n", 437 | "trainer.train()\n", 438 | "\n", 439 | "# 评估训练完成后的模型(加载的是最好的模型)\n", 440 | "print(\"训练完成,正在评估最终模型...\")\n", 441 | "eval_results = trainer.evaluate()\n", 442 | "print(f\"最终评估结果: {eval_results}\")\n", 443 | "\n", 444 | "# 你现在可以保存最终的模型和 tokenizer\n", 445 | "trainer.save_model(\"./final_model\")\n", 446 | "tokenizer.save_pretrained(\"./final_model\")" 447 | ] 448 | } 449 | ], 450 | "metadata": { 451 | "kernelspec": { 452 | "display_name": "Python 3 (ipykernel)", 453 | "language": "python", 454 | "name": "python3" 455 | }, 456 | "language_info": { 457 | "codemirror_mode": { 458 | "name": "ipython", 459 | "version": 3 460 | }, 461 | "file_extension": ".py", 462 | "mimetype": "text/x-python", 463 | "name": "python", 464 | "nbconvert_exporter": "python", 465 | "pygments_lexer": "ipython3", 466 | "version": "3.11.11" 467 | } 468 | }, 469 | "nbformat": 4, 470 | "nbformat_minor": 4 471 | } 472 | -------------------------------------------------------------------------------- /主文件中的代码/hit_stopwords.txt: -------------------------------------------------------------------------------- 1 | ——— 2 | 》), 3 | )÷(1- 4 | ”, 5 | )、 6 | =( 7 | : 8 | → 9 | ℃ 10 | & 11 | * 12 | 一一 13 | ~~~~ 14 | ’ 15 | . 16 | 『 17 | .一 18 | ./ 19 | -- 20 | 』 21 | =″ 22 | 【 23 | [*] 24 | }> 25 | [⑤]] 26 | [①D] 27 | c] 28 | ng昉 29 | * 30 | // 31 | [ 32 | ] 33 | [②e] 34 | [②g] 35 | ={ 36 | } 37 | ,也 38 | ‘ 39 | A 40 | [①⑥] 41 | [②B] 42 | [①a] 43 | [④a] 44 | [①③] 45 | [③h] 46 | ③] 47 | 1. 48 | -- 49 | [②b] 50 | ’‘ 51 | ××× 52 | [①⑧] 53 | 0:2 54 | =[ 55 | [⑤b] 56 | [②c] 57 | [④b] 58 | [②③] 59 | [③a] 60 | [④c] 61 | [①⑤] 62 | [①⑦] 63 | [①g] 64 | ∈[ 65 | [①⑨] 66 | [①④] 67 | [①c] 68 | [②f] 69 | [②⑧] 70 | [②①] 71 | [①C] 72 | [③c] 73 | [③g] 74 | [②⑤] 75 | [②②] 76 | 一. 77 | [①h] 78 | .数 79 | [] 80 | [①B] 81 | 数/ 82 | [①i] 83 | [③e] 84 | [①①] 85 | [④d] 86 | [④e] 87 | [③b] 88 | [⑤a] 89 | [①A] 90 | [②⑧] 91 | [②⑦] 92 | [①d] 93 | [②j] 94 | 〕〔 95 | ][ 96 | :// 97 | ′∈ 98 | [②④ 99 | [⑤e] 100 | 12% 101 | b] 102 | ... 103 | ................... 104 | …………………………………………………③ 105 | ZXFITL 106 | [③F] 107 | 」 108 | [①o] 109 | ]∧′=[ 110 | ∪φ∈ 111 | ′| 112 | {- 113 | ②c 114 | } 115 | [③①] 116 | R.L. 117 | [①E] 118 | Ψ 119 | -[*]- 120 | ↑ 121 | .日 122 | [②d] 123 | [② 124 | [②⑦] 125 | [②②] 126 | [③e] 127 | [①i] 128 | [①B] 129 | [①h] 130 | [①d] 131 | [①g] 132 | [①②] 133 | [②a] 134 | f] 135 | [⑩] 136 | a] 137 | [①e] 138 | [②h] 139 | [②⑥] 140 | [③d] 141 | [②⑩] 142 | e] 143 | 〉 144 | 】 145 | 元/吨 146 | [②⑩] 147 | 2.3% 148 | 5:0 149 | [①] 150 | :: 151 | [②] 152 | [③] 153 | [④] 154 | [⑤] 155 | [⑥] 156 | [⑦] 157 | [⑧] 158 | [⑨] 159 | …… 160 | —— 161 | ? 162 | 、 163 | 。 164 | “ 165 | ” 166 | 《 167 | 》 168 | ! 169 | , 170 | : 171 | ; 172 | ? 173 | . 174 | , 175 | . 176 | ' 177 | ? 178 | · 179 | ——— 180 | ── 181 | ? 182 | — 183 | < 184 | > 185 | ( 186 | ) 187 | 〔 188 | 〕 189 | [ 190 | ] 191 | ( 192 | ) 193 | - 194 | + 195 | ~ 196 | × 197 | / 198 | / 199 | ① 200 | ② 201 | ③ 202 | ④ 203 | ⑤ 204 | ⑥ 205 | ⑦ 206 | ⑧ 207 | ⑨ 208 | ⑩ 209 | Ⅲ 210 | В 211 | " 212 | ; 213 | # 214 | @ 215 | γ 216 | μ 217 | φ 218 | φ. 219 | × 220 | Δ 221 | ■ 222 | ▲ 223 | sub 224 | exp 225 | sup 226 | sub 227 | Lex 228 | # 229 | % 230 | & 231 | ' 232 | + 233 | +ξ 234 | ++ 235 | - 236 | -β 237 | < 238 | <± 239 | <Δ 240 | <λ 241 | <φ 242 | << 243 | = 244 | = 245 | =☆ 246 | =- 247 | > 248 | >λ 249 | _ 250 | ~± 251 | ~+ 252 | [⑤f] 253 | [⑤d] 254 | [②i] 255 | ≈ 256 | [②G] 257 | [①f] 258 | LI 259 | ㈧ 260 | [- 261 | ...... 262 | 〉 263 | [③⑩] 264 | 第二 265 | 一番 266 | 一直 267 | 一个 268 | 一些 269 | 许多 270 | 种 271 | 有的是 272 | 也就是说 273 | 末##末 274 | 啊 275 | 阿 276 | 哎 277 | 哎呀 278 | 哎哟 279 | 唉 280 | 俺 281 | 俺们 282 | 按 283 | 按照 284 | 吧 285 | 吧哒 286 | 把 287 | 罢了 288 | 被 289 | 本 290 | 本着 291 | 比 292 | 比方 293 | 比如 294 | 鄙人 295 | 彼 296 | 彼此 297 | 边 298 | 别 299 | 别的 300 | 别说 301 | 并 302 | 并且 303 | 不 304 | 都 305 | 好 306 | 去 307 | 不比 308 | 不成 309 | 不单 310 | 不但 311 | 不独 312 | 不管 313 | 不光 314 | 不过 315 | 不仅 316 | 不拘 317 | 不论 318 | 不怕 319 | 不然 320 | 不如 321 | 不特 322 | 不惟 323 | 不问 324 | 不只 325 | 朝 326 | 朝着 327 | 趁 328 | 趁着 329 | 乘 330 | 冲 331 | 除 332 | 除此之外 333 | 除非 334 | 除了 335 | 此 336 | 此间 337 | 此外 338 | 从 339 | 从而 340 | 打 341 | 待 342 | 但 343 | 但是 344 | 当 345 | 当着 346 | 到 347 | 得 348 | 的 349 | 的话 350 | 等 351 | 等等 352 | 地 353 | 第 354 | 叮咚 355 | 对 356 | 对于 357 | 多 358 | 多少 359 | 而 360 | 而况 361 | 而且 362 | 而是 363 | 而外 364 | 而言 365 | 而已 366 | 尔后 367 | 反过来 368 | 反过来说 369 | 反之 370 | 非但 371 | 非徒 372 | 否则 373 | 嘎 374 | 嘎登 375 | 该 376 | 赶 377 | 个 378 | 各 379 | 各个 380 | 各位 381 | 各种 382 | 各自 383 | 给 384 | 根据 385 | 跟 386 | 故 387 | 故此 388 | 固然 389 | 关于 390 | 管 391 | 归 392 | 果然 393 | 果真 394 | 过 395 | 哈 396 | 哈哈 397 | 呵 398 | 和 399 | 何 400 | 何处 401 | 何况 402 | 何时 403 | 嘿 404 | 哼 405 | 哼唷 406 | 呼哧 407 | 乎 408 | 哗 409 | 还是 410 | 还有 411 | 换句话说 412 | 换言之 413 | 或 414 | 或是 415 | 或者 416 | 极了 417 | 及 418 | 及其 419 | 及至 420 | 即 421 | 即便 422 | 即或 423 | 即令 424 | 即若 425 | 即使 426 | 几 427 | 几时 428 | 己 429 | 既 430 | 既然 431 | 既是 432 | 继而 433 | 加之 434 | 假如 435 | 假若 436 | 假使 437 | 鉴于 438 | 将 439 | 较 440 | 较之 441 | 叫 442 | 接着 443 | 结果 444 | 借 445 | 紧接着 446 | 进而 447 | 尽 448 | 尽管 449 | 经 450 | 经过 451 | 就 452 | 就是 453 | 就是说 454 | 据 455 | 具体地说 456 | 具体说来 457 | 开始 458 | 开外 459 | 靠 460 | 咳 461 | 可 462 | 可见 463 | 可是 464 | 可以 465 | 况且 466 | 啦 467 | 来 468 | 来着 469 | 离 470 | 例如 471 | 哩 472 | 连 473 | 连同 474 | 两者 475 | 了 476 | 临 477 | 另 478 | 另外 479 | 另一方面 480 | 论 481 | 嘛 482 | 吗 483 | 慢说 484 | 漫说 485 | 冒 486 | 么 487 | 每 488 | 每当 489 | 们 490 | 莫若 491 | 某 492 | 某个 493 | 某些 494 | 拿 495 | 哪 496 | 哪边 497 | 哪儿 498 | 哪个 499 | 哪里 500 | 哪年 501 | 哪怕 502 | 哪天 503 | 哪些 504 | 哪样 505 | 那 506 | 那边 507 | 那儿 508 | 那个 509 | 那会儿 510 | 那里 511 | 那么 512 | 那么些 513 | 那么样 514 | 那时 515 | 那些 516 | 那样 517 | 乃 518 | 乃至 519 | 呢 520 | 能 521 | 你 522 | 你们 523 | 您 524 | 宁 525 | 宁可 526 | 宁肯 527 | 宁愿 528 | 哦 529 | 呕 530 | 啪达 531 | 旁人 532 | 呸 533 | 凭 534 | 凭借 535 | 其 536 | 其次 537 | 其二 538 | 其他 539 | 其它 540 | 其一 541 | 其余 542 | 其中 543 | 起 544 | 起见 545 | 起见 546 | 岂但 547 | 恰恰相反 548 | 前后 549 | 前者 550 | 且 551 | 然而 552 | 然后 553 | 然则 554 | 让 555 | 人家 556 | 任 557 | 任何 558 | 任凭 559 | 如 560 | 如此 561 | 如果 562 | 如何 563 | 如其 564 | 如若 565 | 如上所述 566 | 若 567 | 若非 568 | 若是 569 | 啥 570 | 上下 571 | 尚且 572 | 设若 573 | 设使 574 | 甚而 575 | 甚么 576 | 甚至 577 | 省得 578 | 时候 579 | 什么 580 | 什么样 581 | 使得 582 | 是 583 | 是的 584 | 首先 585 | 谁 586 | 谁知 587 | 顺 588 | 顺着 589 | 似的 590 | 虽 591 | 虽然 592 | 虽说 593 | 虽则 594 | 随 595 | 随着 596 | 所 597 | 所以 598 | 他 599 | 他们 600 | 他人 601 | 它 602 | 它们 603 | 她 604 | 她们 605 | 倘 606 | 倘或 607 | 倘然 608 | 倘若 609 | 倘使 610 | 腾 611 | 替 612 | 通过 613 | 同 614 | 同时 615 | 哇 616 | 万一 617 | 往 618 | 望 619 | 为 620 | 为何 621 | 为了 622 | 为什么 623 | 为着 624 | 喂 625 | 嗡嗡 626 | 我 627 | 我们 628 | 呜 629 | 呜呼 630 | 乌乎 631 | 无论 632 | 无宁 633 | 毋宁 634 | 嘻 635 | 吓 636 | 相对而言 637 | 像 638 | 向 639 | 向着 640 | 嘘 641 | 呀 642 | 焉 643 | 沿 644 | 沿着 645 | 要 646 | 要不 647 | 要不然 648 | 要不是 649 | 要么 650 | 要是 651 | 也 652 | 也罢 653 | 也好 654 | 一 655 | 一般 656 | 一旦 657 | 一方面 658 | 一来 659 | 一切 660 | 一样 661 | 一则 662 | 依 663 | 依照 664 | 矣 665 | 以 666 | 以便 667 | 以及 668 | 以免 669 | 以至 670 | 以至于 671 | 以致 672 | 抑或 673 | 因 674 | 因此 675 | 因而 676 | 因为 677 | 哟 678 | 用 679 | 由 680 | 由此可见 681 | 由于 682 | 有 683 | 有的 684 | 有关 685 | 有些 686 | 又 687 | 于 688 | 于是 689 | 于是乎 690 | 与 691 | 与此同时 692 | 与否 693 | 与其 694 | 越是 695 | 云云 696 | 哉 697 | 再说 698 | 再者 699 | 在 700 | 在下 701 | 咱 702 | 咱们 703 | 则 704 | 怎 705 | 怎么 706 | 怎么办 707 | 怎么样 708 | 怎样 709 | 咋 710 | 照 711 | 照着 712 | 者 713 | 这 714 | 这边 715 | 这儿 716 | 这个 717 | 这会儿 718 | 这就是说 719 | 这里 720 | 这么 721 | 这么点儿 722 | 这么些 723 | 这么样 724 | 这时 725 | 这些 726 | 这样 727 | 正如 728 | 吱 729 | 之 730 | 之类 731 | 之所以 732 | 之一 733 | 只是 734 | 只限 735 | 只要 736 | 只有 737 | 至 738 | 至于 739 | 诸位 740 | 着 741 | 着呢 742 | 自 743 | 自从 744 | 自个儿 745 | 自各儿 746 | 自己 747 | 自家 748 | 自身 749 | 综上所述 750 | 总的来看 751 | 总的来说 752 | 总的说来 753 | 总而言之 754 | 总之 755 | 纵 756 | 纵令 757 | 纵然 758 | 纵使 759 | 遵照 760 | 作为 761 | 兮 762 | 呃 763 | 呗 764 | 咚 765 | 咦 766 | 喏 767 | 啐 768 | 喔唷 769 | 嗬 770 | 嗯 771 | 嗳 772 | ! 773 | " 774 | # 775 | $ 776 | % 777 | & 778 | ' 779 | ( 780 | ) 781 | * 782 | + 783 | , 784 | - 785 | -- 786 | . 787 | .. 788 | ... 789 | ...... 790 | ................... 791 | ./ 792 | .一 793 | .数 794 | .日 795 | / 796 | // 797 | 0 798 | 1 799 | 2 800 | 3 801 | 4 802 | 5 803 | 6 804 | 7 805 | 8 806 | 9 807 | : 808 | :// 809 | :: 810 | ; 811 | < 812 | = 813 | > 814 | >> 815 | ? 816 | @ 817 | A 818 | Lex 819 | [ 820 | \ 821 | ] 822 | ^ 823 | _ 824 | ` 825 | exp 826 | sub 827 | sup 828 | | 829 | } 830 | ~ 831 | ~~~~ 832 | · 833 | × 834 | ××× 835 | Δ 836 | Ψ 837 | γ 838 | μ 839 | φ 840 | φ. 841 | В 842 | — 843 | —— 844 | ——— 845 | ‘ 846 | ’ 847 | ’‘ 848 | “ 849 | ” 850 | ”, 851 | … 852 | …… 853 | …………………………………………………③ 854 | ′∈ 855 | ′| 856 | ℃ 857 | Ⅲ 858 | ↑ 859 | → 860 | ∈[ 861 | ∪φ∈ 862 | ≈ 863 | ① 864 | ② 865 | ②c 866 | ③ 867 | ③] 868 | ④ 869 | ⑤ 870 | ⑥ 871 | ⑦ 872 | ⑧ 873 | ⑨ 874 | ⑩ 875 | ── 876 | ■ 877 | ▲ 878 |   879 | 、 880 | 。 881 | 〈 882 | 〉 883 | 《 884 | 》 885 | 》), 886 | 」 887 | 『 888 | 』 889 | 【 890 | 】 891 | 〔 892 | 〕 893 | 〕〔 894 | ㈧ 895 | 一 896 | 一. 897 | 一一 898 | 一下 899 | 一个 900 | 一些 901 | 一何 902 | 一切 903 | 一则 904 | 一则通过 905 | 一天 906 | 一定 907 | 一方面 908 | 一旦 909 | 一时 910 | 一来 911 | 一样 912 | 一次 913 | 一片 914 | 一番 915 | 一直 916 | 一致 917 | 一般 918 | 一起 919 | 一转眼 920 | 一边 921 | 一面 922 | 七 923 | 万一 924 | 三 925 | 三天两头 926 | 三番两次 927 | 三番五次 928 | 上 929 | 上下 930 | 上升 931 | 上去 932 | 上来 933 | 上述 934 | 上面 935 | 下 936 | 下列 937 | 下去 938 | 下来 939 | 下面 940 | 不 941 | 不一 942 | 不下 943 | 不久 944 | 不了 945 | 不亦乐乎 946 | 不仅 947 | 不仅...而且 948 | 不仅仅 949 | 不仅仅是 950 | 不会 951 | 不但 952 | 不但...而且 953 | 不光 954 | 不免 955 | 不再 956 | 不力 957 | 不单 958 | 不变 959 | 不只 960 | 不可 961 | 不可开交 962 | 不可抗拒 963 | 不同 964 | 不外 965 | 不外乎 966 | 不够 967 | 不大 968 | 不如 969 | 不妨 970 | 不定 971 | 不对 972 | 不少 973 | 不尽 974 | 不尽然 975 | 不巧 976 | 不已 977 | 不常 978 | 不得 979 | 不得不 980 | 不得了 981 | 不得已 982 | 不必 983 | 不怎么 984 | 不怕 985 | 不惟 986 | 不成 987 | 不拘 988 | 不择手段 989 | 不敢 990 | 不料 991 | 不断 992 | 不日 993 | 不时 994 | 不是 995 | 不曾 996 | 不止 997 | 不止一次 998 | 不比 999 | 不消 1000 | 不满 1001 | 不然 1002 | 不然的话 1003 | 不特 1004 | 不独 1005 | 不由得 1006 | 不知不觉 1007 | 不管 1008 | 不管怎样 1009 | 不经意 1010 | 不胜 1011 | 不能 1012 | 不能不 1013 | 不至于 1014 | 不若 1015 | 不要 1016 | 不论 1017 | 不起 1018 | 不足 1019 | 不过 1020 | 不迭 1021 | 不问 1022 | 不限 1023 | 与 1024 | 与其 1025 | 与其说 1026 | 与否 1027 | 与此同时 1028 | 专门 1029 | 且 1030 | 且不说 1031 | 且说 1032 | 两者 1033 | 严格 1034 | 严重 1035 | 个 1036 | 个人 1037 | 个别 1038 | 中小 1039 | 中间 1040 | 丰富 1041 | 串行 1042 | 临 1043 | 临到 1044 | 为 1045 | 为主 1046 | 为了 1047 | 为什么 1048 | 为什麽 1049 | 为何 1050 | 为止 1051 | 为此 1052 | 为着 1053 | 主张 1054 | 主要 1055 | 举凡 1056 | 举行 1057 | 乃 1058 | 乃至 1059 | 乃至于 1060 | 么 1061 | 之 1062 | 之一 1063 | 之前 1064 | 之后 1065 | 之後 1066 | 之所以 1067 | 之类 1068 | 乌乎 1069 | 乎 1070 | 乒 1071 | 乘 1072 | 乘势 1073 | 乘机 1074 | 乘胜 1075 | 乘虚 1076 | 乘隙 1077 | 九 1078 | 也 1079 | 也好 1080 | 也就是说 1081 | 也是 1082 | 也罢 1083 | 了 1084 | 了解 1085 | 争取 1086 | 二 1087 | 二来 1088 | 二话不说 1089 | 二话没说 1090 | 于 1091 | 于是 1092 | 于是乎 1093 | 云云 1094 | 云尔 1095 | 互 1096 | 互相 1097 | 五 1098 | 些 1099 | 交口 1100 | 亦 1101 | 产生 1102 | 亲口 1103 | 亲手 1104 | 亲眼 1105 | 亲自 1106 | 亲身 1107 | 人 1108 | 人人 1109 | 人们 1110 | 人家 1111 | 人民 1112 | 什么 1113 | 什么样 1114 | 什麽 1115 | 仅 1116 | 仅仅 1117 | 今 1118 | 今后 1119 | 今天 1120 | 今年 1121 | 今後 1122 | 介于 1123 | 仍 1124 | 仍旧 1125 | 仍然 1126 | 从 1127 | 从不 1128 | 从严 1129 | 从中 1130 | 从事 1131 | 从今以后 1132 | 从优 1133 | 从古到今 1134 | 从古至今 1135 | 从头 1136 | 从宽 1137 | 从小 1138 | 从新 1139 | 从无到有 1140 | 从早到晚 1141 | 从未 1142 | 从来 1143 | 从此 1144 | 从此以后 1145 | 从而 1146 | 从轻 1147 | 从速 1148 | 从重 1149 | 他 1150 | 他人 1151 | 他们 1152 | 他是 1153 | 他的 1154 | 代替 1155 | 以 1156 | 以上 1157 | 以下 1158 | 以为 1159 | 以便 1160 | 以免 1161 | 以前 1162 | 以及 1163 | 以后 1164 | 以外 1165 | 以後 1166 | 以故 1167 | 以期 1168 | 以来 1169 | 以至 1170 | 以至于 1171 | 以致 1172 | 们 1173 | 任 1174 | 任何 1175 | 任凭 1176 | 任务 1177 | 企图 1178 | 伙同 1179 | 会 1180 | 伟大 1181 | 传 1182 | 传说 1183 | 传闻 1184 | 似乎 1185 | 似的 1186 | 但 1187 | 但凡 1188 | 但愿 1189 | 但是 1190 | 何 1191 | 何乐而不为 1192 | 何以 1193 | 何况 1194 | 何处 1195 | 何妨 1196 | 何尝 1197 | 何必 1198 | 何时 1199 | 何止 1200 | 何苦 1201 | 何须 1202 | 余外 1203 | 作为 1204 | 你 1205 | 你们 1206 | 你是 1207 | 你的 1208 | 使 1209 | 使得 1210 | 使用 1211 | 例如 1212 | 依 1213 | 依据 1214 | 依照 1215 | 依靠 1216 | 便 1217 | 便于 1218 | 促进 1219 | 保持 1220 | 保管 1221 | 保险 1222 | 俺 1223 | 俺们 1224 | 倍加 1225 | 倍感 1226 | 倒不如 1227 | 倒不如说 1228 | 倒是 1229 | 倘 1230 | 倘使 1231 | 倘或 1232 | 倘然 1233 | 倘若 1234 | 借 1235 | 借以 1236 | 借此 1237 | 假使 1238 | 假如 1239 | 假若 1240 | 偏偏 1241 | 做到 1242 | 偶尔 1243 | 偶而 1244 | 傥然 1245 | 像 1246 | 儿 1247 | 允许 1248 | 元/吨 1249 | 充其极 1250 | 充其量 1251 | 充分 1252 | 先不先 1253 | 先后 1254 | 先後 1255 | 先生 1256 | 光 1257 | 光是 1258 | 全体 1259 | 全力 1260 | 全年 1261 | 全然 1262 | 全身心 1263 | 全部 1264 | 全都 1265 | 全面 1266 | 八 1267 | 八成 1268 | 公然 1269 | 六 1270 | 兮 1271 | 共 1272 | 共同 1273 | 共总 1274 | 关于 1275 | 其 1276 | 其一 1277 | 其中 1278 | 其二 1279 | 其他 1280 | 其余 1281 | 其后 1282 | 其它 1283 | 其实 1284 | 其次 1285 | 具体 1286 | 具体地说 1287 | 具体来说 1288 | 具体说来 1289 | 具有 1290 | 兼之 1291 | 内 1292 | 再 1293 | 再其次 1294 | 再则 1295 | 再有 1296 | 再次 1297 | 再者 1298 | 再者说 1299 | 再说 1300 | 冒 1301 | 冲 1302 | 决不 1303 | 决定 1304 | 决非 1305 | 况且 1306 | 准备 1307 | 凑巧 1308 | 凝神 1309 | 几 1310 | 几乎 1311 | 几度 1312 | 几时 1313 | 几番 1314 | 几经 1315 | 凡 1316 | 凡是 1317 | 凭 1318 | 凭借 1319 | 出 1320 | 出于 1321 | 出去 1322 | 出来 1323 | 出现 1324 | 分别 1325 | 分头 1326 | 分期 1327 | 分期分批 1328 | 切 1329 | 切不可 1330 | 切切 1331 | 切勿 1332 | 切莫 1333 | 则 1334 | 则甚 1335 | 刚 1336 | 刚好 1337 | 刚巧 1338 | 刚才 1339 | 初 1340 | 别 1341 | 别人 1342 | 别处 1343 | 别是 1344 | 别的 1345 | 别管 1346 | 别说 1347 | 到 1348 | 到了儿 1349 | 到处 1350 | 到头 1351 | 到头来 1352 | 到底 1353 | 到目前为止 1354 | 前后 1355 | 前此 1356 | 前者 1357 | 前进 1358 | 前面 1359 | 加上 1360 | 加之 1361 | 加以 1362 | 加入 1363 | 加强 1364 | 动不动 1365 | 动辄 1366 | 勃然 1367 | 匆匆 1368 | 十分 1369 | 千 1370 | 千万 1371 | 千万千万 1372 | 半 1373 | 单 1374 | 单单 1375 | 单纯 1376 | 即 1377 | 即令 1378 | 即使 1379 | 即便 1380 | 即刻 1381 | 即如 1382 | 即将 1383 | 即或 1384 | 即是说 1385 | 即若 1386 | 却 1387 | 却不 1388 | 历 1389 | 原来 1390 | 去 1391 | 又 1392 | 又及 1393 | 及 1394 | 及其 1395 | 及时 1396 | 及至 1397 | 双方 1398 | 反之 1399 | 反之亦然 1400 | 反之则 1401 | 反倒 1402 | 反倒是 1403 | 反应 1404 | 反手 1405 | 反映 1406 | 反而 1407 | 反过来 1408 | 反过来说 1409 | 取得 1410 | 取道 1411 | 受到 1412 | 变成 1413 | 古来 1414 | 另 1415 | 另一个 1416 | 另一方面 1417 | 另外 1418 | 另悉 1419 | 另方面 1420 | 另行 1421 | 只 1422 | 只当 1423 | 只怕 1424 | 只是 1425 | 只有 1426 | 只消 1427 | 只要 1428 | 只限 1429 | 叫 1430 | 叫做 1431 | 召开 1432 | 叮咚 1433 | 叮当 1434 | 可 1435 | 可以 1436 | 可好 1437 | 可是 1438 | 可能 1439 | 可见 1440 | 各 1441 | 各个 1442 | 各人 1443 | 各位 1444 | 各地 1445 | 各式 1446 | 各种 1447 | 各级 1448 | 各自 1449 | 合理 1450 | 同 1451 | 同一 1452 | 同时 1453 | 同样 1454 | 后 1455 | 后来 1456 | 后者 1457 | 后面 1458 | 向 1459 | 向使 1460 | 向着 1461 | 吓 1462 | 吗 1463 | 否则 1464 | 吧 1465 | 吧哒 1466 | 吱 1467 | 呀 1468 | 呃 1469 | 呆呆地 1470 | 呐 1471 | 呕 1472 | 呗 1473 | 呜 1474 | 呜呼 1475 | 呢 1476 | 周围 1477 | 呵 1478 | 呵呵 1479 | 呸 1480 | 呼哧 1481 | 呼啦 1482 | 咋 1483 | 和 1484 | 咚 1485 | 咦 1486 | 咧 1487 | 咱 1488 | 咱们 1489 | 咳 1490 | 哇 1491 | 哈 1492 | 哈哈 1493 | 哉 1494 | 哎 1495 | 哎呀 1496 | 哎哟 1497 | 哗 1498 | 哗啦 1499 | 哟 1500 | 哦 1501 | 哩 1502 | 哪 1503 | 哪个 1504 | 哪些 1505 | 哪儿 1506 | 哪天 1507 | 哪年 1508 | 哪怕 1509 | 哪样 1510 | 哪边 1511 | 哪里 1512 | 哼 1513 | 哼唷 1514 | 唉 1515 | 唯有 1516 | 啊 1517 | 啊呀 1518 | 啊哈 1519 | 啊哟 1520 | 啐 1521 | 啥 1522 | 啦 1523 | 啪达 1524 | 啷当 1525 | 喀 1526 | 喂 1527 | 喏 1528 | 喔唷 1529 | 喽 1530 | 嗡 1531 | 嗡嗡 1532 | 嗬 1533 | 嗯 1534 | 嗳 1535 | 嘎 1536 | 嘎嘎 1537 | 嘎登 1538 | 嘘 1539 | 嘛 1540 | 嘻 1541 | 嘿 1542 | 嘿嘿 1543 | 四 1544 | 因 1545 | 因为 1546 | 因了 1547 | 因此 1548 | 因着 1549 | 因而 1550 | 固 1551 | 固然 1552 | 在 1553 | 在下 1554 | 在于 1555 | 地 1556 | 均 1557 | 坚决 1558 | 坚持 1559 | 基于 1560 | 基本 1561 | 基本上 1562 | 处在 1563 | 处处 1564 | 处理 1565 | 复杂 1566 | 多 1567 | 多么 1568 | 多亏 1569 | 多多 1570 | 多多少少 1571 | 多多益善 1572 | 多少 1573 | 多年前 1574 | 多年来 1575 | 多数 1576 | 多次 1577 | 够瞧的 1578 | 大 1579 | 大不了 1580 | 大举 1581 | 大事 1582 | 大体 1583 | 大体上 1584 | 大凡 1585 | 大力 1586 | 大多 1587 | 大多数 1588 | 大大 1589 | 大家 1590 | 大张旗鼓 1591 | 大批 1592 | 大抵 1593 | 大概 1594 | 大略 1595 | 大约 1596 | 大致 1597 | 大都 1598 | 大量 1599 | 大面儿上 1600 | 失去 1601 | 奇 1602 | 奈 1603 | 奋勇 1604 | 她 1605 | 她们 1606 | 她是 1607 | 她的 1608 | 好 1609 | 好在 1610 | 好的 1611 | 好象 1612 | 如 1613 | 如上 1614 | 如上所述 1615 | 如下 1616 | 如今 1617 | 如何 1618 | 如其 1619 | 如前所述 1620 | 如同 1621 | 如常 1622 | 如是 1623 | 如期 1624 | 如果 1625 | 如次 1626 | 如此 1627 | 如此等等 1628 | 如若 1629 | 始而 1630 | 姑且 1631 | 存在 1632 | 存心 1633 | 孰料 1634 | 孰知 1635 | 宁 1636 | 宁可 1637 | 宁愿 1638 | 宁肯 1639 | 它 1640 | 它们 1641 | 它们的 1642 | 它是 1643 | 它的 1644 | 安全 1645 | 完全 1646 | 完成 1647 | 定 1648 | 实现 1649 | 实际 1650 | 宣布 1651 | 容易 1652 | 密切 1653 | 对 1654 | 对于 1655 | 对应 1656 | 对待 1657 | 对方 1658 | 对比 1659 | 将 1660 | 将才 1661 | 将要 1662 | 将近 1663 | 小 1664 | 少数 1665 | 尔 1666 | 尔后 1667 | 尔尔 1668 | 尔等 1669 | 尚且 1670 | 尤其 1671 | 就 1672 | 就地 1673 | 就是 1674 | 就是了 1675 | 就是说 1676 | 就此 1677 | 就算 1678 | 就要 1679 | 尽 1680 | 尽可能 1681 | 尽如人意 1682 | 尽心尽力 1683 | 尽心竭力 1684 | 尽快 1685 | 尽早 1686 | 尽然 1687 | 尽管 1688 | 尽管如此 1689 | 尽量 1690 | 局外 1691 | 居然 1692 | 届时 1693 | 属于 1694 | 屡 1695 | 屡屡 1696 | 屡次 1697 | 屡次三番 1698 | 岂 1699 | 岂但 1700 | 岂止 1701 | 岂非 1702 | 川流不息 1703 | 左右 1704 | 巨大 1705 | 巩固 1706 | 差一点 1707 | 差不多 1708 | 己 1709 | 已 1710 | 已矣 1711 | 已经 1712 | 巴 1713 | 巴巴 1714 | 带 1715 | 帮助 1716 | 常 1717 | 常常 1718 | 常言说 1719 | 常言说得好 1720 | 常言道 1721 | 平素 1722 | 年复一年 1723 | 并 1724 | 并不 1725 | 并不是 1726 | 并且 1727 | 并排 1728 | 并无 1729 | 并没 1730 | 并没有 1731 | 并肩 1732 | 并非 1733 | 广大 1734 | 广泛 1735 | 应当 1736 | 应用 1737 | 应该 1738 | 庶乎 1739 | 庶几 1740 | 开外 1741 | 开始 1742 | 开展 1743 | 引起 1744 | 弗 1745 | 弹指之间 1746 | 强烈 1747 | 强调 1748 | 归 1749 | 归根到底 1750 | 归根结底 1751 | 归齐 1752 | 当 1753 | 当下 1754 | 当中 1755 | 当儿 1756 | 当前 1757 | 当即 1758 | 当口儿 1759 | 当地 1760 | 当场 1761 | 当头 1762 | 当庭 1763 | 当时 1764 | 当然 1765 | 当真 1766 | 当着 1767 | 形成 1768 | 彻夜 1769 | 彻底 1770 | 彼 1771 | 彼时 1772 | 彼此 1773 | 往 1774 | 往往 1775 | 待 1776 | 待到 1777 | 很 1778 | 很多 1779 | 很少 1780 | 後来 1781 | 後面 1782 | 得 1783 | 得了 1784 | 得出 1785 | 得到 1786 | 得天独厚 1787 | 得起 1788 | 心里 1789 | 必 1790 | 必定 1791 | 必将 1792 | 必然 1793 | 必要 1794 | 必须 1795 | 快 1796 | 快要 1797 | 忽地 1798 | 忽然 1799 | 怎 1800 | 怎么 1801 | 怎么办 1802 | 怎么样 1803 | 怎奈 1804 | 怎样 1805 | 怎麽 1806 | 怕 1807 | 急匆匆 1808 | 怪 1809 | 怪不得 1810 | 总之 1811 | 总是 1812 | 总的来看 1813 | 总的来说 1814 | 总的说来 1815 | 总结 1816 | 总而言之 1817 | 恍然 1818 | 恐怕 1819 | 恰似 1820 | 恰好 1821 | 恰如 1822 | 恰巧 1823 | 恰恰 1824 | 恰恰相反 1825 | 恰逢 1826 | 您 1827 | 您们 1828 | 您是 1829 | 惟其 1830 | 惯常 1831 | 意思 1832 | 愤然 1833 | 愿意 1834 | 慢说 1835 | 成为 1836 | 成年 1837 | 成年累月 1838 | 成心 1839 | 我 1840 | 我们 1841 | 我是 1842 | 我的 1843 | 或 1844 | 或则 1845 | 或多或少 1846 | 或是 1847 | 或曰 1848 | 或者 1849 | 或许 1850 | 战斗 1851 | 截然 1852 | 截至 1853 | 所 1854 | 所以 1855 | 所在 1856 | 所幸 1857 | 所有 1858 | 所谓 1859 | 才 1860 | 才能 1861 | 扑通 1862 | 打 1863 | 打从 1864 | 打开天窗说亮话 1865 | 扩大 1866 | 把 1867 | 抑或 1868 | 抽冷子 1869 | 拦腰 1870 | 拿 1871 | 按 1872 | 按时 1873 | 按期 1874 | 按照 1875 | 按理 1876 | 按说 1877 | 挨个 1878 | 挨家挨户 1879 | 挨次 1880 | 挨着 1881 | 挨门挨户 1882 | 挨门逐户 1883 | 换句话说 1884 | 换言之 1885 | 据 1886 | 据实 1887 | 据悉 1888 | 据我所知 1889 | 据此 1890 | 据称 1891 | 据说 1892 | 掌握 1893 | 接下来 1894 | 接着 1895 | 接著 1896 | 接连不断 1897 | 放量 1898 | 故 1899 | 故意 1900 | 故此 1901 | 故而 1902 | 敞开儿 1903 | 敢 1904 | 敢于 1905 | 敢情 1906 | 数/ 1907 | 整个 1908 | 断然 1909 | 方 1910 | 方便 1911 | 方才 1912 | 方能 1913 | 方面 1914 | 旁人 1915 | 无 1916 | 无宁 1917 | 无法 1918 | 无论 1919 | 既 1920 | 既...又 1921 | 既往 1922 | 既是 1923 | 既然 1924 | 日复一日 1925 | 日渐 1926 | 日益 1927 | 日臻 1928 | 日见 1929 | 时候 1930 | 昂然 1931 | 明显 1932 | 明确 1933 | 是 1934 | 是不是 1935 | 是以 1936 | 是否 1937 | 是的 1938 | 显然 1939 | 显著 1940 | 普通 1941 | 普遍 1942 | 暗中 1943 | 暗地里 1944 | 暗自 1945 | 更 1946 | 更为 1947 | 更加 1948 | 更进一步 1949 | 曾 1950 | 曾经 1951 | 替 1952 | 替代 1953 | 最 1954 | 最后 1955 | 最大 1956 | 最好 1957 | 最後 1958 | 最近 1959 | 最高 1960 | 有 1961 | 有些 1962 | 有关 1963 | 有利 1964 | 有力 1965 | 有及 1966 | 有所 1967 | 有效 1968 | 有时 1969 | 有点 1970 | 有的 1971 | 有的是 1972 | 有着 1973 | 有著 1974 | 望 1975 | 朝 1976 | 朝着 1977 | 末##末 1978 | 本 1979 | 本人 1980 | 本地 1981 | 本着 1982 | 本身 1983 | 权时 1984 | 来 1985 | 来不及 1986 | 来得及 1987 | 来看 1988 | 来着 1989 | 来自 1990 | 来讲 1991 | 来说 1992 | 极 1993 | 极为 1994 | 极了 1995 | 极其 1996 | 极力 1997 | 极大 1998 | 极度 1999 | 极端 2000 | 构成 2001 | 果然 2002 | 果真 2003 | 某 2004 | 某个 2005 | 某些 2006 | 某某 2007 | 根据 2008 | 根本 2009 | 格外 2010 | 梆 2011 | 概 2012 | 次第 2013 | 欢迎 2014 | 欤 2015 | 正值 2016 | 正在 2017 | 正如 2018 | 正巧 2019 | 正常 2020 | 正是 2021 | 此 2022 | 此中 2023 | 此后 2024 | 此地 2025 | 此处 2026 | 此外 2027 | 此时 2028 | 此次 2029 | 此间 2030 | 殆 2031 | 毋宁 2032 | 每 2033 | 每个 2034 | 每天 2035 | 每年 2036 | 每当 2037 | 每时每刻 2038 | 每每 2039 | 每逢 2040 | 比 2041 | 比及 2042 | 比如 2043 | 比如说 2044 | 比方 2045 | 比照 2046 | 比起 2047 | 比较 2048 | 毕竟 2049 | 毫不 2050 | 毫无 2051 | 毫无例外 2052 | 毫无保留地 2053 | 汝 2054 | 沙沙 2055 | 没 2056 | 没奈何 2057 | 没有 2058 | 沿 2059 | 沿着 2060 | 注意 2061 | 活 2062 | 深入 2063 | 清楚 2064 | 满 2065 | 满足 2066 | 漫说 2067 | 焉 2068 | 然 2069 | 然则 2070 | 然后 2071 | 然後 2072 | 然而 2073 | 照 2074 | 照着 2075 | 牢牢 2076 | 特别是 2077 | 特殊 2078 | 特点 2079 | 犹且 2080 | 犹自 2081 | 独 2082 | 独自 2083 | 猛然 2084 | 猛然间 2085 | 率尔 2086 | 率然 2087 | 现代 2088 | 现在 2089 | 理应 2090 | 理当 2091 | 理该 2092 | 瑟瑟 2093 | 甚且 2094 | 甚么 2095 | 甚或 2096 | 甚而 2097 | 甚至 2098 | 甚至于 2099 | 用 2100 | 用来 2101 | 甫 2102 | 甭 2103 | 由 2104 | 由于 2105 | 由是 2106 | 由此 2107 | 由此可见 2108 | 略 2109 | 略为 2110 | 略加 2111 | 略微 2112 | 白 2113 | 白白 2114 | 的 2115 | 的确 2116 | 的话 2117 | 皆可 2118 | 目前 2119 | 直到 2120 | 直接 2121 | 相似 2122 | 相信 2123 | 相反 2124 | 相同 2125 | 相对 2126 | 相对而言 2127 | 相应 2128 | 相当 2129 | 相等 2130 | 省得 2131 | 看 2132 | 看上去 2133 | 看出 2134 | 看到 2135 | 看来 2136 | 看样子 2137 | 看看 2138 | 看见 2139 | 看起来 2140 | 真是 2141 | 真正 2142 | 眨眼 2143 | 着 2144 | 着呢 2145 | 矣 2146 | 矣乎 2147 | 矣哉 2148 | 知道 2149 | 砰 2150 | 确定 2151 | 碰巧 2152 | 社会主义 2153 | 离 2154 | 种 2155 | 积极 2156 | 移动 2157 | 究竟 2158 | 穷年累月 2159 | 突出 2160 | 突然 2161 | 窃 2162 | 立 2163 | 立刻 2164 | 立即 2165 | 立地 2166 | 立时 2167 | 立马 2168 | 竟 2169 | 竟然 2170 | 竟而 2171 | 第 2172 | 第二 2173 | 等 2174 | 等到 2175 | 等等 2176 | 策略地 2177 | 简直 2178 | 简而言之 2179 | 简言之 2180 | 管 2181 | 类如 2182 | 粗 2183 | 精光 2184 | 紧接着 2185 | 累年 2186 | 累次 2187 | 纯 2188 | 纯粹 2189 | 纵 2190 | 纵令 2191 | 纵使 2192 | 纵然 2193 | 练习 2194 | 组成 2195 | 经 2196 | 经常 2197 | 经过 2198 | 结合 2199 | 结果 2200 | 给 2201 | 绝 2202 | 绝不 2203 | 绝对 2204 | 绝非 2205 | 绝顶 2206 | 继之 2207 | 继后 2208 | 继续 2209 | 继而 2210 | 维持 2211 | 综上所述 2212 | 缕缕 2213 | 罢了 2214 | 老 2215 | 老大 2216 | 老是 2217 | 老老实实 2218 | 考虑 2219 | 者 2220 | 而 2221 | 而且 2222 | 而况 2223 | 而又 2224 | 而后 2225 | 而外 2226 | 而已 2227 | 而是 2228 | 而言 2229 | 而论 2230 | 联系 2231 | 联袂 2232 | 背地里 2233 | 背靠背 2234 | 能 2235 | 能否 2236 | 能够 2237 | 腾 2238 | 自 2239 | 自个儿 2240 | 自从 2241 | 自各儿 2242 | 自后 2243 | 自家 2244 | 自己 2245 | 自打 2246 | 自身 2247 | 臭 2248 | 至 2249 | 至于 2250 | 至今 2251 | 至若 2252 | 致 2253 | 般的 2254 | 良好 2255 | 若 2256 | 若夫 2257 | 若是 2258 | 若果 2259 | 若非 2260 | 范围 2261 | 莫 2262 | 莫不 2263 | 莫不然 2264 | 莫如 2265 | 莫若 2266 | 莫非 2267 | 获得 2268 | 藉以 2269 | 虽 2270 | 虽则 2271 | 虽然 2272 | 虽说 2273 | 蛮 2274 | 行为 2275 | 行动 2276 | 表明 2277 | 表示 2278 | 被 2279 | 要 2280 | 要不 2281 | 要不是 2282 | 要不然 2283 | 要么 2284 | 要是 2285 | 要求 2286 | 见 2287 | 规定 2288 | 觉得 2289 | 譬喻 2290 | 譬如 2291 | 认为 2292 | 认真 2293 | 认识 2294 | 让 2295 | 许多 2296 | 论 2297 | 论说 2298 | 设使 2299 | 设或 2300 | 设若 2301 | 诚如 2302 | 诚然 2303 | 话说 2304 | 该 2305 | 该当 2306 | 说明 2307 | 说来 2308 | 说说 2309 | 请勿 2310 | 诸 2311 | 诸位 2312 | 诸如 2313 | 谁 2314 | 谁人 2315 | 谁料 2316 | 谁知 2317 | 谨 2318 | 豁然 2319 | 贼死 2320 | 赖以 2321 | 赶 2322 | 赶快 2323 | 赶早不赶晚 2324 | 起 2325 | 起先 2326 | 起初 2327 | 起头 2328 | 起来 2329 | 起见 2330 | 起首 2331 | 趁 2332 | 趁便 2333 | 趁势 2334 | 趁早 2335 | 趁机 2336 | 趁热 2337 | 趁着 2338 | 越是 2339 | 距 2340 | 跟 2341 | 路经 2342 | 转动 2343 | 转变 2344 | 转贴 2345 | 轰然 2346 | 较 2347 | 较为 2348 | 较之 2349 | 较比 2350 | 边 2351 | 达到 2352 | 达旦 2353 | 迄 2354 | 迅速 2355 | 过 2356 | 过于 2357 | 过去 2358 | 过来 2359 | 运用 2360 | 近 2361 | 近几年来 2362 | 近年来 2363 | 近来 2364 | 还 2365 | 还是 2366 | 还有 2367 | 还要 2368 | 这 2369 | 这一来 2370 | 这个 2371 | 这么 2372 | 这么些 2373 | 这么样 2374 | 这么点儿 2375 | 这些 2376 | 这会儿 2377 | 这儿 2378 | 这就是说 2379 | 这时 2380 | 这样 2381 | 这次 2382 | 这点 2383 | 这种 2384 | 这般 2385 | 这边 2386 | 这里 2387 | 这麽 2388 | 进入 2389 | 进去 2390 | 进来 2391 | 进步 2392 | 进而 2393 | 进行 2394 | 连 2395 | 连同 2396 | 连声 2397 | 连日 2398 | 连日来 2399 | 连袂 2400 | 连连 2401 | 迟早 2402 | 迫于 2403 | 适应 2404 | 适当 2405 | 适用 2406 | 逐步 2407 | 逐渐 2408 | 通常 2409 | 通过 2410 | 造成 2411 | 逢 2412 | 遇到 2413 | 遭到 2414 | 遵循 2415 | 遵照 2416 | 避免 2417 | 那 2418 | 那个 2419 | 那么 2420 | 那么些 2421 | 那么样 2422 | 那些 2423 | 那会儿 2424 | 那儿 2425 | 那时 2426 | 那末 2427 | 那样 2428 | 那般 2429 | 那边 2430 | 那里 2431 | 那麽 2432 | 部分 2433 | 都 2434 | 鄙人 2435 | 采取 2436 | 里面 2437 | 重大 2438 | 重新 2439 | 重要 2440 | 鉴于 2441 | 针对 2442 | 长期以来 2443 | 长此下去 2444 | 长线 2445 | 长话短说 2446 | 问题 2447 | 间或 2448 | 防止 2449 | 阿 2450 | 附近 2451 | 陈年 2452 | 限制 2453 | 陡然 2454 | 除 2455 | 除了 2456 | 除却 2457 | 除去 2458 | 除外 2459 | 除开 2460 | 除此 2461 | 除此之外 2462 | 除此以外 2463 | 除此而外 2464 | 除非 2465 | 随 2466 | 随后 2467 | 随时 2468 | 随着 2469 | 随著 2470 | 隔夜 2471 | 隔日 2472 | 难得 2473 | 难怪 2474 | 难说 2475 | 难道 2476 | 难道说 2477 | 集中 2478 | 零 2479 | 需要 2480 | 非但 2481 | 非常 2482 | 非徒 2483 | 非得 2484 | 非特 2485 | 非独 2486 | 靠 2487 | 顶多 2488 | 顷 2489 | 顷刻 2490 | 顷刻之间 2491 | 顷刻间 2492 | 顺 2493 | 顺着 2494 | 顿时 2495 | 颇 2496 | 风雨无阻 2497 | 饱 2498 | 首先 2499 | 马上 2500 | 高低 2501 | 高兴 2502 | 默然 2503 | 默默地 2504 | 齐 2505 | ︿ 2506 | ! 2507 | # 2508 | $ 2509 | % 2510 | & 2511 | ' 2512 | ( 2513 | ) 2514 | )÷(1- 2515 | )、 2516 | * 2517 | + 2518 | +ξ 2519 | ++ 2520 | , 2521 | ,也 2522 | - 2523 | -β 2524 | -- 2525 | -[*]- 2526 | . 2527 | / 2528 | 0 2529 | 0:2 2530 | 1 2531 | 1. 2532 | 12% 2533 | 2 2534 | 2.3% 2535 | 3 2536 | 4 2537 | 5 2538 | 5:0 2539 | 6 2540 | 7 2541 | 8 2542 | 9 2543 | : 2544 | ; 2545 | < 2546 | <± 2547 | <Δ 2548 | <λ 2549 | <φ 2550 | << 2551 | = 2552 | =″ 2553 | =☆ 2554 | =( 2555 | =- 2556 | =[ 2557 | ={ 2558 | > 2559 | >λ 2560 | ? 2561 | @ 2562 | A 2563 | LI 2564 | R.L. 2565 | ZXFITL 2566 | [ 2567 | [①①] 2568 | [①②] 2569 | [①③] 2570 | [①④] 2571 | [①⑤] 2572 | [①⑥] 2573 | [①⑦] 2574 | [①⑧] 2575 | [①⑨] 2576 | [①A] 2577 | [①B] 2578 | [①C] 2579 | [①D] 2580 | [①E] 2581 | [①] 2582 | [①a] 2583 | [①c] 2584 | [①d] 2585 | [①e] 2586 | [①f] 2587 | [①g] 2588 | [①h] 2589 | [①i] 2590 | [①o] 2591 | [② 2592 | [②①] 2593 | [②②] 2594 | [②③] 2595 | [②④ 2596 | [②⑤] 2597 | [②⑥] 2598 | [②⑦] 2599 | [②⑧] 2600 | [②⑩] 2601 | [②B] 2602 | [②G] 2603 | [②] 2604 | [②a] 2605 | [②b] 2606 | [②c] 2607 | [②d] 2608 | [②e] 2609 | [②f] 2610 | [②g] 2611 | [②h] 2612 | [②i] 2613 | [②j] 2614 | [③①] 2615 | [③⑩] 2616 | [③F] 2617 | [③] 2618 | [③a] 2619 | [③b] 2620 | [③c] 2621 | [③d] 2622 | [③e] 2623 | [③g] 2624 | [③h] 2625 | [④] 2626 | [④a] 2627 | [④b] 2628 | [④c] 2629 | [④d] 2630 | [④e] 2631 | [⑤] 2632 | [⑤]] 2633 | [⑤a] 2634 | [⑤b] 2635 | [⑤d] 2636 | [⑤e] 2637 | [⑤f] 2638 | [⑥] 2639 | [⑦] 2640 | [⑧] 2641 | [⑨] 2642 | [⑩] 2643 | [*] 2644 | [- 2645 | [] 2646 | ] 2647 | ]∧′=[ 2648 | ][ 2649 | _ 2650 | a] 2651 | b] 2652 | c] 2653 | e] 2654 | f] 2655 | ng昉 2656 | { 2657 | {- 2658 | | 2659 | } 2660 | }> 2661 | ~ 2662 | ~± 2663 | ~+ 2664 | ¥ 2665 | -------------------------------------------------------------------------------- /主文件中的代码/所有可视化图表.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | B站评论数据可视化分析 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 269 |
270 | 447 |
448 | 615 |
616 | 778 |
779 | 941 |
942 | 1104 |
1105 | 1107 | 1108 |
1109 |

创作者整体情感分析画像

1110 |

正向评论比例: 正向评论占比为 46.73%

1111 |

负向评论比例: 负向评论占比为 53.27%

1112 |

不同性别用户情感反应分析

1113 |

正向评论比例:

1114 | 1119 |

负向评论比例:

1120 | 1125 |
1126 | 1127 |
1128 |

创作者综合评估报告

1129 |

* 核心指标分析 *

1130 | 1136 |

* 创作者类型 *

1137 |

强烈推荐创作者

1138 |

创作者高频词为:春晚(54)、原版(32)、套装(28)、动物(28)、改编(26)、hanser(24)、表情(23)、感觉(21)、大哭(21)、原唱(16)

1139 |

【评分逻辑说明】

1140 |
    1141 |
  1. TOP100高赞评论加权:正向评论点赞数之和,负向评论点赞数之和
  2. 1142 |
  3. 综合评分 = 70%×正向得分占比 + 30%×正向评论数量占比
  4. 1143 |
  5. 评价阈值:>0.7强烈推荐,>0.6正向,>0.4中立,≤0.4负向
  6. 1144 |
1145 |
1146 | 1147 | 1148 | --------------------------------------------------------------------------------