戰(zhàn))
簡介這是一套基于Word2Vec與SVM對電商評論進(jìn)行情感分析的完整Python項(xiàng)目面向NLP初學(xué)者、數(shù)據(jù)挖掘?qū)W習(xí)者以及需要快速落地評論分析流程的電商運(yùn)營與開發(fā)人員。項(xiàng)目覆蓋數(shù)據(jù)預(yù)處理、Word2Vec詞向量訓(xùn)練、特征矩陣構(gòu)建、SVM模型訓(xùn)練與調(diào)優(yōu)、模型評估等關(guān)鍵環(huán)節(jié)并提供可運(yùn)行的代碼與配套數(shù)據(jù)集。壓縮包共18個(gè)文件包括6個(gè)CSV數(shù)據(jù)文件、5個(gè)Python腳本、4個(gè)NumPy數(shù)組文件以及訓(xùn)練好的SVM模型、停用詞表和說明文檔整體大小約30.15MB。腳本按數(shù)據(jù)清洗、詞向量訓(xùn)練、模型構(gòu)建、模型測試等模塊拆分訓(xùn)練好的pkl模型可直接加載使用CSV與npy文件則方便讀者對照訓(xùn)練與驗(yàn)證。目前已有1050人學(xué)習(xí)下載適合希望獲得可直接運(yùn)行的情感分析案例、通過動(dòng)手實(shí)踐掌握NLP與機(jī)器學(xué)習(xí)完整流程的用戶。1. 電商評論情感分析為什么用 Word2Vec SVM一個(gè) 5000 條樣本就能跑通的老實(shí)方案做電商的都知道評論數(shù)據(jù)是離業(yè)務(wù)最近的文本資產(chǎn)。單靠人工盯評價(jià)詳情頁一天幾百條還行到了大促期間幾千條差評根本看不過來。我處理這個(gè)需求時(shí)第一反應(yīng)不是上 BERT 或者 ChatGLM 微調(diào)而是用 Word2Vec SVM 這個(gè)老組合先把評論里的詞轉(zhuǎn)成向量再做一次二分類情感判斷。原因很直接——電商評論普遍只有幾十個(gè)字語法碎片化嚴(yán)重但情感信號集中在少數(shù)關(guān)鍵詞上這種場景恰恰是 Word2Vec 善于捕捉的。加上 SVM 對小樣本、高維特征分類穩(wěn)健在幾千條有標(biāo)注的評論上就能產(chǎn)出可用模型還不需要 GPU。這套方案在真實(shí)項(xiàng)目里最大的價(jià)值是可控?cái)?shù)據(jù)就是一張兩列的 CSV腳本理順之后十幾分鐘出結(jié)果調(diào)參路徑清晰業(yè)務(wù)方要的“好評率統(tǒng)計(jì)”“差評預(yù)警”都能直接落地。下面從數(shù)據(jù)集準(zhǔn)備開始一步步把流程跑通。2. 數(shù)據(jù)集準(zhǔn)備與中文預(yù)處理從一條淘寶評論到一個(gè)干凈詞表2.1 數(shù)據(jù)集格式兩列 CSV好評 1 差評 0幾千條就能跑標(biāo)題里說“含數(shù)據(jù)集可直接運(yùn)行”落地時(shí)最省心的數(shù)據(jù)集格式就是 CSV兩列l(wèi)abel和review。label用整數(shù)1 表示好評0 表示差評。別把評分列混進(jìn)來做三分類二分類是電商評論情感分析最常見、也最容易評估的切法等業(yè)務(wù)成熟了再擴(kuò)展成中立/正面/負(fù)面三分類也不遲。數(shù)據(jù)量上5000 條有標(biāo)注評論已經(jīng)能跑出一個(gè)業(yè)務(wù)可用的模型少于 2000 條時(shí)SVM 的調(diào)參空間會變小但依然比隨機(jī)猜強(qiáng)很多。如果你手頭只有幾百條優(yōu)先保證差評數(shù)據(jù)占比別太低后面會看到這直接影響模型能不能識別差評。下面這段代碼生成一個(gè)最小的示例 CSV方便你先跑通流程再替換成自己的真實(shí)數(shù)據(jù)import pandas as pd # label: 1 表示好評0 表示差評 data pd.DataFrame([ (1, 質(zhì)量好孩子很喜歡推薦), (1, 發(fā)貨很快包裝嚴(yán)實(shí)客服態(tài)度也好), (0, 用了三天就壞申請退貨還拖了一天), (0, 實(shí)物和圖片差太遠(yuǎn)不值這個(gè)價(jià)), ], columns[label, review]) data.to_csv(ecommerce_review.csv, indexFalse, encodingutf-8-sig) print(data)這段代碼的關(guān)鍵是列名必須叫l(wèi)abel和review后續(xù)所有處理函數(shù)都按這兩個(gè)字段寫避免在數(shù)據(jù)清洗時(shí)反復(fù)改字段名。encodingutf-8-sig是給 Excel 用戶留的活路——Windows 下直接雙擊打開 CSV帶 BOM 頭才不會亂碼。真實(shí)數(shù)據(jù)如果來自訂單系統(tǒng)通常會有評分字段常見做法是把 4 分及以上映射為好評1 到 2 分映射為差評3 分先丟掉或單獨(dú)留存別硬塞進(jìn)二分類里把邊界搞臟。2.2 中文評論清洗與 jieba 分詞正則、停用詞、否定詞別刪電商評論最麻煩的不是長而是臟表情符號、火星文、英文縮寫、錯(cuò)別字、廣告信息混在一起。清洗的目標(biāo)不是把文本變成標(biāo)準(zhǔn)書面語而是最大限度保住情感信號。我的處理順序是先去掉非中文/非字母/非數(shù)字的符號再做分詞最后按停用詞表過濾。這里有個(gè)容易翻車的點(diǎn)停用詞表不要包含否定詞。很多開源停用詞表把“不、沒、別、無”也收進(jìn)去了分詞后刪掉它們“太差了”會變成“太差”意思還在“不喜歡”變成“喜歡”情感直接反轉(zhuǎn)。這是血淚經(jīng)驗(yàn)我第一次做的時(shí)候用的通用停用詞表模型 f1 一直在 0.6 附近打轉(zhuǎn)后來檢查預(yù)處理結(jié)果才發(fā)現(xiàn)差評里全是反向詞被刪光了。import re import jieba # 停用詞集合只放真正的虛詞和標(biāo)點(diǎn)占位詞不放否定詞 STOP_WORDS set( 的 了 是 在 我 有 和 就 都 一 一個(gè) 很 也 你 他 她 它 這個(gè) 那個(gè) 還 又 才 吧 啊 呢 嗎 哦 嗯 呀 啦.split() ) def clean_text(text: str) - str: # 只保留中文、英文字母和數(shù)字去掉表情與特殊符號 text re.sub(r[^\u4e00-\u9fa5A-Za-z0-9], , text) # 把連續(xù)空格壓縮成一個(gè)避免分詞時(shí)空 token 干擾 return re.sub(r\s, , text).strip() def cut_words(text: str): cleaned clean_text(text) words [w for w in jieba.cut(cleaned) if w.strip() and w not in STOP_WORDS] return words data[words] data[review].apply(cut_words) print(data[[review, words]].head())正則里的\u4e00-\u9fa5是中文 Unicode 范圍加上A-Za-z0-9是為了保留“yyds”“iPhone15”這類英文數(shù)字混排的詞它們在電商評論里往往帶著明確情感傾向。jieba.cut默認(rèn)全模式還是精確模式這里用的是默認(rèn)精確模式對短文本足夠。分詞后過濾空字符串和停用詞但注意單字詞“好”“差”“快”這類有情感色彩的字別一并過濾所以停用詞表里我沒放“好”和“差”。如果你發(fā)現(xiàn)某些商品詞被 jieba 切碎比如“空氣炸鍋”被切成“空氣”“炸鍋”最省事的辦法是加自定義詞典jieba.load_userdict(user_dict.txt) # user_dict.txt 每行一個(gè)詞空氣炸鍋 5 n這個(gè)文件里每行格式是“詞 詞頻 詞性”詞頻建議寫 10 以上讓 jieba 優(yōu)先識別成整詞。新品牌名、行業(yè)黑話都丟進(jìn)去能明顯減少后續(xù) Word2Vec 學(xué)到碎片向量的問題。3. 用 Gensim 自己訓(xùn) Word2Vec參數(shù)怎么設(shè)句子向量怎么來3.1 為什么不直接用預(yù)訓(xùn)練詞向量電商黑話和通用向量對不上很多人拿到中文文本第一反應(yīng)是加載一個(gè)預(yù)訓(xùn)練詞向量比如騰訊詞向量或百度百科向量。它們在通用領(lǐng)域確實(shí)好但放到電商評論里有一個(gè)很尷尬的問題商品黑話、平臺梗、營銷詞在公共語料里要么沒收錄要么上下文完全是另一套場景。“白菜價(jià)”在百科語料里可能和“蔬菜批發(fā)”共現(xiàn)在電商評論里卻和“劃算”共現(xiàn)——這種語義偏移會直接污染下游分類。自己用評論語料訓(xùn) Word2Vec 的好處就在這里向量是從你的數(shù)據(jù)里長出來的“垃圾”的鄰居會變成“差勁”“不值”“退貨”而不是百科里的“廢品回收”。代價(jià)只是多花幾十秒訓(xùn)練時(shí)間對幾千條評論來說完全可忽略。而且 Word2Vec 不是深度神經(jīng)網(wǎng)絡(luò)它本質(zhì)上是在做詞共現(xiàn)的矩陣分解小語料也能訓(xùn)。min_count 調(diào)低一點(diǎn)、維度給小一點(diǎn)效果不會因?yàn)閿?shù)據(jù)量少就崩盤。這正好匹配電商評論的語料規(guī)模。3.2 用 Gensim 訓(xùn)練 Word2Vecvector_size、window、min_count 怎么給我用 Gensim 4.x 版本參數(shù)名和舊版有差異最典型的是size改成了vector_size照著舊教程寫會直接報(bào)錯(cuò)。訓(xùn)練代碼不長真正值得花時(shí)間的是參數(shù)怎么給from gensim.models import Word2Vec sentences data[words].tolist() # 每條評論是分詞后的 list model Word2Vec( sentencessentences, vector_size128, # 每個(gè)詞映射成 128 維向量 window5, # 上下文窗口只看左右各 5 個(gè)詞 min_count1, # 詞頻小于 1 的詞丟棄小語料設(shè) 1 保留更多詞 sg1, # 1 用 Skip-gram0 用 CBOW小語料推薦 Skip-gram epochs10, # 遍歷語料 10 輪 workers4, # 并行線程數(shù) seed42 ) model.save(word2vec.model)參數(shù)里最影響效果的是min_count和sg。min_count1表示詞頻只有 1 的詞也保留這在小語料里很重要“踩雷”“避雷”這類新詞往往只出現(xiàn)幾次丟掉就只剩下“雷”一個(gè)普通詞了。sg1選 Skip-gram它在語料小時(shí)對低頻詞更友好CBOW 更像是在做“完形填空”平滑了高頻詞但對情感詞不夠敏銳。如果語料大到幾萬條以上可以試試sg0提速。vector_size128對幾千條評論是合適的中位數(shù)。少于 2000 條數(shù)據(jù)時(shí)建議降到 64詞表就幾百個(gè)維度太高會讓每個(gè)詞向量都成了稀疏隨機(jī)數(shù)SVM 反而不好擬合。window5保持默認(rèn)即可評論平均不到 30 個(gè)字窗口太大容易把無關(guān)詞拉進(jìn)上下文。訓(xùn)練完后立刻做一次直覺驗(yàn)證這一步能省下后面調(diào)參的大量時(shí)間print(model.wv.most_similar(好評, topn10)) print(model.wv.most_similar(垃圾, topn10))如果“好評”的近鄰里出現(xiàn)“質(zhì)量”“滿意”“推薦”說明共現(xiàn)關(guān)系學(xué)對了如果近鄰全是不相關(guān)的高頻詞優(yōu)先檢查分詞是否太碎而不是急著調(diào) SVM。3.3 句向量生成把一條評論的平均詞向量做成 SVM 的輸入Word2Vec 產(chǎn)出的是詞向量但 SVM 需要一條評論對應(yīng)一個(gè)固定長度的向量。最常見、最可靠的做法是平均詞向量把一條評論里所有詞的向量按維度取平均得到一個(gè) 128 維向量。樸素但足夠穩(wěn)。有個(gè)進(jìn)階做法是按 TF-IDF 權(quán)重做加權(quán)平均讓“差”“退”“貴”這類情感詞貢獻(xiàn)更大。我試過幾次提升在 1 到 2 個(gè)點(diǎn)之間可做可不做。對于現(xiàn)階段的流程普通平均已經(jīng)能讓 SVM 學(xué)到足夠多的情感信號。import numpy as np DIM 128 # 和 Word2Vec 的 vector_size 保持一致 def sentence_vector(words, model, dimDIM): vectors [] for w in words: if w in model.wv: vectors.append(model.wv[w]) if not vectors: # 整句都沒有詞命中時(shí)返回零向量后續(xù)要注意 OOV 問題 return np.zeros(dim) return np.mean(vectors, axis0) X np.array([sentence_vector(words, model) for words in data[words]]) y data[label].values print(特征矩陣形狀:, X.shape) print(標(biāo)簽分布:, np.bincount(y))np.mean(vectors, axis0)的意思是假設(shè)一條評論有 10 個(gè)詞每個(gè)詞 128 維得到 10 行 128 列的矩陣按第 0 維求平均輸出一個(gè) 128 維的句向量。axis0經(jīng)常有人寫錯(cuò)成axis1那樣得到的是 10 個(gè)數(shù)字特征維度全錯(cuò)了——遇到X.shape對不上 SVM 輸入時(shí)先查這一步。全 OOV 返回零向量的分支看起來只是個(gè)兜底實(shí)際上是個(gè)坑源。評論里如果全是表情符號或者火星文這條向量就是 128 個(gè) 0SVM 會把它當(dāng)成一個(gè)特殊聚類來處理。處理辦法后面避坑章節(jié)展開。4. 訓(xùn)練 SVM 分類器C 與 RBF 核的調(diào)參順序和效果驗(yàn)證4.1 為什么這里選 SVM小樣本、高維、無 GPU 也能跑到這一步手里是 5000 行 × 128 維的特征矩陣分類器選擇上有幾條路邏輯回歸、SVM、隨機(jī)森林、XGBoost、深度學(xué)習(xí)。我選 SVM 的原因很實(shí)際樣本量小的時(shí)候SVM 在高維空間里找最大間隔超平面比樹模型更不容易過擬合RBF 核又能處理詞向量均值后的非線性邊界而邏輯回歸在線性邊界上吃虧。隨機(jī)森林在這個(gè)任務(wù)上也不是不能用但它在高維稀疏特征上容易把噪聲當(dāng)信號尤其詞向量均值里混雜著大量弱相關(guān)的維度。神經(jīng)網(wǎng)絡(luò)在小數(shù)據(jù)集上訓(xùn)練不穩(wěn)定同樣的數(shù)據(jù)跑兩輪結(jié)果可能差好幾個(gè)點(diǎn)。SVM 的另一個(gè)好處是訓(xùn)練快5000 條樣本上網(wǎng)格搜索最多百來次擬合也就幾分鐘的事。我一般在第一版方案里直接給 SVC 配 RBF 核而不是 LinearSVC。RBF 是 SVM 的默認(rèn)選擇它把特征映射到更高維空間去找邊界落地時(shí)表現(xiàn)更穩(wěn)。前提是前面做了特征標(biāo)準(zhǔn)化不然 gamma 參數(shù)會失真。4.2 搭建訓(xùn)練集與測試集標(biāo)準(zhǔn)化這步漏了RBF 核直接翻車SVM 對特征的尺度敏感這是我踩過最深的一次坑。Word2Vec 產(chǎn)出的向量每個(gè)維度基本在 -1 到 1 附近但不同維度方差不一樣直接喂進(jìn) RBF 核gamma 參數(shù)實(shí)際起作用的范圍會漂移網(wǎng)格搜索出來的最佳 gamma 很可能只在當(dāng)前數(shù)據(jù)集上碰巧有效。標(biāo)準(zhǔn)化是必修課from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy # 按標(biāo)簽比例分層抽樣小樣本下必須加 ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)stratifyy這句的作用是保證訓(xùn)練集和測試集里的好評差評比例和原始數(shù)據(jù)一致。如果數(shù)據(jù)里好評占 80%差評占 20%隨機(jī)切分后測試集理論上還是這個(gè)比例但樣本量小時(shí)方差很大可能出現(xiàn)測試集里差評只有 5% 的情況評估結(jié)果完全失真。所以小樣本一律加stratify。fit_transform和transform的區(qū)別是標(biāo)準(zhǔn)的訓(xùn)練集上fit_transform計(jì)算均值和方差測試集上只用transform。代碼里已經(jīng)按這個(gè)寫別在測試集上重新 fit。4.3 GridSearchCV 自動(dòng)找 C 和 gamma兩個(gè)參數(shù)四個(gè)坑SVM 用 RBF 核時(shí)只需要調(diào)兩個(gè)核心參數(shù)正則化系數(shù) C 和核寬度 gamma。C 越大模型越傾向于把訓(xùn)練集每個(gè)點(diǎn)都分對容易過擬合C 越小邊界越平滑但欠擬合風(fēng)險(xiǎn)上升。gamma 控制 RBF 核的影響范圍gamma 越大樣本點(diǎn)的影響半徑越小邊界越曲折gamma 越小模型越接近線性。網(wǎng)格搜索范圍我一般這樣給from sklearn.svm import SVC from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1], } svm SVC(kernelrbf, class_weightbalanced, random_state42) grid GridSearchCV( svm, param_grid, scoringf1, # 用 f1 而不是 accuracy原因見下一節(jié) cv5, n_jobs-1, verbose1 ) grid.fit(X_train_scaled, y_train) print(最佳參數(shù):, grid.best_params_) print(交叉驗(yàn)證 f1:, grid.best_score_)這里有兩個(gè)“坑”要說清楚。第一搜索范圍是 4×4 共 16 組參數(shù)5 折交叉驗(yàn)證就是 80 次擬合數(shù)據(jù)量在幾千條時(shí)完全跑得動(dòng)但如果你把 C 和 gamma 各給了 10 個(gè)值就是 500 次擬合時(shí)間會拉長到半小時(shí)以上。我一般先粗后細(xì)第一輪 C 和 gamma 各給 4 個(gè)數(shù)量級跨度確定大致區(qū)域第二輪在最優(yōu)值附近加密。第二交叉驗(yàn)證得分和你最終期望的指標(biāo)要對齊。scoringf1會對每一折計(jì)算正類的 f1然后取均值。電商評論這個(gè)場景正類通常設(shè)成差評這樣網(wǎng)格搜索直接優(yōu)化的是“差評找得準(zhǔn)不準(zhǔn)”而不是被好評數(shù)量帶偏的準(zhǔn)確率。另一個(gè)檢查點(diǎn)如果最佳參數(shù)落在搜索范圍的邊界上比如 C100 或 gamma1 正好是最優(yōu)說明你的搜索范圍給窄了下一輪要往外擴(kuò)一個(gè)數(shù)量級重新搜。這個(gè)習(xí)慣能省很多重復(fù)實(shí)驗(yàn)的時(shí)間。4.4 評估別只看 accuracy差評的召回率才是電商命門模型訓(xùn)完先用測試集跑一遍分類報(bào)告from sklearn.metrics import classification_report, confusion_matrix y_pred grid.predict(X_test_scaled) print(classification_report(y_test, y_pred, target_names[差評, 好評])) print(confusion_matrix(y_test, y_pred))輸出的分類報(bào)告里有三列指標(biāo)需要讀懂。精確率表示預(yù)測為差評的評論里真正是差評的比例召回率表示真實(shí)差評里被模型找出來的比例f1 是兩者的調(diào)和平均。電商場景里我更看重差評的召回率——寧可把幾條好評誤判成差評讓運(yùn)營多看一眼也不能讓差評悄悄漏過去。一個(gè)漏掉的差評可能意味著一天內(nèi)持續(xù)產(chǎn)生退貨損失。有個(gè)經(jīng)驗(yàn)值供參考在 5000 條樣本、128 維詞向量這個(gè)配置下差評召回率做到 0.7 以上已經(jīng)可以交付使用低于 0.5 時(shí)優(yōu)先回去查數(shù)據(jù)預(yù)處理而不是繼續(xù)調(diào) C 和 gamma。SVM 調(diào)參對結(jié)果的提升通常在 5 個(gè)點(diǎn)左右預(yù)處理改一個(gè)否定詞表可能直接跳 10 個(gè)點(diǎn)。另外默認(rèn)的 SVC 是沒有概率輸出的。如果業(yè)務(wù)后續(xù)要接閾值過濾比如“只把置信度超過 0.8 的差評推給人工”可以給 SVC 加probabilityTrue代價(jià)是訓(xùn)練和預(yù)測速度明顯變慢。我一般建議先不加等業(yè)務(wù)真要概率了再加。5. 情感分析實(shí)戰(zhàn)避坑數(shù)據(jù)泄漏、OOV 詞與樣本不平衡5.1 詞向量在切分前訓(xùn)練會讓評估虛高現(xiàn)象交叉驗(yàn)證的 f1 到 0.9把模型部署到線上處理新評論準(zhǔn)確率掉到 0.7 以下。原因先把全部評論拿去訓(xùn) Word2Vec再切分訓(xùn)練集測試集。詞向量在訓(xùn)練階段已經(jīng)見過測試集里的詞和上下文SVM 的輸入特征里帶上了測試集的信息等于開卷考試。這不是標(biāo)簽泄漏但效果一樣——離線指標(biāo)樂觀線上現(xiàn)原形。解決嚴(yán)格按“先切分、后訓(xùn)詞向量”的順序來。代碼順序大概是# 錯(cuò)誤順序詞向量用了全量語料 sentences_all data[words].tolist() word2vec_all Word2Vec(sentences_all, ...) X_all build_X(word2vec_all) X_train, X_test train_test_split(X_all, ...) # 正確順序先切分只用訓(xùn)練集訓(xùn)詞向量 train_data, test_data train_test_split(data, ...) word2vec Word2Vec(train_data[words].tolist(), ...) X_train build_X(word2vec, train_data[words]) X_test build_X(word2vec, test_data[words])注意切分是發(fā)生在分詞之后的但發(fā)生在 Word2Vec 訓(xùn)練之前。如果你的數(shù)據(jù)量到了十萬條級別用全量無標(biāo)注語料訓(xùn)詞向量在工業(yè)上是常見做法但那是半監(jiān)督場景這時(shí)離線評估結(jié)果只能當(dāng)作上限參考不要拿去向業(yè)務(wù)方承諾線上效果。5.2 新詞和 OOV 詞返回零向量情感信息被悄悄吃掉現(xiàn)象一條明顯差評“這質(zhì)量真的是 yyds 反向種草”模型預(yù)測成了好評或者“踩雷”“避雷”這類詞出現(xiàn)時(shí)預(yù)測概率明顯偏向中性。原因yyds、踩雷、種草不在 Word2Vec 詞表里進(jìn)sentence_vector時(shí)被直接跳過如果整句里沒幾個(gè)詞命中詞表句向量就退化成少數(shù)詞的均值甚至全是零向量。SVM 拿到這樣的輸入等于把這條評論當(dāng)成一個(gè)毫無特征的樣本只能猜。解決給詞表留足空間把min_count從 2 改成 1同時(shí)把 3.2 里的自定義詞典持續(xù)追加新詞。更關(guān)鍵的是要識別否定結(jié)構(gòu)而不是只靠單個(gè)詞向量。我之前說過停用詞表別刪否定詞但光保留還不夠最好把否定詞后面的幾個(gè)詞做上標(biāo)記NEGATIVE_WORDS {不, 沒, 別, 無, 莫, 未, 難, 非} def attach_negation(words): result [] for i, w in enumerate(words): if w in NEGATIVE_WORDS: # 否定詞后 3 個(gè)詞加上 neg_ 前綴讓 Word2Vec 學(xué)到反向語義 for j in range(i 1, min(i 4, len(words))): result.append(neg_ words[j]) else: result.append(w) return result data[words] data[words].apply(attach_negation)這段代碼會把“不太行”這一串分詞結(jié)果[不, 太, 行]改成[不, neg_太, neg_行]。這樣訓(xùn)練出的neg_行向量會天然靠近“差勁”“失望”這些詞情感信號就不會被“行”這個(gè)正面詞稀釋了。注意加了neg_前綴后必須重新訓(xùn)練 Word2Vec因?yàn)樵~表變了。5.3 “默認(rèn)好評”重復(fù)評論造成的數(shù)據(jù)泄漏現(xiàn)象測試集 f1 很高但抽樣檢查時(shí)發(fā)現(xiàn)模型對“好評”兩個(gè)字的判斷接近滿分對陌生評論卻經(jīng)常出錯(cuò)。原因電商訂單系統(tǒng)里大量評論是系統(tǒng)自動(dòng)填充的“默認(rèn)好評”或者同一句模板被上千個(gè)訂單復(fù)用。隨機(jī)切分時(shí)同一句話既進(jìn)了訓(xùn)練集又進(jìn)了測試集SVM 相當(dāng)于直接背下了這句話評估時(shí)“見過”的句子太多指標(biāo)自然虛高。解決切分前先去重。最直接的是按評論文本去重data data.drop_duplicates(subset[review], keepfirst)但這里有個(gè)細(xì)節(jié)如果兩個(gè)用戶寫了一句一模一樣的真實(shí)評論比如“物流很快態(tài)度很好”按文本去重會誤刪。更穩(wěn)妥的做法是按用戶 ID 或訂單 ID 分組切分保證同一個(gè)用戶的評論不在訓(xùn)練集和測試集里同時(shí)出現(xiàn)。數(shù)據(jù)里沒有用戶 ID 的話先用文本去重再人工掃一遍高頻評論把明顯是模板填充的句子標(biāo)記出來剔除掉。5.4 好評和差評 9:1模型學(xué)會復(fù)讀現(xiàn)象模型預(yù)測結(jié)果全是好評accuracy 高達(dá) 0.9看混淆矩陣發(fā)現(xiàn)差評一個(gè)都沒抓住。原因電商評論天然不平衡好評占比常在 80% 以上。SVM 在訓(xùn)練時(shí)為了降低整體損失發(fā)現(xiàn)把多數(shù)類全部猜對就能拿到很高的分?jǐn)?shù)于是學(xué)會了“復(fù)讀”——全部輸出好評。解決兩層處理。第一層在模型上給 SVC 加class_weightbalanced讓算法自動(dòng)放大少數(shù)類的懲罰權(quán)重第二層在評估上用 f1 和差評召回率替代 accuracy 作為主要指標(biāo)。代碼層面只需要改一行svm SVC(kernelrbf, class_weightbalanced, random_state42)如果加了class_weight后差評召回率依然很低再考慮對差評樣本做輕量過采樣。注意不要直接用 SMOTE 在詞向量均值上生成合成樣本合成的向量可能會落在 SVM 邊界內(nèi)部的空白區(qū)域反而干擾分類面。更好的做法是回到文本層對差評評論做同義替換增強(qiáng)比如“不好”換成“太差”“不行”然后再重新提取向量。6. 把流程收成可復(fù)用腳本保存模型、增量更新與預(yù)測新評論前面的步驟都跑通后面臨的問題從“怎么訓(xùn)”變成“怎么用”。常見做法是把 Word2Vec、標(biāo)準(zhǔn)化器、SVM 模型三個(gè)對象分別保存再寫一個(gè)預(yù)測函數(shù)。千萬別只存詞向量文件分詞器、停用詞表、自定義詞典這些預(yù)處理資產(chǎn)不一起版本化換臺機(jī)器跑預(yù)測時(shí)你會后悔。import joblib from gensim.models import Word2Vec model.save(word2vec.model) joblib.dump(scaler, scaler.pkl) joblib.dump(grid.best_estimator_, svm.pkl) def predict_single(review: str): words cut_words(review) words attach_negation(words) vec sentence_vector(words, model, dim128) vec scaler.transform(vec.reshape(1, -1)) label svm.predict(vec)[0] return 好評 if label 1 else 差評 sample 包裝破損客服已讀不回非常失望 print(predict_single(sample))預(yù)測函數(shù)里最容易漏的是scaler.transform(vec.reshape(1, -1))這一步。訓(xùn)練時(shí)特征做了標(biāo)準(zhǔn)化預(yù)測時(shí)輸入也必須是標(biāo)準(zhǔn)化后的向量否則 SVM 拿到的特征尺度是亂的。vec.reshape(1, -1)是把一維的 128 維向量變成 1 行 128 列因?yàn)?sklearn 的transform和predict都要求二維輸入。增量更新的邏輯也要想清楚新一批人工標(biāo)注評論進(jìn)來后先用model.build_vocab(new_sentences, updateTrue)擴(kuò)展詞表再調(diào)用model.train(new_sentences, total_exampleslen(new_sentences), epochs5)做增量訓(xùn)練。但詞向量更新后所有句向量都會變所以 SVM 必須重新訓(xùn)練而不是只更新 Word2Vec。這個(gè)流程沒法完全自動(dòng)化我的習(xí)慣是每兩周做一次增量重訓(xùn)并把新出現(xiàn)的業(yè)務(wù)詞追加進(jìn)自定義詞典。驗(yàn)證方面我常用一個(gè)笨方法隨機(jī)抽 100 條新評論人工標(biāo)注后和模型預(yù)測結(jié)果比對把錯(cuò)誤案例回填到訓(xùn)練集?;靥顣r(shí)只看 10 條左右就夠了重點(diǎn)挑那些模型“差評漏報(bào)”的樣本。我之前因?yàn)橹槐4媪?kv詞向量文件而丟了分詞器和停用詞表換機(jī)器后花了半天重寫預(yù)處理腳本后來把整個(gè)預(yù)處理鏈路的配置用 JSON 存了一份再?zèng)]有翻過車。希望你也能把這套流程變成自己的標(biāo)準(zhǔn)工具箱少走這些彎路。本文還有配套的精品資源點(diǎn)擊獲取