:從京東爬蟲到機器學習模型全流程解析)
簡介圍繞基于機器學習的商品評論情感分析這份畢業(yè)設(shè)計壓縮包面向計算機專業(yè)學生可用于課程設(shè)計、畢設(shè)答辯或自然語言處理入門實戰(zhàn)。項目涵蓋評論爬取、數(shù)據(jù)清洗、分詞、情感詞典構(gòu)建、詞頻-逆文檔頻率與詞向量特征提取以及樸素貝葉斯、支持向量機、極端梯度提升、長短期記憶網(wǎng)絡(luò)等多種模型的訓練與評估并提供圖形界面和可視化腳本能展示完整的分析流程。資源共43個文件、約66.66MB以Python腳本、表格數(shù)據(jù)、模型文件及配置文檔為主包含14個Python程序、7個CSV數(shù)據(jù)文件、2個Excel表格和多個訓練好的情感分類模型與詞向量模型適合直接運行和二次修改。目前已有167人學習下載。總體而言這份壓縮包覆蓋從數(shù)據(jù)采集到報告撰寫的完整環(huán)節(jié)并補充了Git版本管理、超參數(shù)搜索等實踐細節(jié)是一份能支撐實際答辯和功能演示的畢業(yè)設(shè)計資料。1. 情感分析不是看“好評/差評”那么簡單這個畢業(yè)設(shè)計到底在做什么你可能以為“商品評論情感分析”就是把五星好評算正面、一星差評算負面然后用機器學習算法跑一個準確率就完事。但真正動手抓過京東或淘寶評論的人都知道評論區(qū)里充斥著“默認好評”的模板文本、和商品毫不相干的湊字評價、還有那種“物流很快但質(zhì)量稀爛”的混合情感。這個基于機器學習的商品評論情感分析項目核心不是模型有多深而是你能不能把“用戶到底對商品持什么態(tài)度”這件事從一堆噪聲里可靠地抽出來。它適合正在做機器學習課程設(shè)計或畢業(yè)設(shè)計的同學也適合想入門 NLP 分類任務(wù)的從業(yè)者。本文把從爬蟲、清洗、特征工程到模型調(diào)參與評估的完整鏈路拆開講給你一套能照著復現(xiàn)的落地方案。2. 定技術(shù)路線先想清楚數(shù)據(jù)從哪來、模型學到什么再談準確率2.1 數(shù)據(jù)源選型為什么“爬京東評論”是主流選擇這個項目的數(shù)據(jù)來源常見做法是爬取京東商品評論。京東的評論區(qū)有一個半公開的 JSON 接口比淘寶的反爬策略溫和得多返回字段結(jié)構(gòu)化程度高自帶評分、追評時間、購買屬性等元信息非常適合做情感分析的初始數(shù)據(jù)集。而且京東評論區(qū)分“好評”“中評”“差評”三個標簽頁方便你直接拿到標注數(shù)據(jù)做有監(jiān)督學習。爬蟲的請求頭里必須帶上User-Agent和Referer否則京東會返回 403。接口核心參數(shù)是productId商品 ID、score0 全部 / 1 好評 / 2 中評 / 3 差評、page和pageSize。要注意的是京東這個接口單頁最多返回 10 條評論翻頁超過一定深度會被風控攔截所以做畢業(yè)設(shè)計的話多換幾個商品 ID 比死磕單商品翻頁更穩(wěn)妥。當接口返回的commentsCount為 0 或code不為0時說明被限流了此時不要繼續(xù)請求退避 3 到 5 秒再試。代碼里要保留原始響應(yīng)文本方便排查編碼問題。抓下來的數(shù)據(jù)至少要有四個字段評論內(nèi)容、評分、點贊數(shù)、評論時間。評分是后文標注情感標簽的基礎(chǔ)而點贊數(shù)可以作為“這條評論是否具有代表性”的輔助特征。import requests import json import time def fetch_jd_comments(product_id, score0, page1, page_size10): url https://club.jd.com/comment/productPageComments.action params { productId: product_id, score: score, sortType: 5, # 按時間排序保證每次抓取順序穩(wěn)定 page: page, pageSize: page_size, # 固定10接口不接受更大的值 isShadowSku: 0, fold: 1, } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: fhttps://item.jd.com/{product_id}.html, } resp requests.get(url, paramsparams, headersheaders, timeout15) data resp.json() if data.get(code) ! 0: print(fpage {page} 被限流任務(wù)中止) return [] rows [] for c in data.get(comments, []): rows.append({ content: c.get(content, ), score: c.get(score), recommend: c.get(recommend, ), comment_date: c.get(creationTime, ), product_id: product_id, }) return rows if __name__ __main__: rows fetch_jd_comments(100012043978, score0, page1) print(f抓取到 {len(rows)} 條評論示例內(nèi)容: {rows[0][content][:30]})參數(shù)里sortType5是按時間排序如果不固定排序方式翻頁時可能拿到重復評論影響后續(xù)去重統(tǒng)計。isShadowSku和fold這兩個參數(shù)保持默認即可基本不需要改動。建議把抓取結(jié)果實時落盤成 JSON 或 CSV避免中途斷網(wǎng)導致全部重跑。我一般會加一個斷點續(xù)爬邏輯用已抓取的文件行數(shù)作為下次抓取的起始頁但畢設(shè)規(guī)模的數(shù)據(jù)量通常不需要這么復雜手動分段跑就夠了。2.2 分類粒度二分類、三分類還是五分類分類粒度決定了項目的工程復雜度和評估方式。最省事的是二分類把評分 4 到 5 星視為正面1 到 2 星視為負面3 星直接丟棄。這樣邊界干凈類別均衡也好控制。但答辯時容易被老師追問“中評為什么不要”所以如果你的數(shù)據(jù)量能支撐建議做三分類好評 / 中評 / 差評對應(yīng)評分 5 / 3 / 1把 4 星和 2 星作為模糊地帶并入相鄰類別。五分類看上去更細致但負面樣本通常不夠且 1 星和 2 星的文本差異極小——“一般般”和“很差”之間的邊界詞向量根本分不開模型容易在相鄰類別上亂跳。我做這個項目時選了四分類好評、差評、中評、默認好評模板文本單獨歸一類。這樣既避免了模糊地帶的標注噪聲也把京東特有的“此用戶未填寫評價內(nèi)容”這類垃圾樣本隔離出去不污染正文模型。標注映射關(guān)系建議做成配置文件或一個清晰的函數(shù)不要散落在代碼里。后續(xù)如果要換分類粒度只改這一處映射即可別的地方全部復用。def score_to_label(score): if score in (5,): return positive elif score in (4, 3): return neutral elif score in (2, 1): return negative else: return unknown import pandas as pd df pd.read_csv(jd_comments.csv) df[label] df[score].apply(score_to_label) print(df[label].value_counts())這個映射有個細節(jié)京東評分是離散的 1 到 5但不同商品的評分分布差異很大有的商品 4 星偏多有的 3 星偏多。直接用評分映射會產(chǎn)生類別不均衡后面的處理章節(jié)會詳細講。在這個階段你要關(guān)心的是每個類別的樣本量是否能撐起訓練我一般要求每個類別不少于 3000 條否則模型學不到可靠模式。2.3 技術(shù)棧與評估口徑先定標準再談?wù){(diào)參技術(shù)棧的選擇要匹配你的運行環(huán)境。如果只有 CPU就不要一上來就上 BERT訓練一個 epoch 可能要幾小時答辯前很容易翻車。最穩(wěn)的組合是Python pandas jieba scikit-learn模型用樸素貝葉斯或邏輯回歸打底時間充足再試試 LSTM。BERT 或者transformers這類深度模型可以作為加分項寫在“后續(xù)工作”里不用強行跑通。評估口徑要提前想清楚。類別不均衡時準確率是騙人的——如果負面樣本只占 5%全部預(yù)測成正面也有 95% 的準確率。正確的評估指標是宏平均 F1macro-F1和混淆矩陣。宏平均 F1 把每個類別的 F1 單獨算再取平均能真實反映小類別的表現(xiàn)。這個口徑從第一篇實驗開始就固定下來中途不要換否則前后對比沒有意義。from sklearn.metrics import classification_report, f1_score y_true [...] # 真實標簽 y_pred [...] # 模型預(yù)測標簽 report classification_report(y_true, y_pred, target_names[negative, neutral, positive]) print(report) # 重點看 macro avg 那一行的 f1-score如果你用的是 scikit-learn 的接口classification_report會一次性給出每個類別的精確率、召回率、F1 和樣本數(shù)。我一般要求宏平均 F1 穩(wěn)定在 0.80 以上才算及格0.85 以上是良好0.90 以上需要比較干凈的語料才能達到。數(shù)據(jù)噪聲很高的情況下0.80 就是很好的結(jié)果了不要盲目追求高指標。3. 把京東評論變成干凈的訓練集清洗、去重與標注修正3.1 清洗去掉模板文本、HTML 標簽和超長噪聲京東評論區(qū)有大量非自然語言的文本。最常見的三類一是“此商品太棒了我很喜歡”之類的系統(tǒng)默認好評提示二是用戶粘貼的商品參數(shù)或活動鏈接三是純表情或“哈哈哈哈”這類無信息量文本。清洗的目標不是把文本變漂亮而是把模型不需要學的噪聲去掉否則模型會把“默認好評”學成一個獨立類別而不是學到真實的情感表達。清洗順序很關(guān)鍵。先處理 HTML 實體和解碼問題再做長度過濾最后做關(guān)鍵詞去噪。如果先做長度過濾含大量標簽但正文很短的文本會被誤刪。我一般用正則把[a-zA-Z];這類 HTML 實體替換成空格再把http[s]?://\S替換成空字符串。長度過濾的閾值設(shè)在 2 到 100 字之間低于 2 字的沒有信息量高于 100 字的可能是復制粘貼的評測文章對情感分類沒有幫助。import re import pandas as pd html_pattern re.compile(r[a-zA-Z];) url_pattern re.compile(rhttps?://\S) def clean_text(text): if not isinstance(text, str): return text html_pattern.sub( , text) text url_pattern.sub( , text) text re.sub(r\s, , text).strip() return text df pd.read_csv(jd_comments.csv) df[clean] df[content].apply(clean_text) df[len] df[clean].apply(len) df df[df[len] 2]這一步要輸出一個清洗后可讀的 CSV并肉眼抽樣檢查 200 條左右。檢查的目的不是看清洗規(guī)則對不對而是看有沒有漏網(wǎng)的異常文本。如果發(fā)現(xiàn)某種噪聲頻繁出現(xiàn)就把它對應(yīng)的正則或規(guī)則補進去。清洗是迭代的過程不要指望一次到位。常見的漏網(wǎng)之魚是“此用戶很懶什么都沒有留下”這類半模板文本它包含真實情感嗎不包含需要單獨過濾。3.2 去重同一個用戶在不同商品下的重復評論京東用戶會在多個商品下復制粘貼同一條評論尤其是參與返京豆活動的用戶。這類重復評論如果不處理模型會嚴重過擬合到重復文本上導致驗證集準確率高但真實場景表現(xiàn)差。去重不能只做字符串完全匹配因為用戶可能只改一個標點或加一個空格我一般用歸一化后的文本做去重去掉所有空格和標點再比較是否相等。更狠一點的做法是算文本之間的編輯距離但畢設(shè)數(shù)據(jù)量在小萬級別時直接跑difflib會慢到懷疑人生。折中方案是先用文本哈希粗篩再對哈希相同的分組做兩兩編輯距離驗證。我實踐下來歸一化完全匹配已經(jīng)能解決大部分問題編輯距離留給極端情況。import re def normalize_for_dedup(text): return re.sub(r[\s\W_], , text) df[norm] df[clean].apply(normalize_for_dedup) df df.drop_duplicates(subset[norm], keepfirst) print(f去重后剩余 {len(df)} 條評論)去重后會改變類別分布所以去重要在清洗之后、劃分訓練測試集之前完成。順序錯了的話測試集里可能混著訓練集見過的重復文本評估結(jié)果虛高。我踩過這個坑第一次實驗沒去重測試集準確率 0.91去掉重復后直接掉到 0.83這才意識到測試集泄漏了。3.3 標注修正評分不等于情感怎么處理“陰陽怪氣”評分與真實情感并不總是對齊。有人給 1 星但評論內(nèi)容是“東西還行就是快遞太慢了”也有人給 5 星但寫的是“幫朋友買的不知道質(zhì)量如何”。如果完全信任評分做標簽?zāi)P蜁W到錯誤模式。但手工重標上萬條不現(xiàn)實我一般用規(guī)則加抽檢來修正先標記出“評分與文本情感沖突”的候選樣本再抽 10% 人工確認。候選標記的規(guī)則很簡單文本里出現(xiàn)明確的矛盾信號詞比如“快遞慢”“質(zhì)量差”“客服不理人”的同時評分大于等于 4或者出現(xiàn)“好評”但評分小于等于 2。這類樣本通常只占總量 5% 左右人工處理成本可控。也可以在標注修正后直接丟棄這些沖突樣本因為它們屬于標注噪聲保留會讓模型的決策邊界更模糊。conflict_keywords [快遞慢, 質(zhì)量差, 客服, 退貨, 垃圾, 差評] def flag_conflict(row): text row[clean] if any(k in text for k in conflict_keywords) and row[score] 4: return True return False df[conflict] df.apply(flag_conflict, axis1) print(f發(fā)現(xiàn)疑似沖突樣本 {df[conflict].sum()} 條) df_core df[~df[conflict]].copy()這一步的意義在于你辛辛苦苦用規(guī)則修正的每一個標簽都在告訴模型“評分只是弱信號文本才是強信號”。我見過很多情感分析項目分數(shù)很高但把測試集里的沖突樣本挑出來看模型幾乎全錯。核驗方式很簡單訓練完成后單獨抽出沖突樣本子集看分類準確率如果低于 0.5說明模型過度依賴評分風格而非文本語義需要加強清洗或調(diào)整特征。4. 讓中文變成機器能讀的數(shù)字分詞、停用詞與向量化4.1 分詞為什么不直接用 jieba 默認詞典中文文本沒有天然空格分詞是特征工程的起點。jieba 是最常見的工具自帶詞典覆蓋多數(shù)通用詞匯但在商品評論領(lǐng)域會出現(xiàn)“入股不虧”“避雷”“YYDS”這類網(wǎng)絡(luò)新詞默認詞典分不出來就會被切碎成單字丟失語義信息。解決方法是先對語料做一次詞頻統(tǒng)計找出被切碎的高頻詞手動加入自定義詞典。自定義詞典的格式很簡單每行一個詞可以帶詞頻和詞性。詞頻不要拍腦袋我一般按語料規(guī)模估算如果總詞數(shù)是 50 萬一個出現(xiàn) 200 次以上的詞詞頻給 5 就夠。詞頻給太高會影響 jieba 對其他詞的分詞判斷反而引入噪聲。分詞之后做一次驗證打印 50 條隨機文本的分詞結(jié)果看看品牌名、商品名、情感詞是否正確切開。import jieba # user_dict.txt 每行: 詞 詞頻 詞性 # YYDS 500 nz # 避雷 300 v jieba.load_userdict(user_dict.txt) def tokenize(text): return [w for w in jieba.cut(text) if w.strip()] df_core[tokens] df_core[clean].apply(tokenize) print(df_core[tokens].head(10).tolist())分詞結(jié)果要保存下來后續(xù) TF-IDF 和 Word2Vec 都要復用不要每次訓練都重新分詞。分詞參數(shù)里唯一需要調(diào)的其實是詞典jieba.cut的HMM參數(shù)默認開對未登錄詞有補充識別效果但也會把一些英文混著中文的文本切亂。如果語料里英文占比較高可以把HMMFalse試一試對比一下前后效果再決定。4.2 TF-IDF向量化三個必調(diào)參數(shù)TF-IDF 是把分詞結(jié)果轉(zhuǎn)成向量最直接的方法。sklearn 的TfidfVectorizer有三個參數(shù)對最終效果影響最大max_features、min_df和ngram_range。max_features控制特征數(shù)量商品評論文本量級在 1 萬條左右時5000 到 10000 個特征就夠用設(shè)太大內(nèi)存容易爆設(shè)太小信息量不夠。min_df是文檔頻率下限默認 1 會把只出現(xiàn)一次的生僻詞也納入特征我一般設(shè) 5讓至少出現(xiàn)在 5 條評論里的詞才進入詞表。ngram_range是容易被忽略的點。二元詞組(1, 2)能捕捉“質(zhì)量好”“物流慢”這類組合情感比單個詞更穩(wěn)定但特征維度會翻幾倍。我建議先跑(1, 1)做基線再試(1, 2)對比 F1 有沒有提升。如果提升不到 1 個百分點就留在(1, 1)因為特征維度過高會導致訓練時間變長邏輯回歸還好換成其他模型就吃力了。from sklearn.feature_extraction.text import TfidfVectorizer df_core[text] df_core[tokens].apply(lambda x: .join(x)) vectorizer TfidfVectorizer( max_features8000, min_df5, ngram_range(1, 2), sublinear_tfTrue, # 用 1log(tf) 代替原始詞頻緩解高頻詞主導 ) X vectorizer.fit_transform(df_core[text]) y df_core[label] print(f特征矩陣形狀: {X.shape})sublinear_tf是我覺得最值得開的一個參數(shù)。京東評論區(qū)“的”“了”“就”這類虛詞即使加了停用詞表也未必清干凈開了sublinear_tf之后詞頻差異被壓縮模型不再被高頻無義詞帶偏。特征矩陣是稀疏矩陣保存時直接用scipy.sparse.save_npz存成.npz文件下次加載不重復計算能省不少時間。4.3 詞向量與序列模型Word2Vec 到底該自己訓練還是下載現(xiàn)成的如果你想嘗試 LSTM 這類序列模型就得把文本轉(zhuǎn)成詞向量序列。有兩個選擇用現(xiàn)成的中文詞向量或者用 gensim 在自己的語料上訓練 Word2Vec。畢設(shè)層面我更推薦自己在語料上訓練因為中文通用詞向量是在新聞、百科等正式語料上訓練的對“便宜大碗”“踩雷”這類電商口語詞覆蓋很差。自訓練只需設(shè)置維度、窗口、最小詞頻三個參數(shù)。維度通常設(shè) 100 到 200太小表達不了語義差異太大在小語料上容易過擬合。窗口設(shè) 5 是默認值處理短文本評論夠用。min_count設(shè) 5出現(xiàn)次數(shù)少于 5 的詞直接丟棄否則向量質(zhì)量會被稀有詞的噪聲拖垮。訓練完成后一定要做一次相似詞測試比如查“質(zhì)量”的 top 10 相似詞如果出來一堆不相關(guān)的詞說明語料量不夠或參數(shù)不合適。from gensim.models import Word2Vec from gensim.models.word2vec import LineSentence # 把分詞結(jié)果寫入文件每行一條評論詞與詞用空格分隔 with open(corpus.txt, w, encodingutf-8) as f: for tokens in df_core[tokens]: f.write( .join(tokens) \n) model Word2Vec( sentencesLineSentence(corpus.txt), vector_size150, window5, min_count5, workers4, epochs10, ) print(model.wv.most_similar(質(zhì)量, topn10))epochs10在短文本語料上比默認的 5 效果更好因為每條評論太短單次遍歷學不到足夠的共現(xiàn)信息。這里要注意一個常見翻車點Word2Vec在 gensim 4.0 之后把size參數(shù)改名成了vector_size網(wǎng)上老教程抄過來會直接報 TypeError。詞向量訓練好后要保存為word2vec.model和word2vec.kv兩個文件模型給后續(xù)微調(diào)用kv 給快速加載用。5. 模型評估與避坑清單準確率虛高、樣本不均衡和過擬合的血淚記錄5.1 基線模型對比樸素貝葉斯、邏輯回歸、LSTM 的取舍不要一上來就訓深度學習模型。我一般先跑兩個傳統(tǒng)機器學習基線樸素貝葉斯和邏輯回歸。樸素貝葉斯在短文本分類上很強計算快適合做下限參考邏輯回歸在 TF-IDF 特征上表現(xiàn)穩(wěn)定且系數(shù)可以直接當特征重要性看答辯時解釋起來很有說服力。如果這兩個模型的宏平均 F1 已經(jīng)到 0.82那 LSTM 至少要超過 0.84 才有繼續(xù)調(diào)的必要不然直接交付傳統(tǒng)方案更劃算。from sklearn.naive_bayes import MultinomialNB from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import f1_score X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) nb MultinomialNB(alpha1.0) nb.fit(X_train, y_train) y_pred_nb nb.predict(X_test) print(fMultinomialNB macro-F1: {f1_score(y_test, y_pred_nb, averagemacro):.4f}) lr LogisticRegression(max_iter1000, C1.0, class_weightbalanced) lr.fit(X_train, y_train) y_pred_lr lr.predict(X_test) print(fLogisticRegression macro-F1: {f1_score(y_test, y_pred_lr, averagemacro):.4f})class_weightbalanced是處理類別不均衡最省事的辦法它會按類別頻率反向加權(quán)讓少數(shù)類別在損失函數(shù)里的占比提升。注意邏輯回歸的max_iter默認 100TF-IDF 特征維度高時經(jīng)常不收斂要調(diào)到 1000 以上。至于 LSTM代碼量比前兩個大得多我放到下一節(jié)講。你還要記錄每個模型的訓練時間答辯時這張“傳統(tǒng) vs 深度學習”的對比表非常加分。5.2 避坑清單五條必看的踩坑記錄5.2.1 準確率 0.93 但模型實際是廢的現(xiàn)象測試集準確率看著很高隨手抽 20 條真實評論預(yù)測錯了一半。 原因類別不均衡。負面樣本只占 6%模型全預(yù)測成正面也有 94% 的準確率。 解決換成宏平均 F1 作為主指標并在訓練時使用class_weightbalanced或過采樣/欠采樣。我常用imbalanced-learn庫的RandomOverSampler但要注意過采樣會讓驗證集評估偏樂觀最好在過采樣之前劃分數(shù)據(jù)。5.2.2 測試集泄漏去重不徹底導致指標虛高現(xiàn)象模型在測試集上 F1 高達 0.92部署到新數(shù)據(jù)上直接崩到 0.75。 原因清洗后忘記去重同一條評論同時出現(xiàn)在訓練集和測試集。 解決去重必須先于數(shù)據(jù)劃分。更嚴格的做法是校驗用戶 ID確保同一個用戶的評論不會跨集合出現(xiàn)因為同一個人的用語風格會讓模型學到“人”而不是“情感”。5.2.3 jieba 分詞把“不”和“好”切開導致情感反轉(zhuǎn)識別失敗現(xiàn)象模型對“不好”“不行”“不喜歡”全部預(yù)測錯誤。 原因默認詞典沒有把“不好”這類組合詞切成一個整體TF-IDF 把“不”和“好”當成獨立特征語義被割裂。 解決建立否定詞典把“不好”“不行”“不滿意”等加入自定義詞典或者在特征基礎(chǔ)上疊加“否定詞 相鄰情感詞”的組合特征。我實測這個操作能讓負面類別 F1 提升 3 到 5 個百分點。5.2.4 Word2Vec 訓練后相似詞一片混亂現(xiàn)象most_similar(質(zhì)量)返回的全是數(shù)字、標點這類無意義 token。 原因語料太小或者min_count太低把噪聲詞也納入了詞表。 解決把min_count從 5 提到 10同時檢查清洗環(huán)節(jié)是否把數(shù)字和標點全清干凈了。如果語料只有幾千條不要強行用 Word2Vec換 TF-IDF 更穩(wěn)。5.2.5 模型對“快遞”相關(guān)評論集體誤判為差評現(xiàn)象包含“快遞”的評論大量被預(yù)測為負面但實際上很多是好評。 原因語料里“快遞慢”“快遞垃圾”等負面表達占比過高模型學到“快遞”這個詞與負面的弱相關(guān)性。 解決訓練前做一次特征分析把高頻但與情感無關(guān)的強特征降權(quán)或者直接用邏輯回歸系數(shù)定位這類問題。真正的解法是擴充正面語料中“快遞”出現(xiàn)的比例讓模型看到“快遞很快”也能是正面的。5.3 混淆矩陣與錯誤分析指標準確不代表業(yè)務(wù)可靠混淆矩陣能告訴你模型具體在哪些類別之間混淆。對于三分類情感分析最常見的現(xiàn)象是“中評”與“好評”之間界限模糊因為京東的 3 星用戶常寫“還行吧”情感本身就不強烈。如果中評類別被大量分到好評你可以選擇調(diào)整中評的判定閾值也可以在訓練時給中評樣本更高的權(quán)重。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred_lr, labels[negative, neutral, positive]) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labels[negative, neutral, positive]) disp.plot(cmapBlues) plt.savefig(confusion_matrix.png, dpi150, bbox_inchestight)畫混淆矩陣是給答辯看的但更重要的是從矩陣讀出下一步行動。如果中評和好評的混淆數(shù)占了總誤差的 60%說明分類粒度本身可能不合理與其調(diào)參不如回到 2.2 節(jié)改分類定義。模型評估做到這個深度在一眾只看準確率的畢設(shè)里已經(jīng)能拉開差距了。6. 把模型從“能跑”變成“能答辯”驗證細節(jié)、可解釋性與交付技巧6.1 交叉驗證別讓隨機種子決定你的成績單次劃分訓練測試集結(jié)果受隨機種子影響很大。我做實驗時固定用 5 折交叉驗證取宏平均 F1 的均值和標準差。標準差能反映模型的穩(wěn)定性如果五折之間 F1 波動超過 0.03說明數(shù)據(jù)分布不均勻或模型過擬合了某一類樣本。交叉驗證的結(jié)果寫進論文里比單次結(jié)果有說服力得多。from sklearn.model_selection import cross_val_score scores cross_val_score(lr, X, y, cv5, scoringf1_macro) print(f5-fold macro-F1: {scores.mean():.4f} ± {scores.std():.4f})6.2 可解釋性用邏輯回歸系數(shù)講清楚“模型為什么這么判”畢業(yè)設(shè)計答辯時老師最常問的問題是“你的模型依據(jù)什么做出判斷”。用深度學習模型很難回答但邏輯回歸的系數(shù)可以直接對應(yīng)到詞特征。把系數(shù)絕對值 top 20 的詞打印出來正系數(shù)是正面詞負系數(shù)是負面詞這就是一個樸素但直觀的解釋。如果要展示單條評論的預(yù)測理由可以用 LIME 庫生成局部解釋我在項目里對每類隨機抽 5 條評論做了解釋放在論文附錄里。6.3 交付物清單與驗收標準交付時不要只給一個訓練好的模型文件要包含完整的四件套清洗與爬蟲腳本、特征與訓練代碼、模型文件、評估報告。評估報告里至少有三張圖類別分布圖、混淆矩陣、宏平均 F1 的折線對比圖。驗收標準不是模型跑通而是新抓的 1000 條評論經(jīng)過你的推理鏈路后宏平均 F1 不低于訓練時的 95%。我自己做這類項目養(yǎng)成的習慣是每次改完數(shù)據(jù)或模型先把結(jié)果記錄在一個 Markdown 文件里再繼續(xù)下一步。沒有記錄的實驗等于沒做。這個習慣讓后面寫論文時省了大量回頭補實驗的時間。希望幫到你少踩一些我踩過的坑。本文還有配套的精品資源點擊獲取