絡(luò)輿情分析系統(tǒng)實(shí)戰(zhàn):從爬蟲到情感分析)
簡(jiǎn)介這是面向高校計(jì)算機(jī)相關(guān)專業(yè)期末大作業(yè)與項(xiàng)目實(shí)戰(zhàn)的基于Python的網(wǎng)絡(luò)輿情分析系統(tǒng)完整項(xiàng)目覆蓋數(shù)據(jù)采集、文本預(yù)處理、情感分析和可視化展示等核心環(huán)節(jié)難度適中適合正在完成課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或需要綜合練手的學(xué)習(xí)者。整個(gè)項(xiàng)目經(jīng)導(dǎo)師評(píng)審?fù)ㄟ^并獲得九十八分源碼均已在本地編譯并經(jīng)過嚴(yán)格調(diào)試下載后可直接對(duì)照運(yùn)行減少環(huán)境搭建和排錯(cuò)成本。資源包共一百一十八個(gè)文件以Python腳本、Java界面源碼、jar依賴、class字節(jié)碼、txt說明文檔和xml配置文件為主同時(shí)提供ipynb交互式示例、Excel數(shù)據(jù)文件、圖表圖片及說明文檔整體約四十五點(diǎn)二MB便于按模塊快速定位。目前已有143人學(xué)習(xí)下載。借助完整可運(yùn)行的工程代碼、配套數(shù)據(jù)與說明文檔可以清晰梳理輿情分析系統(tǒng)的整體邏輯、界面設(shè)計(jì)和統(tǒng)計(jì)圖表生成方式也便于替換或擴(kuò)展數(shù)據(jù)源、算法模型與展示樣式作為大作業(yè)或項(xiàng)目實(shí)戰(zhàn)的起點(diǎn)。1. 網(wǎng)絡(luò)輿情分析系統(tǒng)是人工智能大作業(yè)的穩(wěn)妥選擇如果你正被人工智能大作業(yè)追著跑又不想用MNIST手寫數(shù)字識(shí)別這類練手題基于Python搭建一個(gè)網(wǎng)絡(luò)輿情分析系統(tǒng)是比較穩(wěn)的一步棋。它把爬蟲采集、文本清洗、情感判斷和可視化串成了完整鏈路代碼量足夠撐起課設(shè)報(bào)告同時(shí)又不依賴GPU和深度學(xué)習(xí)框架。源碼拿到手真正要花心思的反而是后面這些事反爬策略、停用詞表、情感閾值、ECharts路徑。節(jié)點(diǎn)跑通只算及格參數(shù)調(diào)得能讓導(dǎo)師追問時(shí)答得上來才配得上“高分”兩個(gè)字。下面按我拿到這類項(xiàng)目后一路踩坑的順序把架構(gòu)、啟動(dòng)步驟、調(diào)參和排錯(cuò)完整拆一遍。2. 先看數(shù)據(jù)流再看代碼網(wǎng)絡(luò)輿情系統(tǒng)的架構(gòu)與技術(shù)選型2.1 輿情項(xiàng)目的四層架構(gòu)采集、清洗、分析、展示一套能應(yīng)付答辯的輿情分析系統(tǒng)代碼再亂模塊邊界一定是清楚的。我拿到一套人工智能大作業(yè)源碼第一件事不是逐行讀而是先把項(xiàng)目根目錄里的文件按這四層歸類采集層負(fù)責(zé)從新聞網(wǎng)站、微博搜索頁或公開API抓取文本清洗層負(fù)責(zé)去HTML標(biāo)簽、去重、過濾掉推廣內(nèi)容分析層負(fù)責(zé)分詞、關(guān)鍵詞提取、情感打分和統(tǒng)計(jì)展示層負(fù)責(zé)生成詞云、趨勢(shì)折線圖和分類餅圖。只要這四個(gè)邊界在后面無論是換數(shù)據(jù)源還是換算法都只動(dòng)一層不會(huì)牽一發(fā)動(dòng)全身。這四層對(duì)應(yīng)到常見源碼包里一般是這么分布的采集層是crawler.py或spider/目錄清洗和分析層是preprocess.py和analyze.py展示層可能是app.py里的Flask頁面也可能是report.py直接生成HTML。很多拿到手就翻車的同學(xué)都是跳過采集層直接跑分析腳本結(jié)果數(shù)據(jù)格式不匹配報(bào)錯(cuò)又回頭找爬蟲繞了一大圈才明白系統(tǒng)是流水線不是散裝零件。下面這個(gè)表格是本類項(xiàng)目最常見的技術(shù)棧你可以拿它和手里的源碼做對(duì)照看缺了哪層就往哪層補(bǔ)層級(jí)常見實(shí)現(xiàn)輸入輸出采集層requests BeautifulSoup / Scrapy關(guān)鍵詞、頁碼原始文本CSV清洗層pandas re原始CSV去重、去噪后的DataFrame分析層jieba SnowNLP / snownlp清洗后文本詞頻、情感分?jǐn)?shù)、主題分布展示層pyecharts / ECharts / Flask分析結(jié)果HTML圖表、報(bào)告目錄如果拿到手的源碼少了某層最簡(jiǎn)單的補(bǔ)齊方式不是重寫而是找一個(gè)同類開源模塊補(bǔ)上。比如采集層只有新聞源沒有微博源你可以自己加一個(gè)函數(shù)分析層只有詞頻沒有情感那就在analyze.py里加一段基于SnowNLP的腳本。這部分后面會(huì)展開。2.2 選定Python技術(shù)棧的理由夠用、可解釋、不燒算力為什么這類人工智能大作業(yè)普遍選擇Python而不是Java或C因?yàn)檩浨榉治龅暮诵氖俏谋咎幚矶鳳ython生態(tài)把從抓到看中間每一環(huán)都封好了。這是技術(shù)選型里的“省心”路線requests發(fā)請(qǐng)求BeautifulSoup解析HTMLjieba切詞SnowNLP算情感pyecharts畫圖。每一樣都不是最強(qiáng)但合起來正好覆蓋一個(gè)輿情分析系統(tǒng)的全部需求而且每個(gè)庫都有海量中文教程出問題搜索就能解決。這里要回答一個(gè)老師大概率會(huì)問的問題為什么不用BERT或者LSTM來做情感分析答案是性價(jià)比。深度學(xué)習(xí)模型確實(shí)能在情感分類上做得更好但你首先得有標(biāo)注數(shù)據(jù)其次得配環(huán)境、調(diào)超參數(shù)最后還要在答辯現(xiàn)場(chǎng)證明你的模型不是過擬合。對(duì)大作業(yè)體量來說SnowNLP內(nèi)置的樸素貝葉斯模型已經(jīng)能給出0到1的情感傾向分雖然不夠細(xì)膩但足夠支撐“正面、中性、負(fù)面”三類統(tǒng)計(jì)。你向?qū)熃忉尅拔矣昧藰闼刎惾~斯”比解釋“我用了注意力機(jī)制”輕松得多追問到細(xì)節(jié)也能接得住。選型里還有一個(gè)容易被忽略的點(diǎn)數(shù)據(jù)存儲(chǔ)。常見的高分項(xiàng)目資料包一般會(huì)用SQLite或CSV而不是MySQL。原因很簡(jiǎn)單SQLite是Python自帶的不需要額外裝服務(wù)交給老師演示時(shí)也不用擔(dān)心數(shù)據(jù)庫沒啟動(dòng)。CSV則更方便Excel打開核對(duì)。我一般建議保留CSV作為中間產(chǎn)物同時(shí)用SQLite存一份結(jié)構(gòu)化結(jié)果這樣報(bào)告里的數(shù)據(jù)表格和圖表都能對(duì)得上。工具鏈上vscode python環(huán)境配置是這套項(xiàng)目里最基礎(chǔ)的一環(huán)。我拿到源碼會(huì)先把Python版本固定下來建議3.9到3.11之間太新的版本裝舊版SnowNLP可能遇到依賴庫schema的兼容問題。環(huán)境統(tǒng)一之后再用requirements.txt把依賴鎖住這比在全局環(huán)境里一個(gè)個(gè)pip install要穩(wěn)得多也方便換電腦復(fù)現(xiàn)。3. 在本地把Python源碼跑通環(huán)境搭建與最小執(zhí)行步驟3.1 創(chuàng)建虛擬環(huán)境并安裝依賴網(wǎng)絡(luò)輿情分析系統(tǒng)的依賴不算多但如果不做環(huán)境隔離很容易把Python官方包和項(xiàng)目包混在一起。我的習(xí)慣是每個(gè)項(xiàng)目都建獨(dú)立虛擬環(huán)境尤其是用來交作業(yè)的項(xiàng)目答辯前幾天環(huán)境崩掉是血淚教訓(xùn)。python -m venv venv # Windows下激活虛擬環(huán)境 venv\Scripts\activate # Linux/macOS下激活虛擬環(huán)境 source venv/bin/activate python -m pip install --upgrade pip pip install -r requirements.txtrequirements.txt是這套項(xiàng)目的依賴清單通常長(zhǎng)這樣requests2.31.0 beautifulsoup44.12.2 jieba0.42.1 snownlp0.12.2 pandas2.0.0 pyecharts2.0.0 flask3.0.0如果源碼包里沒有這個(gè)文件你可以按上面的版本手動(dòng)生成一份。這里特別提醒snownlp有兩個(gè)常見包名一個(gè)是snownlp另一個(gè)是SnowNLP大小寫不同但指的是同一個(gè)庫。安裝時(shí)用snownlp小寫Python導(dǎo)入時(shí)用from snownlp import SnowNLP。語法層面稍微注意因?yàn)檎`寫成SnowNLP會(huì)讓解釋器一臉懵。裝依賴時(shí)最容易出現(xiàn)的問題有兩個(gè)一是pandas和numpy版本沖突二是pyecharts在較新Python環(huán)境里缺少importlib_resources。前者建議通過requirements.txt固定版本解決別在項(xiàng)目里單獨(dú)安裝最新版pandas后者可以在安裝完requirements后補(bǔ)一句pip install importlib_resources。3.2 先跑采集層用可復(fù)現(xiàn)的方式抓取數(shù)據(jù)采集是整個(gè)輿情項(xiàng)目里最容易翻車的環(huán)節(jié)。真實(shí)社交媒體反爬嚴(yán)格直接跑爬蟲經(jīng)常會(huì)撞上驗(yàn)證碼或空數(shù)據(jù)。我見過的可靠方案是采集腳本保留但給它加一個(gè)--offline參數(shù)演示時(shí)走本地緩存數(shù)據(jù)平時(shí)研究再走真實(shí)網(wǎng)絡(luò)這樣答辯現(xiàn)場(chǎng)不會(huì)因?yàn)橥饩W(wǎng)波動(dòng)斷掉。# keyword_crawler.py import requests import csv import time import random from bs4 import BeautifulSoup def collect_news(keyword, max_pages3, delay1.5, outputdata/news.csv): 從公開搜索結(jié)果頁抓取包含關(guān)鍵詞的網(wǎng)頁標(biāo)題和摘要。 這里以適合課堂演示的公開頁面為例換數(shù)據(jù)源時(shí)只要改 parse_page函數(shù)里的CSS選擇器即可。 results [] seen_titles set() for page in range(1, max_pages 1): # 構(gòu)造搜索urlpn參數(shù)是搜索結(jié)果的偏移量 url fhttps://www.bing.com/search?q{keyword}first{page*10} resp requests.get(url, headers{ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36 }, timeout10) if resp.status_code ! 200: print(f第{page}頁返回狀態(tài)碼{resp.status_code}跳過) continue soup BeautifulSoup(resp.text, html.parser) # 不同搜索平臺(tái)結(jié)果塊的class不同這里是通用寫法 for item in soup.select(li.b_algo): title_tag item.select_one(h2 a) snippet_tag item.select_one(p) if title_tag is None: continue title title_tag.get_text(stripTrue) snippet snippet_tag.get_text(stripTrue) if snippet_tag else if title in seen_titles: continue # 去重 seen_titles.add(title) results.append([keyword, title, snippet]) # 防止請(qǐng)求過快在頁面之間隨機(jī)停頓 time.sleep(delay random.uniform(0, 1)) with open(output, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([keyword, title, content]) writer.writerows(results) print(f采集完成共{len(results)}條保存到{output}) if __name__ __main__: # python keyword_crawler.py --keyword 人工智能 --pages 3 --output data/ai.csv import argparse parser argparse.ArgumentParser() parser.add_argument(--keyword, requiredTrue) parser.add_argument(--pages, typeint, default3) parser.add_argument(--output, defaultdata/news.csv) args parser.parse_args() collect_news(args.keyword, args.pages)這段代碼里三個(gè)參數(shù)最關(guān)鍵keyword決定分析主題pages決定數(shù)據(jù)量而delay是反爬的命門。很多新手把delay設(shè)成0結(jié)果發(fā)幾頁就被封IP。我一般設(shè)1.5秒以上每次請(qǐng)求之間再加隨機(jī)抖動(dòng)讓訪問頻率更像“人”。encodingutf-8-sig是為了讓CSV被Excel打開時(shí)中文不亂碼很多資料包里的爬蟲腳本沒寫這個(gè)參數(shù)生成的CSV用Excel打開就是一片亂碼這是最常見的“看起來壞了”的場(chǎng)景。3.3 再跑分析主流程一條命令生成結(jié)果目錄采集到CSV后接下來就是分析主流程。這個(gè)環(huán)節(jié)的驗(yàn)收標(biāo)準(zhǔn)是給一條命令輸出一個(gè)帶圖表和統(tǒng)計(jì)結(jié)果的目錄。很多高分項(xiàng)目的代碼里都有一個(gè)類似analyze.py的總?cè)肟诶锩姘亚逑?、分詞、情感、統(tǒng)計(jì)串成流水線。python analyze.py --input data/ai.csv --output output/這段命令背后的analyze.py核心邏輯如下# analyze.py import pandas as pd from snownlp import SnowNLP import jieba import jieba.analyse def clean_text(text): 去掉HTML標(biāo)簽和多余空白保留中文、英文、數(shù)字 import re text re.sub(r[^], , text) # 去HTML標(biāo)簽 text re.sub(r[^\w\s], , text) # 去標(biāo)點(diǎn) return text.strip() def analyze_csv(input_path, output_dir): df pd.read_csv(input_path, encodingutf-8-sig) df df.drop_duplicates(subset[title]) # 按標(biāo)題去重 df[content] df[content].fillna() # 空內(nèi)容補(bǔ)全 df[clean] df[content].apply(lambda x: clean_text(x)) # 情感打分0~1越接近1越正向 df[sentiment] df[clean].apply( lambda x: SnowNLP(x).sentiments if len(x) 0 else 0.5 ) # 關(guān)鍵詞提取基于TF-IDF從所有文本里取top10 all_text .join(df[clean].tolist()) tags jieba.analyse.extract_tags(all_text, topK10, withWeightTrue) print(關(guān)鍵詞TOP10) for word, weight in tags: print(f {word}: {weight:.4f}) df.to_csv(f{output_dir}/result.csv, indexFalse, encodingutf-8-sig) print(f分析完成結(jié)果保存到{output_dir}/result.csv) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(--input, requiredTrue) parser.add_argument(--output, defaultoutput) args parser.parse_args() analyze_csv(args.input, args.output)注意sentiment列是后面畫情感趨勢(shì)圖的原材料。fillna()這步不能省因?yàn)樽セ貋淼臄?shù)據(jù)里可能有的摘要為空不處理的話SnowNLP()會(huì)直接拋異常。extract_tags用的是TF-IDF統(tǒng)計(jì)withWeightTrue會(huì)輸出每個(gè)詞的權(quán)重這個(gè)權(quán)重值正是報(bào)告里“關(guān)鍵詞表”的來源。4. 調(diào)出導(dǎo)師認(rèn)可的結(jié)果分詞、情感閾值與圖表參數(shù)4.1 分詞與詞頻jieba必做的兩個(gè)動(dòng)作輿情分析里最常見的一句“玄學(xué)”是為什么我分詞分出來一堆沒用的詞答案多半是沒讓jieba學(xué)會(huì)領(lǐng)域詞匯同時(shí)沒過濾停用詞。默認(rèn)的jieba詞庫偏向通用領(lǐng)域在“人工智能”這個(gè)主題下它會(huì)把“機(jī)器學(xué)習(xí)”“深度學(xué)習(xí)”切開也會(huì)把“AI”當(dāng)成單字。解決辦法通常是兩件事加載自定義詞典準(zhǔn)備一份停用詞表。import jieba import jieba.analyse # userdict.txt 每行格式詞語 詞頻 詞性 jieba.load_userdict(userdict.txt) # 例如文件內(nèi)容 # 人工智能 10 n # 機(jī)器學(xué)習(xí) 10 n # 大數(shù)據(jù) 10 n stopwords set(open(stopwords.txt, encodingutf-8).read().split()) # 例如文件內(nèi)容 # 我們 因?yàn)?所以 但是 如果 雖然 而且 然后 來說 進(jìn)行 通過 def filter_words(text): words jieba.cut(text) return [w for w in words if w.strip() and w not in stopwords and len(w) 1]自定義詞典的最后一列是詞性n代表名詞v代表動(dòng)詞。詞頻寫10或100都行它只影響詞典里詞被切出的優(yōu)先級(jí)。注意len(w) 1這步能把單字噪聲過濾掉但代價(jià)是“不”“很”這些單字否定詞也會(huì)被丟對(duì)后續(xù)情感分析會(huì)有影響。所以如果你要保留否定詞就不要加這個(gè)過濾條件而是在情感計(jì)算前單獨(dú)處理。分詞完下一步通常是詞頻統(tǒng)計(jì)。常見做法是使用collections.Counter統(tǒng)計(jì)再用pyecharts的WordCloud接口畫圖。這里有個(gè)容易踩坑的點(diǎn)詞頻統(tǒng)計(jì)前一定要做停用詞過濾否則高頻詞永遠(yuǎn)是“的、了、在、是”這類沒有分析價(jià)值的詞。一份好的停用詞表應(yīng)該在100到300之間覆蓋虛詞、代詞、常見動(dòng)詞不要貪多。4.2 情感得分閾值別把0.5當(dāng)唯一標(biāo)準(zhǔn)SnowNLP輸出的sentiments值是一個(gè)0到1之間的概率大于0.5表示偏正向。這個(gè)數(shù)字看起來簡(jiǎn)單直接用會(huì)出問題訓(xùn)練語料是商品評(píng)論在“輿情”這種新聞標(biāo)題和評(píng)論文本上分?jǐn)?shù)會(huì)整體偏高負(fù)面事件里也可能看到0.6以上的分?jǐn)?shù)。所以不要寫死“0.5為正0.5以下為負(fù)”要按實(shí)際數(shù)據(jù)調(diào)閾值。from snownlp import SnowNLP def classify_sentiment(score): 按經(jīng)驗(yàn)閾值分成正面、中性、負(fù)面三類 if score 0.6: return 正面 elif score 0.4: return 負(fù)面 else: return 中性 def adjust_with_negation(text, score): 簡(jiǎn)單否定詞修正句子含不/沒有且分?jǐn)?shù)偏高時(shí)降一檔 neg_words [不, 沒有, 無, 未] contain_neg any(w in text for w in neg_words) if contain_neg and score 0.6: return 0.4 # 拉回中性 return score閾值到底取0.4還是0.45取決于你的數(shù)據(jù)分布。我一般會(huì)在跑完分析后隨機(jī)抽30條結(jié)果自己手動(dòng)標(biāo)一遍正負(fù)然后和程序結(jié)果對(duì)一下再回來調(diào)閾值。這步很土但最有效。筆記里推薦的方法是將人工標(biāo)注結(jié)果導(dǎo)成Excel表格用公式算準(zhǔn)確率準(zhǔn)確率到80%以上再固化閾值。如果負(fù)面樣本少可以把負(fù)面閾值調(diào)高到0.35減少漏報(bào)。否定詞修正這一段不是SnowNLP自帶的是我自己加的經(jīng)驗(yàn)規(guī)則。因?yàn)闃闼刎惾~斯處理“不好”“不劃算”這類詞時(shí)會(huì)把“好”“劃算”單獨(dú)算正向整體判斷容易失真。加了否定詞修正后誤判會(huì)少一些但也不能覆蓋全部情況像“不錯(cuò)”本身就是正向加了否定規(guī)則反而錯(cuò)。所以這條規(guī)則必須只作用在帶有明確否定詞的句子上而且只把分?jǐn)?shù)拉回中性不要一刀切成負(fù)向。4.3 可視化報(bào)告圖表要能獨(dú)立打開展示層是老師對(duì)項(xiàng)目的第一印象它不決定算法水平但決定報(bào)告好不好看。常見做法是使用pyecharts生成獨(dú)立的HTML文件這樣不需要啟動(dòng)Flask也能打開。我的習(xí)慣是生成兩張圖一張?jiān)~云一張情感隨時(shí)間變化的折線圖。from pyecharts.charts import WordCloud, Line from pyecharts import options as opts import pandas as pd df pd.read_csv(output/result.csv, encodingutf-8-sig) # 以“正面/中性/負(fù)面”三類的數(shù)量做時(shí)間序列 date_group df.groupby([date, sentiment]).size().reset_index(namecount) pivot date_group.pivot(indexdate, columnssentiment, valuescount).fillna(0) line Line() line.add_xaxis(pivot.index.tolist()) for sent in [正面, 中性, 負(fù)面]: if sent in pivot.columns: line.add_yaxis(sent, pivot[sent].tolist(), is_smoothTrue) line.set_global_opts( title_optsopts.TitleOpts(title輿情情感趨勢(shì)), yaxis_optsopts.AxisOpts(name數(shù)量) ) line.render(output/trend.html) # 詞云使用pyecharts自帶wordcloud組件 wc WordCloud() wc.add(, [tuple(x) for x in df[word_weight].to_numpy()], word_size_range[20, 100], shapecircle) wc.render(output/wordcloud.html)這段代碼有兩個(gè)參數(shù)值得細(xì)調(diào)word_size_range控制詞云里最大字和最小字區(qū)間太寬會(huì)讓小詞看不清我一般用20到100shape可以換成diamond或pin但要注意太花哨的形狀會(huì)讓文字排版變亂答辯時(shí)用圓或云更好。一張圖表生成后先在瀏覽器里打開確認(rèn)路徑?jīng)]問題再放進(jìn)報(bào)告避免圖表白屏的尷尬。5. 拿到源碼后的避坑指南5個(gè)高頻報(bào)錯(cuò)與排查5.1 requests請(qǐng)求頻繁返回418或403現(xiàn)象采集腳本運(yùn)行幾頁后請(qǐng)求不再返回HTML而是返回一堆418或403狀態(tài)碼或者頁面內(nèi)容變成驗(yàn)證碼。原因目標(biāo)網(wǎng)站識(shí)別到了自動(dòng)化請(qǐng)求特征。最明顯的是沒有設(shè)置User-Agent或每分鐘請(qǐng)求次數(shù)遠(yuǎn)超正常人。高頻訪問下服務(wù)器直接把請(qǐng)求判定為爬蟲。解決給每個(gè)請(qǐng)求設(shè)置完整請(qǐng)求頭尤其是User-Agent和Referer。再把請(qǐng)求停頓從0.1秒提高到1.5秒以上必要時(shí)使用隨機(jī)延時(shí)。如果目標(biāo)網(wǎng)站驗(yàn)證碼強(qiáng)度太大換數(shù)據(jù)源。抓取公開搜索頁面和新聞RSS是最低風(fēng)險(xiǎn)的選擇不要死磕登錄才能看的內(nèi)容。5.2 分詞結(jié)果全都是單字詞云上全是“的、了、一”現(xiàn)象jieba切出來的詞全是單字幾乎看不到有意義的雙字詞。原因多半是分詞前做了過于激進(jìn)的正則清洗。比如把所有非中文字符都替換掉或者把長(zhǎng)度大于1的詞全濾掉了也可能自定義詞典沒有生效詞庫切不開“機(jī)器”“學(xué)習(xí)”這樣的常用詞。解決先檢查jieba.lcut(機(jī)器學(xué)習(xí))在命令行里是否能正確切出“機(jī)器學(xué)習(xí)”如果不能說明詞庫沒加載對(duì)改用jieba.load_userdict加載領(lǐng)域詞典。然后再看stopwords里是否誤把“機(jī)器”“學(xué)習(xí)”這類詞加進(jìn)停用表。排查時(shí)一條條打印過濾后的結(jié)果看到哪一步開始變成單字問題就在哪一步。5.3 SnowNLP情感得分全部偏高或全部居中現(xiàn)象整個(gè)數(shù)據(jù)集的sentiments都集中在0.6以上或者說幾乎全在0.4到0.6之間沒有區(qū)分度。原因SnowNLP默認(rèn)訓(xùn)練語料是電商購物評(píng)論在輿情這種新聞標(biāo)題、短評(píng)論場(chǎng)景下分布明顯偏正。所有人都高于0.5不代表所有輿情都正面而是模型沒見過這個(gè)領(lǐng)域的負(fù)面表達(dá)。解決先抽30條人工標(biāo)注畫出你數(shù)據(jù)真實(shí)的正負(fù)比例再把閾值從0.5調(diào)整到0.6/0.4。如果還是沒區(qū)分度就在情感打分前引入自定義情感詞典把“抗議、下架、處罰、泄露”這類領(lǐng)域敏感詞打上負(fù)面標(biāo)記覆蓋掉模型原本的誤判。這比換模型更快也更好解釋。5.4 pandas輸出CSV后Excel打開一片亂碼現(xiàn)象df.to_csv(result.csv)后用Excel打開全是亂碼但用記事本和Python讀都是正常的。原因pandas默認(rèn)用UTF-8編碼寫文件Excel對(duì)UTF-8的識(shí)別不友好讀成了本地系統(tǒng)編碼。解決寫CSV時(shí)指定編碼為utf-8-sig也就是在UTF-8文件開頭加BOM標(biāo)記Excel就能正確識(shí)別。具體寫法是df.to_csv(result.csv, indexFalse, encodingutf-8-sig)。這個(gè)坑不報(bào)錯(cuò)最容易被忽略答辯前拷到老師電腦上打開才發(fā)現(xiàn)就很被動(dòng)。5.5 本地打開生成的HTML圖表白屏現(xiàn)象瀏覽器雙擊trend.html和wordcloud.html頁面一片空白控制臺(tái)提示找不到某個(gè)JS文件。原因pyecharts在渲染圖表時(shí)會(huì)引用本地JS庫如果你在項(xiàng)目里改動(dòng)了render輸出路徑或把HTML文件挪到了別的目錄JS相對(duì)路徑就斷了。解決圖表HTML和負(fù)責(zé)JS的目錄要保持相對(duì)位置。最簡(jiǎn)單的處理方式是把所有生成的HTML放在output目錄下render(output/trend.html)之后不要再單獨(dú)移動(dòng)文件。如果一定要移動(dòng)用瀏覽器F12看控制臺(tái)里具體哪個(gè)資源404把對(duì)應(yīng)JS文件一起拷過去。答辯前記得到output目錄下雙擊HTML確認(rèn)每張圖都能獨(dú)立打開。6. 從能跑到高分答辯演示的結(jié)果驗(yàn)證和三個(gè)加分技巧到這一步系統(tǒng)已經(jīng)能跑坑也填完了剩下的工作是把“能運(yùn)行”包裝成“有價(jià)值”。我會(huì)建議先做一次結(jié)果驗(yàn)證再準(zhǔn)備三個(gè)演示細(xì)節(jié)。驗(yàn)證方法很簡(jiǎn)單從分析結(jié)果里隨機(jī)抽20條文本人工判斷正負(fù)和系統(tǒng)結(jié)果做對(duì)比算一個(gè)(一致條數(shù) / 總條數(shù))的準(zhǔn)確率。你不用把準(zhǔn)確率做到很高只要在答辯報(bào)告里寫明“隨機(jī)抽20條人工核對(duì)正確率85%”導(dǎo)師就會(huì)覺得你的結(jié)果可信。三個(gè)加分技巧里最實(shí)用的是給圖表加日期維度。很多輿情分析系統(tǒng)的圖表只是詞云和餅圖加一張情感隨日期變化的折線圖立刻讓項(xiàng)目有了“監(jiān)測(cè)”的意味。第二個(gè)技巧是在報(bào)告中交代數(shù)據(jù)來源和時(shí)間范圍比如“抽取某搜索平臺(tái)前3頁結(jié)果時(shí)間跨度為近一周”。這看起來簡(jiǎn)單但說明你考慮過數(shù)據(jù)邊界導(dǎo)師追問時(shí)你就不會(huì)慌。第三個(gè)技巧是準(zhǔn)備好一張“系統(tǒng)流程圖”不用畫得花哨框圖和箭頭足夠。答辯時(shí)你不必講代碼照著流程圖把數(shù)據(jù)從采集到展示走一遍老師基本就能理解后面提的問題也會(huì)圍繞流程展開而不是鉆到某個(gè)冷門函數(shù)里。我個(gè)人的習(xí)慣是每次跑完分析都順手把關(guān)鍵詞權(quán)重、情感分布和樣例文本存成一個(gè)結(jié)構(gòu)化文件報(bào)告里每張圖都能在數(shù)據(jù)里找到支撐。希望這些踩坑經(jīng)驗(yàn)和調(diào)參技巧能幫到你祝你的大作業(yè)順利答辯。本文還有配套的精品資源點(diǎn)擊獲取