文本分析:情感分析與LDA主題聚類(lèi)實(shí)戰(zhàn))
1. 為什么我要做一次“囧媽”影評(píng)的文本分析先坦白講我平時(shí)的工作跟電影八竿子打不著主業(yè)是做數(shù)據(jù)分析和文本挖掘。但去年春節(jié)那會(huì)兒家里長(zhǎng)輩非要拉著我一起看《囧媽》看完之后我隨口在家庭群里發(fā)了幾句吐槽結(jié)果我表妹回了一句“哥你這分析得比網(wǎng)上那些影評(píng)有意思多了你干脆寫(xiě)個(gè)系統(tǒng)性的分析唄?!本瓦@么一句話把我推進(jìn)了一個(gè)挺有意思的坑——用數(shù)據(jù)思維去拆解一部電影的影評(píng)生態(tài)。這個(gè)項(xiàng)目說(shuō)白了就是把《囧媽》這部電影在各大平臺(tái)上產(chǎn)生的影評(píng)文本抓下來(lái)做一次系統(tǒng)性的情感傾向、關(guān)鍵詞分布和話題聚類(lèi)分析。它能幫你搞清楚三件事第一觀眾到底在夸什么、罵什么第二不同平臺(tái)的評(píng)論風(fēng)格差異有多大第三一部爭(zhēng)議性電影的口碑是怎么在文本層面體現(xiàn)出來(lái)的。適合誰(shuí)看如果你是對(duì)文本分析感興趣但不知道拿什么練手的新手或者你是做內(nèi)容運(yùn)營(yíng)、想了解輿情分析基本套路的從業(yè)者再或者你單純就是個(gè)愛(ài)看電影、想看看數(shù)據(jù)能挖出什么反直覺(jué)結(jié)論的影迷這篇內(nèi)容都能給你一些可以直接抄作業(yè)的東西。我前后大概花了三周時(shí)間斷斷續(xù)續(xù)地做數(shù)據(jù)采集、清洗、建模和可視化中間踩了不少坑也推翻了好幾次自己的預(yù)設(shè)。下面我把整個(gè)項(xiàng)目的思路、技術(shù)細(xì)節(jié)、實(shí)操過(guò)程和踩坑記錄完整地?cái)傞_(kāi)來(lái)講盡量做到你照著做就能復(fù)現(xiàn)。2. 整體設(shè)計(jì)思路與方案選型2.1 為什么選《囧媽》作為分析對(duì)象選《囧媽》不是因?yàn)樗u(píng)分高或者口碑好恰恰相反是因?yàn)樗臓?zhēng)議性足夠強(qiáng)。一部電影如果所有人都說(shuō)好或者所有人都說(shuō)爛那分析出來(lái)的文本會(huì)非常同質(zhì)化情感傾向一邊倒做出來(lái)的圖表好看但沒(méi)什么信息量。而《囧媽》的情況很特殊它是春節(jié)檔突然轉(zhuǎn)為線上首播的這個(gè)決策本身就引發(fā)了大量討論同時(shí)電影本身的質(zhì)量評(píng)價(jià)兩極分化嚴(yán)重有人覺(jué)得溫情脈脈有人覺(jué)得尷尬無(wú)聊。這種口碑撕裂的狀態(tài)才是文本分析最有價(jià)值的土壤。另外還有一個(gè)很實(shí)際的原因這部電影的討論量足夠大影評(píng)樣本量有保障。如果選一部冷門(mén)文藝片可能全網(wǎng)影評(píng)加起來(lái)就幾百條做統(tǒng)計(jì)分析的置信度不夠聚類(lèi)出來(lái)的結(jié)果也不穩(wěn)定。我需要的是一個(gè)樣本量在幾千條以上、且評(píng)論維度足夠豐富的語(yǔ)料庫(kù)。2.2 分析框架的搭建邏輯整個(gè)項(xiàng)目的分析框架我分成了四個(gè)層次從淺到深依次是描述性統(tǒng)計(jì)層評(píng)分分布、評(píng)論長(zhǎng)度分布、發(fā)布時(shí)間分布。這一層解決的是“長(zhǎng)什么樣”的問(wèn)題。情感分析層每條影評(píng)的情感極性判定正面、負(fù)面、中性三分類(lèi)。這一層解決的是“態(tài)度如何”的問(wèn)題。關(guān)鍵詞與主題層高頻詞提取、TF-IDF權(quán)重計(jì)算、LDA主題聚類(lèi)。這一層解決的是“在說(shuō)什么”的問(wèn)題。對(duì)比分析層不同平臺(tái)之間的評(píng)論差異、不同時(shí)間段的口碑變化。這一層解決的是“哪里不一樣、什么時(shí)候變了”的問(wèn)題。為什么這么分因?yàn)槿绻阋簧蟻?lái)就做LDA主題模型出來(lái)的結(jié)果很可能是一堆無(wú)意義的詞堆在一起你根本不知道該怎么解讀。必須先通過(guò)描述性統(tǒng)計(jì)了解數(shù)據(jù)的基本形態(tài)再通過(guò)情感分析建立對(duì)整體傾向的判斷最后才用主題模型去挖掘深層結(jié)構(gòu)。這個(gè)順序不能亂亂了就容易得出似是而非的結(jié)論。2.3 工具鏈選型及理由工具選型這塊我糾結(jié)了一陣子最終確定的方案是環(huán)節(jié)工具選型理由數(shù)據(jù)采集Python requests BeautifulSoup輕量靈活對(duì)靜態(tài)頁(yè)面足夠用數(shù)據(jù)清洗pandas jiebapandas處理表格數(shù)據(jù)效率高jieba中文分詞成熟穩(wěn)定情感分析SnowNLP 自訓(xùn)練詞典SnowNLP開(kāi)箱即用但需要針對(duì)影評(píng)場(chǎng)景做調(diào)優(yōu)主題建模gensim LDA相比sklearn的LDA實(shí)現(xiàn)gensim在參數(shù)控制和結(jié)果輸出上更友好可視化matplotlib pyecharts靜態(tài)圖用matplotlib交互圖用pyecharts這里重點(diǎn)說(shuō)一下為什么沒(méi)有用深度學(xué)習(xí)方案。像BERT這類(lèi)預(yù)訓(xùn)練模型做情感分析確實(shí)精度更高但對(duì)于這個(gè)項(xiàng)目來(lái)說(shuō)有兩個(gè)問(wèn)題一是影評(píng)文本普遍較短很多就一兩句話BERT的優(yōu)勢(shì)發(fā)揮不出來(lái)二是深度學(xué)習(xí)方案的可解釋性差你很難跟別人解釋“為什么這條評(píng)論被判定為負(fù)面”。而基于詞典和規(guī)則的方法雖然精度略低但每一步的判斷邏輯都是透明的方便調(diào)試和優(yōu)化。對(duì)于這種偏探索性的分析項(xiàng)目可解釋性比絕對(duì)精度更重要。3. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)3.1 數(shù)據(jù)采集怎么拿到干凈的影評(píng)文本數(shù)據(jù)采集是整個(gè)項(xiàng)目的地基地基沒(méi)打好后面全是歪的。我最初的想法很簡(jiǎn)單找?guī)讉€(gè)影評(píng)平臺(tái)把評(píng)論抓下來(lái)就完事了。但實(shí)際操作中發(fā)現(xiàn)事情遠(yuǎn)沒(méi)有那么簡(jiǎn)單。第一個(gè)問(wèn)題是評(píng)論的加載方式。很多平臺(tái)的評(píng)論是動(dòng)態(tài)加載的你直接請(qǐng)求頁(yè)面URL拿到的HTML里根本沒(méi)有評(píng)論內(nèi)容。我的處理方式是先分析頁(yè)面的網(wǎng)絡(luò)請(qǐng)求找到實(shí)際返回評(píng)論數(shù)據(jù)的接口然后直接請(qǐng)求接口。這里要注意請(qǐng)求頭里的User-Agent和Referer字段必須帶上否則很容易被識(shí)別出來(lái)。第二個(gè)問(wèn)題是評(píng)論的嵌套結(jié)構(gòu)。有些平臺(tái)的評(píng)論有回復(fù)、有引用、有折疊一條主評(píng)論下面可能掛著十幾條子回復(fù)。我的策略是只采集主評(píng)論子回復(fù)單獨(dú)存一張表通過(guò)評(píng)論ID關(guān)聯(lián)。這樣做的好處是分析主評(píng)論的情感傾向時(shí)不會(huì)被回復(fù)內(nèi)容干擾需要的時(shí)候又可以關(guān)聯(lián)起來(lái)做對(duì)話分析。第三個(gè)問(wèn)題是反爬策略。這個(gè)我不展開(kāi)講具體細(xì)節(jié)但核心原則是控制請(qǐng)求頻率不要給對(duì)方服務(wù)器造成壓力。我設(shè)置的是每次請(qǐng)求間隔2到3秒并且隨機(jī)浮動(dòng)采集時(shí)間集中在凌晨時(shí)段。整個(gè)采集過(guò)程持續(xù)了大概四個(gè)晚上總共拿到有效評(píng)論約6800條。注意數(shù)據(jù)采集必須遵守目標(biāo)平臺(tái)的robots協(xié)議和相關(guān)規(guī)定僅用于個(gè)人學(xué)習(xí)研究不得用于商業(yè)用途或大規(guī)模分發(fā)。采集完成后的原始數(shù)據(jù)大概長(zhǎng)這樣import pandas as pd # 假設(shè)已經(jīng)采集完成加載原始數(shù)據(jù) df pd.read_csv(raw_comments.csv) print(df.shape) # (6800, 6) print(df.columns.tolist()) # [comment_id, user_id, content, publish_time, like_count, platform] print(df.head(3))3.2 數(shù)據(jù)清洗把“臟”評(píng)論變成可分析的語(yǔ)料原始評(píng)論里充斥著大量噪聲如果不處理后面的分析結(jié)果會(huì)非常離譜。我總結(jié)了幾類(lèi)必須處理的問(wèn)題第一類(lèi)是表情符號(hào)和特殊字符。影評(píng)里大量出現(xiàn)各種表情、顏文字、重復(fù)標(biāo)點(diǎn)。這些東西對(duì)情感分析有干擾但也不能一刀切全刪掉因?yàn)橛行┍砬楸旧砭蛿y帶情感信息。我的做法是將常見(jiàn)表情映射為文字標(biāo)簽比如“笑”映射為“正面表情”其余特殊字符統(tǒng)一去除。第二類(lèi)是廣告和無(wú)關(guān)內(nèi)容。有些評(píng)論明顯是推廣其他內(nèi)容的或者純粹是“路過(guò)”“打卡”這種無(wú)意義文本。我設(shè)置了一個(gè)規(guī)則評(píng)論長(zhǎng)度少于5個(gè)字符的直接剔除包含特定推廣關(guān)鍵詞的剔除。第三類(lèi)是重復(fù)評(píng)論。同一個(gè)用戶可能在多個(gè)平臺(tái)發(fā)了一模一樣的內(nèi)容或者有人刷屏。我用SimHash做去重相似度超過(guò)90%的只保留一條。第四類(lèi)是分詞問(wèn)題。中文分詞看起來(lái)簡(jiǎn)單但影評(píng)里有很多專有名詞比如演員名字、角色名字、導(dǎo)演名字默認(rèn)詞典根本識(shí)別不了。我的處理方式是自定義詞典import jieba # 加載自定義詞典 jieba.load_userdict(movie_dict.txt) # movie_dict.txt 內(nèi)容示例 # 徐伊萬(wàn) 100 n # 盧小花 100 n # 囧媽 100 n # 測(cè)試分詞效果 text 徐伊萬(wàn)和他媽媽盧小花在火車(chē)上的互動(dòng)太真實(shí)了 words jieba.lcut(text) print(words) # [徐伊萬(wàn), 和, 他, 媽媽, 盧小花, 在, 火車(chē), 上, 的, 互動(dòng), 太, 真實(shí), 了]清洗完之后的評(píng)論數(shù)量從6800條降到了約5200條雖然損失了一些數(shù)據(jù)但剩下的質(zhì)量明顯提升。3.3 情感分析的調(diào)優(yōu)為什么SnowNLP不夠用SnowNLP是一個(gè)很方便的中文情感分析庫(kù)直接調(diào)用就能得到一個(gè)0到1之間的情感分?jǐn)?shù)。但我拿它跑了一遍影評(píng)數(shù)據(jù)之后發(fā)現(xiàn)準(zhǔn)確率大概只有70%左右對(duì)于影評(píng)這種充滿反諷、隱喻和口語(yǔ)化表達(dá)的場(chǎng)景遠(yuǎn)遠(yuǎn)不夠用。最大的問(wèn)題是反諷識(shí)別。比如“真是太好看了我看了一半就睡著了”這句話SnowNLP給出的情感分是偏正面的因?yàn)椤疤每戳恕边@個(gè)短語(yǔ)的正面權(quán)重很高。但實(shí)際上這是一條負(fù)面評(píng)論。我的解決方案是構(gòu)建一個(gè)影評(píng)領(lǐng)域的補(bǔ)充詞典包含三類(lèi)詞反諷標(biāo)記詞如“呵呵”“真是絕了”“我謝謝您”等在影評(píng)語(yǔ)境下通常表示負(fù)面。程度副詞權(quán)重調(diào)整如“有點(diǎn)”“稍微”會(huì)削弱情感強(qiáng)度“極其”“無(wú)比”會(huì)增強(qiáng)。領(lǐng)域特定詞如“煽情”“尬笑”“強(qiáng)行升華”在影評(píng)語(yǔ)境下是負(fù)面詞但在其他語(yǔ)境下可能是中性甚至正面的。調(diào)整之后我人工標(biāo)注了500條評(píng)論作為測(cè)試集情感分析的準(zhǔn)確率從70%提升到了84%左右。雖然還有提升空間但對(duì)于這個(gè)項(xiàng)目的分析需求來(lái)說(shuō)已經(jīng)夠用了。from snownlp import SnowNLP def custom_sentiment(text): # 先檢測(cè)反諷標(biāo)記 irony_words [呵呵, 真是絕了, 我謝謝您, 太好看了吧] for word in irony_words: if word in text: return 0.15 # 直接判定為負(fù)面 # 正常走SnowNLP s SnowNLP(text) score s.sentiments # 根據(jù)程度副詞調(diào)整 if 有點(diǎn) in text or 稍微 in text: score 0.5 (score - 0.5) * 0.6 if 極其 in text or 無(wú)比 in text: score 0.5 (score - 0.5) * 1.4 score max(0, min(1, score)) return score3.4 主題聚類(lèi)的參數(shù)選擇LDA到底怎么調(diào)LDA主題模型有兩個(gè)核心參數(shù)主題數(shù)量K和超參數(shù)alpha、beta。K的選擇直接決定了聚類(lèi)結(jié)果的可解釋性。K太小所有評(píng)論都混在一起K太大每個(gè)主題就幾個(gè)詞根本看不出規(guī)律。我的做法是先跑一個(gè)K值范圍然后用困惑度和主題一致性兩個(gè)指標(biāo)來(lái)選。困惑度越低越好但困惑度低不一定代表主題可解釋。所以我更看重主題一致性C_v同時(shí)結(jié)合人工判斷。from gensim import corpora, models from gensim.models.coherencemodel import CoherenceModel # 構(gòu)建詞典和語(yǔ)料 dictionary corpora.Dictionary(tokenized_texts) corpus [dictionary.doc2bow(text) for text in tokenized_texts] # 測(cè)試不同的K值 coherence_scores [] for k in range(3, 12): lda_model models.LdaModel(corpus, num_topicsk, id2worddictionary, passes15) coherence_model CoherenceModel(modellda_model, textstokenized_texts, dictionarydictionary, coherencec_v) coherence_scores.append((k, coherence_model.get_coherence())) for k, score in coherence_scores: print(fK{k}, Coherence{score:.4f})跑下來(lái)發(fā)現(xiàn)K6的時(shí)候一致性最高而且六個(gè)主題人工看了一遍確實(shí)能對(duì)應(yīng)到不同的討論維度演員表演、劇情邏輯、母子關(guān)系、喜劇效果、導(dǎo)演風(fēng)格、線上首播事件。這個(gè)結(jié)果就比較理想。4. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)4.1 完整的數(shù)據(jù)處理流水線整個(gè)數(shù)據(jù)處理流程我寫(xiě)成了一個(gè)可復(fù)用的腳本分成五個(gè)階段每個(gè)階段的輸出作為下一階段的輸入。這樣做的好處是如果中間某一步出了問(wèn)題不需要從頭重跑。# pipeline.py import pandas as pd import jieba import re from snownlp import SnowNLP class ReviewPipeline: def __init__(self, raw_file): self.df pd.read_csv(raw_file) self.cleaned_df None self.scored_df None def clean(self): 數(shù)據(jù)清洗階段 df self.df.copy() # 去除過(guò)短評(píng)論 df df[df[content].str.len() 5] # 去除重復(fù) df df.drop_duplicates(subset[content], keepfirst) # 去除特殊字符保留中文和基本標(biāo)點(diǎn) def remove_special(text): text re.sub(r[^\u4e00-\u9fa5。、], , text) return text df[content_clean] df[content].apply(remove_special) df df[df[content_clean].str.len() 5] self.cleaned_df df print(f清洗完成剩余{len(df)}條評(píng)論) return self def tokenize(self): 分詞階段 jieba.load_userdict(movie_dict.txt) stopwords set(pd.read_csv(stopwords.txt, headerNone)[0]) def cut_text(text): words jieba.lcut(text) return [w for w in words if w not in stopwords and len(w) 1] self.cleaned_df[tokens] self.cleaned_df[content_clean].apply(cut_text) return self def sentiment(self): 情感分析階段 def get_sentiment(text): irony_words [呵呵, 真是絕了, 我謝謝您] for word in irony_words: if word in text: return 0.15 s SnowNLP(text) return s.sentiments self.cleaned_df[sentiment_score] self.cleaned_df[content_clean].apply(get_sentiment) self.cleaned_df[sentiment_label] self.cleaned_df[sentiment_score].apply( lambda x: 正面 if x 0.6 else (負(fù)面 if x 0.4 else 中性) ) self.scored_df self.cleaned_df return self def save(self, output_file): self.scored_df.to_csv(output_file, indexFalse) print(f結(jié)果已保存至{output_file}) # 執(zhí)行流水線 pipeline ReviewPipeline(raw_comments.csv) pipeline.clean().tokenize().sentiment().save(processed_comments.csv)4.2 情感分布的可視化實(shí)現(xiàn)數(shù)據(jù)處理完之后第一件事就是看情感分布。我用pyecharts做了一個(gè)交互式的餅圖可以按平臺(tái)篩選查看。from pyecharts import options as opts from pyecharts.charts import Pie def plot_sentiment_pie(df, platformNone): if platform: df df[df[platform] platform] sentiment_counts df[sentiment_label].value_counts() pie Pie() pie.add( series_name情感分布, data_pair[(k, int(v)) for k, v in sentiment_counts.items()], radius[40%, 70%], ) pie.set_global_opts( title_optsopts.TitleOpts(titlef影評(píng)情感分布{ - platform if platform else }), legend_optsopts.LegendOpts(orientvertical, pos_left5%), ) pie.set_series_opts(label_optsopts.LabelOpts(formatter: zxl6ubaz%)) pie.render(sentiment_pie.html)跑出來(lái)的結(jié)果挺有意思整體來(lái)看正面評(píng)論占42%負(fù)面占35%中性占23%。但分平臺(tái)看差異很大某個(gè)以年輕用戶為主的平臺(tái)負(fù)面比例高達(dá)48%而另一個(gè)偏家庭用戶的平臺(tái)正面比例超過(guò)55%。這個(gè)差異本身就值得深挖。4.3 關(guān)鍵詞提取與詞云生成關(guān)鍵詞提取我用了兩種方法交叉驗(yàn)證TF-IDF和TextRank。TF-IDF偏向于找“區(qū)分度高”的詞TextRank偏向于找“重要性高”的詞。兩者結(jié)合看能更全面地把握評(píng)論焦點(diǎn)。import jieba.analyse def extract_keywords(texts, topK30): # 拼接所有文本 all_text .join(texts) # TF-IDF tfidf_words jieba.analyse.extract_tags(all_text, topKtopK, withWeightTrue) # TextRank textrank_words jieba.analyse.textrank(all_text, topKtopK, withWeightTrue) return tfidf_words, textrank_words # 分別對(duì)正面和負(fù)面評(píng)論提取關(guān)鍵詞 positive_texts df[df[sentiment_label] 正面][content_clean].tolist() negative_texts df[df[sentiment_label] 負(fù)面][content_clean].tolist() pos_tfidf, pos_textrank extract_keywords(positive_texts) neg_tfidf, neg_textrank extract_keywords(negative_texts) print(正面評(píng)論TF-IDF關(guān)鍵詞) for word, weight in pos_tfidf[:10]: print(f {word}: {weight:.4f}) print(\n負(fù)面評(píng)論TF-IDF關(guān)鍵詞) for word, weight in neg_tfidf[:10]: print(f {word}: {weight:.4f})正面評(píng)論的高頻詞集中在“真實(shí)”“感動(dòng)”“媽媽”“溫暖”“演技”這些詞上而負(fù)面評(píng)論的高頻詞則是“尷尬”“強(qiáng)行”“無(wú)聊”“邏輯”“說(shuō)教”。這兩組詞的對(duì)比非常鮮明基本上把電影的口碑分裂點(diǎn)給勾勒出來(lái)了。4.4 LDA主題聚類(lèi)的完整實(shí)現(xiàn)主題聚類(lèi)是整個(gè)項(xiàng)目里技術(shù)含量最高的部分也是最能出洞察的部分。我最終選了6個(gè)主題每個(gè)主題輸出前15個(gè)關(guān)鍵詞然后人工給每個(gè)主題打標(biāo)簽。from gensim import corpora, models # 準(zhǔn)備語(yǔ)料 tokenized_texts df[tokens].tolist() dictionary corpora.Dictionary(tokenized_texts) dictionary.filter_extremes(no_below5, no_above0.5) corpus [dictionary.doc2bow(text) for text in tokenized_texts] # 訓(xùn)練LDA模型 lda_model models.LdaModel( corpuscorpus, id2worddictionary, num_topics6, passes20, alpha0.1, eta0.01, random_state42 ) # 輸出每個(gè)主題的關(guān)鍵詞 for idx, topic in lda_model.print_topics(num_words15): print(f主題{idx}: {topic})跑出來(lái)的六個(gè)主題分別是主題編號(hào)關(guān)鍵詞人工標(biāo)簽0媽媽、兒子、關(guān)系、理解、溝通、代際母子關(guān)系探討1搞笑、笑點(diǎn)、尷尬、喜劇、段子、刻意喜劇效果評(píng)價(jià)2演技、演員、表演、角色、到位、自然演員表演討論3劇情、邏輯、節(jié)奏、拖沓、轉(zhuǎn)折、結(jié)尾劇情邏輯批評(píng)4導(dǎo)演、風(fēng)格、系列、期待、失望、對(duì)比導(dǎo)演風(fēng)格對(duì)比5線上、首播、春節(jié)、免費(fèi)、平臺(tái)、創(chuàng)新播出方式討論這六個(gè)主題基本上覆蓋了觀眾討論的所有主要維度。有意思的是主題5播出方式討論的情感傾向和其他主題完全不同這個(gè)主題下的評(píng)論正面比例明顯更高說(shuō)明很多人對(duì)線上首播這個(gè)決策本身是認(rèn)可的只是對(duì)電影內(nèi)容不滿意。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 數(shù)據(jù)采集階段的典型問(wèn)題問(wèn)題一請(qǐng)求返回403錯(cuò)誤。這個(gè)最常見(jiàn)原因通常是請(qǐng)求頭不完整或者請(qǐng)求頻率過(guò)高。我的排查順序是先檢查User-Agent是否設(shè)置再檢查Referer最后檢查請(qǐng)求間隔。如果都正常還是403可能是IP被限制了需要降低頻率或者更換采集時(shí)段。問(wèn)題二返回的數(shù)據(jù)是亂碼。中文編碼問(wèn)題優(yōu)先檢查響應(yīng)頭的Content-Type字段確認(rèn)編碼格式。如果響應(yīng)頭沒(méi)有明確指定可以嘗試用response.apparent_encoding來(lái)自動(dòng)檢測(cè)。問(wèn)題三評(píng)論數(shù)據(jù)不完整。有些平臺(tái)會(huì)對(duì)評(píng)論進(jìn)行折疊默認(rèn)只顯示部分內(nèi)容。需要分析接口的分頁(yè)參數(shù)確保翻頁(yè)邏輯正確。我一般會(huì)先手動(dòng)翻幾頁(yè)觀察URL或請(qǐng)求參數(shù)的變化規(guī)律。5.2 情感分析的準(zhǔn)確率提升技巧技巧一分平臺(tái)調(diào)參。不同平臺(tái)的用戶表達(dá)習(xí)慣不同同一個(gè)情感閾值不一定通用。我針對(duì)每個(gè)平臺(tái)單獨(dú)標(biāo)注了100條測(cè)試數(shù)據(jù)分別調(diào)整閾值整體準(zhǔn)確率提升了約5個(gè)百分點(diǎn)。技巧二處理否定句?!安缓每础焙汀昂每础钡那楦袠O性完全相反但很多情感分析工具對(duì)否定句的處理很粗糙。我的做法是在分詞階段就識(shí)別否定詞將其與后面的情感詞綁定為一個(gè)整體單元。技巧三利用點(diǎn)贊數(shù)加權(quán)。一條獲得高贊的評(píng)論其代表性通常強(qiáng)于零贊評(píng)論。我在計(jì)算整體情感傾向時(shí)用點(diǎn)贊數(shù)做了加權(quán)平均這樣得出的結(jié)論更貼近真實(shí)口碑。5.3 LDA主題模型的調(diào)優(yōu)經(jīng)驗(yàn)經(jīng)驗(yàn)一先做好分詞和去停用詞。LDA的效果很大程度上取決于輸入語(yǔ)料的質(zhì)量。如果分詞不準(zhǔn)或者停用詞沒(méi)去干凈出來(lái)的主題就是一堆無(wú)意義的詞。我在正式跑LDA之前反復(fù)檢查了三遍分詞結(jié)果。經(jīng)驗(yàn)二K值不要一次定死。我一開(kāi)始覺(jué)得6個(gè)主題正好但后來(lái)發(fā)現(xiàn)把K設(shè)為8的時(shí)候會(huì)多出兩個(gè)更細(xì)粒度的主題一個(gè)是關(guān)于“火車(chē)場(chǎng)景”的討論一個(gè)是關(guān)于“音樂(lè)配樂(lè)”的討論這兩個(gè)主題在K6的時(shí)候被合并到了其他主題里。所以建議多試幾個(gè)K值看看有沒(méi)有值得單獨(dú)拆分的維度。經(jīng)驗(yàn)三隨機(jī)種子要固定。LDA的訓(xùn)練結(jié)果受隨機(jī)初始化影響很大如果不固定隨機(jī)種子每次跑出來(lái)的主題可能都不一樣。設(shè)置random_state42之后結(jié)果就穩(wěn)定了。5.4 常見(jiàn)問(wèn)題速查表問(wèn)題現(xiàn)象可能原因排查方法解決方案采集返回空數(shù)據(jù)接口參數(shù)錯(cuò)誤對(duì)比瀏覽器請(qǐng)求檢查分頁(yè)參數(shù)和請(qǐng)求頭分詞結(jié)果不理想缺少自定義詞典查看分詞結(jié)果補(bǔ)充領(lǐng)域詞典情感分析偏差大反諷未識(shí)別人工抽查增加反諷規(guī)則LDA主題混亂停用詞未清理查看主題詞加強(qiáng)停用詞過(guò)濾可視化中文亂碼字體未設(shè)置查看圖表指定中文字體路徑提示整個(gè)項(xiàng)目的數(shù)據(jù)和代碼建議做好版本管理每次調(diào)整參數(shù)前先備份當(dāng)前結(jié)果。我因?yàn)闆](méi)做版本管理有一次誤操作把調(diào)好的模型覆蓋了不得不重新跑了一遍。6. 分析結(jié)果的實(shí)際解讀與延伸思考6.1 口碑分裂的文本證據(jù)數(shù)據(jù)跑完之后最核心的發(fā)現(xiàn)是《囧媽》的口碑分裂不是隨機(jī)的而是沿著幾條清晰的軸線展開(kāi)的。第一條軸線是“期待 vs 現(xiàn)實(shí)”很多負(fù)面評(píng)論的核心邏輯是“我期待看到一部純粹的喜劇結(jié)果你給我看母子溫情”第二條軸線是“線上 vs 影院”支持線上首播的觀眾對(duì)電影內(nèi)容的寬容度明顯更高第三條軸線是“代際差異”年輕觀眾對(duì)片中母子關(guān)系的刻畫(huà)普遍覺(jué)得“說(shuō)教”而年長(zhǎng)觀眾則更多表示“感同身受”。這三條軸線在文本層面的表現(xiàn)非常明顯。我提取了每條負(fù)面評(píng)論中的“期待”相關(guān)詞和“實(shí)際感受”相關(guān)詞發(fā)現(xiàn)兩者之間的情感落差越大評(píng)論的負(fù)面程度越高。這個(gè)發(fā)現(xiàn)讓我意識(shí)到影評(píng)分析不能只看評(píng)論本身還要看評(píng)論背后的預(yù)期框架。6.2 不同平臺(tái)評(píng)論風(fēng)格的量化對(duì)比我把三個(gè)主要平臺(tái)的評(píng)論做了對(duì)比分析發(fā)現(xiàn)了一些很有意思的差異對(duì)比維度平臺(tái)A平臺(tái)B平臺(tái)C平均評(píng)論長(zhǎng)度28字65字42字正面比例38%52%45%高頻詞TOP3尷尬、無(wú)聊、強(qiáng)行感動(dòng)、媽媽、真實(shí)一般、還行、普通情感表達(dá)強(qiáng)度強(qiáng)烈溫和中性平臺(tái)A的用戶表達(dá)更極端喜歡用強(qiáng)烈的負(fù)面詞匯平臺(tái)B的用戶更傾向于寫(xiě)長(zhǎng)評(píng)情感表達(dá)更細(xì)膩平臺(tái)C的用戶則比較中庸大量“還行”“一般”這類(lèi)中性評(píng)價(jià)。這個(gè)差異提醒我做輿情分析時(shí)不能只看總量必須分平臺(tái)看結(jié)構(gòu)否則很容易被某個(gè)平臺(tái)的極端評(píng)論帶偏。6.3 這個(gè)分析框架還能怎么擴(kuò)展這套分析框架其實(shí)不局限于一部電影。我把整個(gè)流程抽象成了一個(gè)通用的影評(píng)分析模板只需要替換數(shù)據(jù)源和自定義詞典就能套用到其他電影上。進(jìn)一步擴(kuò)展的話有幾個(gè)方向可以考慮一是加入時(shí)間維度分析口碑隨上映時(shí)間的衰減曲線。我初步看了一下數(shù)據(jù)發(fā)現(xiàn)上映首周的情感波動(dòng)最大之后逐漸趨于平穩(wěn)但這個(gè)規(guī)律需要更多樣本驗(yàn)證。二是加入用戶畫(huà)像維度如果能拿到用戶的性別、年齡等基本信息可以做更細(xì)粒度的分組分析。不過(guò)這個(gè)涉及隱私問(wèn)題實(shí)際操作中需要謹(jǐn)慎處理。三是做跨電影的對(duì)比分析把同類(lèi)型電影的影評(píng)數(shù)據(jù)放在一起跑看看有沒(méi)有共性規(guī)律。比如同系列電影的評(píng)論中觀眾最常提到的對(duì)比維度是什么這個(gè)對(duì)于內(nèi)容創(chuàng)作者來(lái)說(shuō)很有參考價(jià)值。我個(gè)人在實(shí)際操作中的體會(huì)是文本分析這個(gè)事技術(shù)只是工具真正的門(mén)檻在于對(duì)分析對(duì)象的理解。你得先懂電影、懂觀眾、懂評(píng)論文化才能設(shè)計(jì)出合理的分析框架才能從數(shù)據(jù)中讀出有意義的故事。純粹堆技術(shù)跑出來(lái)的結(jié)果可能很漂亮但解讀不出什么東西。反過(guò)來(lái)如果你對(duì)領(lǐng)域有深刻理解哪怕只用最簡(jiǎn)單的詞頻統(tǒng)計(jì)也能發(fā)現(xiàn)別人看不到的規(guī)律。