在開始正文之前,我們先回顧一下事件背景。
10月21日,朋友圈被一篇名為《估值175億的旅遊獨角獸,是一座僵屍和水軍構成的鬼城?》的文章刷屏。文章作者小聲比比指控線上旅遊網站馬蜂窩存在點評大量造假的情況,包括從其他網站如大衆點評、攜程等抓取相關點評,及通過水軍撰寫虛拟點評。
文章吸引了包括本人在内的大量吃瓜群衆的眼球。畢竟一家估值175億的網際網路公司被這麼多實錘猛捶,十分罕見。
關于此事件相關的分析文章已經不少,但是從技術本身來分析的文章卻不多。作為一個技術宅,我還是想從自己的老本行NLP上探讨一下馬蜂窩事件中反作弊方與作弊方的技術實作方案。
分析思路
其實在AI碼農看來,馬蜂窩事件可以簡化為作弊與反作弊的問題。該事件中至少存在三方:馬蜂窩平台、抄襲水軍、小聲比比指控方。我們可以先假設馬蜂窩與小聲比比雙方均沒有主觀惡意,當然抄襲水軍是惡意作弊的。而主要問題就是如何通過人工智能技術找到作弊的點評、賬号、評論和攻略。
當然如果想系統地處理反作弊問題,需要探讨的人工智能技術比較多樣,包括NLP、時間序列分析、使用者畫像、資料挖掘與分析等。
而為了簡化讨論、抓住重點,我們主要關注其中的NLP技術,畢竟本事件處理的主要内容都是文本。
簡單梳理一下幾個争論的焦點,大緻包括:
1. 馬蜂窩是否有大量抄襲點評
2. 馬蜂窩是否有大量抄襲賬号
3. 馬蜂窩是否有大量水軍評論
4. 馬蜂窩是否有大量洗稿攻略
我們接下來就一個一個探讨。
查找水軍:文本挖掘堪稱“烘幹神器”

根據馬蜂窩官網提供的資料,馬蜂窩全站擁有超過2100萬條點評,是馬蜂窩對外展示的核心競争力之一。小聲比比聲稱:2100萬條真實點評有1800萬條是從大衆點評和攜程裡抄襲過來。而且他們的判斷标準十分嚴苛:一字不差才算抄襲,十句話有一句不同就不算抄襲。
我們可以試想一下,如果讓你實作一個程式,判斷兩個文本存在抄襲,你會怎麼辦?
從一道面試題說起
不知各位程式員在刷面試的時候有沒有遇到求“最長公共子串”的算法題?
——已知子串是在原字元串中是連續不間斷的字元串,輸入兩個字元串X、Y,求X、Y的最長公共子串。
這個面試題其實就适合我們判斷抄襲的業務場景——如果最長公共子串超過一定長度,就認為X、Y之間存在抄襲。
比如設計公式:
兩個字元串X、Y之間的相似度=最長公共子串的長度/X與Y長度的最大值
當相似度大于門檻值的時候認為文本之間存在抄襲。
這個面試題的标準答案是貪心算法(或者說動态規劃),其時間複雜度是O(n2)。它的優點很明顯:子串的判斷是完全比對的,絕對屬于實錘,判斷抄襲文本的準确率是非常高的。
然而理想很豐滿,現實很骨感。在實際應用中,我們會發現它不太好用。
首先是該算法不夠靈活,召回率低。
TIPS:召回率率與準确率的差別:
1.召回率,所有抄襲文本中被判斷為抄襲的文本所占的比例。
2.準确率,所有被判斷為抄襲的文本中真是抄襲文本所占的比例。
3.準确率與召回率往往是一對沖突,難以同時兼顧。
是以,如果作弊者在文字中添加一些無損原意的資訊或者替換一些同義詞,該算法就無法查出。如對于句子“我們這些路癡好不容易找到了飯店的西門”,我們把“飯店”變為“餐館”,把“我們”變為“俺們”,或者加入一些馬蜂窩的網址,就使得新生成的句子與原句子不完全相同。這樣就難以互相抄襲了。幸好馬蜂窩的抄襲水軍技術不行,直接大量硬抄,被這麼輕易抓住也是活該。但如果他們稍微聰明一點做一些文本處理呢?
而且,該算法的另一個缺點更為緻命:速度慢。對于2100萬條真實點評,隻有O(n2)的時間複雜度,處理起來還是挺辛苦的。
那怎麼改進呢?NLP的工程師們早就想到這個問題,并且為此專門衍生出了NLP中一個非常核心的領域——文本表示。至于什麼是文本表示,簡單的說就是不将文本視為字元串,而視為在數學上處理起來更為友善的向量。而怎麼把字元串變為向量,就是文本表示的核心問題。
最簡單的文本表示:詞袋子模型
詞袋子模型是一種非常經典的文本表示。顧名思義,它就是将字元串視為一個“裝滿字元(詞)的袋子”,袋子裡的詞語是随便擺放的。而兩個詞袋子的相似程度就以它們重合的詞及其相關分布進行判斷。
舉個例子,對于“我們這些路癡好不容易找到了飯店的西門”這句話,我們先進行分詞,将所有出現的詞儲存為一個詞表。然後依據“詞語是否出現在詞表中”可以将這句話變為[1,0,1,1,1,0,0,1,…]這樣的向量,其中向量的每個次元唯一對應着詞表中的一個詞。可見這個向量的大部分位置是0值,這種情況叫作“稀疏”。為了減少存儲空間,我們可以隻儲存非零值的位置。
表示成向量的方法有個非常大的好處是判斷相似度速度非常快,隻要計算兩個向量的餘弦值(cos)就夠了。這隻要O(n)的時間複雜度,比之前的方法快了整整一個數量級!
在實際應用中,這種方法非常常用。而且對于中等篇幅的文本詞袋子模型的效果還不錯。召回率比較高。
下圖是示範兩個英文文本通過詞袋子模型判斷相似度的例子。
但詞袋子模型的缺點也很明顯:
1.其準确率往往比較低。
2.隻統計詞語是否出現或者詞頻,會被無意義的詞彙所影響。如“這裡的豬腦、肥腸好吃”與“這裡的沙拉好吃”會被認為很相似。一個改進方式是進行文本預處理。
3.對于句子級别的短文本識别能力較弱。如對于句子“我點了牛肚、肥腸、藕片、金針菇之類,味道還不錯”,其關鍵資訊是“牛肚、肥腸、藕片、金針菇”,通過他們我們能判斷出這家店應該是火鍋、麻辣燙之類的。但這樣語義層面的資訊簡單的詞袋子模型識别不出來。它改進的方式是用上深度學習,至少要用上詞向量。
4.無法關注詞語之間的順序關系,這是詞袋子模型最大的缺點。如“武松打老虎”跟“老虎打武松”在詞袋子模型中是認為一樣的。它改進的方式是用上更複雜的深度學習,如CNN、RNN、Attention等。
文本預處理
剛才說到文本預處理技術。他們典型的方法包括:
1.去除停用詞,如“的”“是”“我”等等。
2.文字、字母、标點符号統一,比如繁體統一轉換為簡體、大寫統一轉換為小寫、标點統一轉換為半角等。其實就是準備幾個字典加幾個正規表達式就行。
3.統計詞頻與逆文檔頻率——TFIDF。不僅考慮詞語是否出現,還考慮其出現的頻率(TF)。不僅考慮這個詞在當下文本的出現的機率,還考慮出現該詞語的文檔占總文檔出現的頻率(DF)。其基本假設是如果一個詞語在不同的文檔中反複出現,那麼它對于識别該文本并不重要。如高頻詞“我們”、“那麼”之類。
基于深度學習的文本表示:詞向量
在詞袋子模型中,每個詞隻對應一個詞表向量中的某一個位置,向量其他位置為0。這種術語叫作“one-hot表示”,導緻每個詞都是孤立、離散的。而詞向量出來之後,幾乎颠覆了大家的認知——原來可以用一個稠密的短向量來表示一個詞。比如“國王”這個詞可以對應向量[0.5,0.713],“女王”這個詞可以對應向量[0.713,0.5]。至于每一次元的數值是什麼意思可以先不管,直接拿來用。
詞向量最神奇的一點是可以用簡單的向量運算表達類比關系。比如可以直接用等式“國王-男人+女人=女王”來表達“國王與男人的關系類似女王與女人的關系”。這就帶有了很強的語義資訊。
下圖是Word2vec的兩個典型的機器學習模型圖(CBOW和Skip-gram)。CBOW模型通過一個詞的上下文(N個詞)預測目前詞,而Skip-gram則是反過來,基于一個詞來預測其上下文(N個詞)。兩種不同的算法都可以得到每個詞的詞向量。
基于深度學習的文本表示:句向量
既然有了詞級别的向量表示,那也可以有句子級别的向量表示。當然最簡單的句子級别向量表示就是将句子中所有詞的詞向量加起來,也很常用。這種方法本質上也是一種詞袋子模型,因為它也沒有考慮到詞語間的順序。
那怎麼模組化句子向量呢?一種簡單的方法是通過神經網絡将輸入的詞向量經過CNN\RNN\self-attention機制得到整個句子的表示,最後用一層max pooling轉換到固定長度的向量。計算兩個句子的餘弦值(cos)作為它們的相似度。
直接用深度神經網絡算出相似度
一種更加激進的方法是直接用神經網絡模組化句子之間的相似度,句子向量都不必用。如下圖所示,在搜尋引擎的場景下,把使用者的搜尋語句(query)和搜尋引擎展示的網頁文本(document)都輸入給神經網絡。之後分别輸出query與各個document的相似度,以使用者是否點選作為标注進行模組化。得到模型後,就可以直接給任意兩句話計算相似度了。
可見,這種方法比較依賴海量的标注資料。而搜尋引擎天然具有這海量的标注資料。那如果我沒有搜尋引擎這麼多的資料怎麼辦?其實像百度這樣的搜尋引擎公司都開放了api,直接用它們訓練好的模型就是了。
打造綜合解決方案
現實的業務場景往往十分複雜,需要多種算法進行組合。對于判斷馬蜂窩點評抄襲的場景,綜合以上的介紹,我們可以形成下面的簡單方案:
1. 先用基于統計的詞袋子模型快速篩選一批相似點評
2. 再用再用字元串比對确定一批實錘
3. 把中間地帶的文本用深度學習篩選一遍,撈一批一批漏網之魚
4. 最後再用人工校驗,分析badcase,進一步優化模型……
識别使用者:文本分類看穿“忽男忽女”
馬蜂窩事件中,另一個雙方都承認的實錘是存在一批抄襲賬号。而小聲比比方面對抄襲賬号的判斷标準也比較嚴格:同時抄襲150個大衆點評賬号的才算作弊賬号。
當然這批馬蜂窩的抄襲水軍的技術的确不行,簡單的規則就可以撈出一大把。但我們仍可以試想一下,如果抄襲者聰明一些,每個機器人賬号隻抄襲幾個賬号,那如何找出他們?
其實,我們可以利用抄襲賬号的另一個實錘:性别自相沖突。如果同一個使用者的一部分點評明顯是男性,另一部分明顯是女性,就是一個自相沖突,就基本可以判斷其是抄襲賬号。
這些問題理論上還可以擴充到年齡、身份的自相沖突。這些本質上就是一個文本分類的問題。我們将從傳統方法、機器學習、深度學習的角度加以說明。
傳統方法:關鍵詞比對
關鍵詞比對是指關鍵詞與頁面中的内容進行比對。如果文本中出現了某些典型關鍵詞,就可以直接判斷該文本所屬的分類。如上圖的例子,我們可以抽出女性關鍵詞:“老公”、“男友”等。男性關鍵詞:“老婆”、“女友”等。我們将已知關鍵詞拿到文中去進行比對,就可以識别賬号評論的性别。
但這種關鍵詞比對的方法同樣存在準确率高、召回率低的問題。
機器學習方法:詞袋子模型+樸素貝葉斯/邏輯回歸/支援向量機
詞袋模型上文已提到過,是一種基于統計的将文本中的詞進行統一表示的方法。而得到這些文檔的向量表示後,可以采用樸素貝葉斯、邏輯回歸或支援向量機等機器學習的算法模型對文本加以分類,進而識别出各文本中的人物年齡、性别等資訊,進而找出沖突點及識别出賬号的真僞。
如下圖顯示了詞袋模型與支援向量機結合對郵件進行分類的過程。
采用機器學習的方法使模型的召回率有所提升,但正如前文所說,詞袋模型無法實作對文本順序的判斷,是以準确率可能不滿足要求。
傳統改進方法是進行大量的特征工程。比如增加詞語的詞性、命名實體相關特征,或者采用更好的分詞器。另一個思路是增加2gram、3gram特征。
所謂2gram、3gram就是把句子中相鄰的2個、3個詞語拼成一個大一點的詞,當成一個整體進行統計,放入詞表中。這樣至少就能識别2個、3個詞語之間的順序關系。
深度學習進行文本分類
采用基于深度學習方法的文本分類技術主要包括卷積神經網絡(CNN),循環神經網絡(RNN),注意力機制(Attention)等。自2012年深度學習技術快速發展後,尤其CNN、RNN在NLP領域獲得了廣泛應用,使得文本分類的準确率不斷提升。
如下如顯示了TextCNN的結構模型,将詞向量經過卷積層、池化層、全連接配接層後,最終得出分類結果。
盤點評論:鬧了笑話的評論都犯了哪些錯
馬蜂窩事件中關于評論的内容又有哪些可以分析的點呢?
模闆評論
如下圖,關于遊記的回複内容每一條都出現了幾千次,這樣一個有固定模闆的評論,通過詞頻統計發現。
機翻關鍵詞
如下圖,可以很明顯看到該條評論是來源于“簡明英漢詞典”,這一點的發現貌似隻能結合詞組統計和用肉眼看。
“投毒”
如下圖,為在對方平台的評論處挂上自己網站的連結。這種情況的發現類似機翻關鍵詞的尋找。
可見,傳統的要找到這些典型的抄襲評論的證據,都需要用肉眼看。而為了提高效率,可以結合統計詞頻的方法。
但其實随着大資料技術的發展,我們可以用更多的可視化技術幫助人工去尋找作弊關鍵點。一個典型的方法是繪制詞雲。其實本質上也是統計詞頻,但是通過可視化技術可以講詞頻較高的詞語、短語放大标出。這樣可以有個更加直覺的認識,形成更加專業的分析報告。
鑒别洗稿
另一個很典型的作弊現象是發現了很多攻略是洗稿作品,有專門的營銷目的。如下圖顯示了針對攻略的洗稿,将對方網站的攻略内容該改頭換面到自己的網站下。圖的右側為将原文(左側)标題和圖檔進行了篡改。
而鑒别洗稿NLP技術其實目前還是開放問題,因為這屬于長文本的相似度判斷。長文本相似與短文本相似最大的差別是長文本的資訊量更加豐富,處理起來更加困難。如句子之間的順序、段落間的謀篇布局、篇章整體的主題等等,都遠比句子級别的資訊更複雜。
這裡提供一個簡單的綜合解決方案:
1.先在詞語級别抽取資訊:用基于統計的詞袋子模型快速篩選一批相似攻略。這個方法的好處是速度快、召回率高,但準确率低。這在面對海量文章進行判斷時比較有用,把絕大部分明顯不是抄襲的攻略都過濾掉。
2.再在句子級别抽取資訊:采用字元串比對判斷是否存在數個以上的句子完全相同。這是洗稿文章典型特征。而這種方法準确率高,但召回率低。而且特别容易被洗稿團隊繞過。
3.這之後可以把中間地帶的文本拆成句子用深度學習篩選一遍,撈一批漏網之魚
4.另外,也可以參考篇章級别抽取資訊。這裡涉及到的NLP技術包括情感傾向分析與主題模型。
5.最後再用人工校驗,分析badcase,進一步優化政策……
主題模型:篇章資訊的提取利器
這裡着重提一下主題模型,它是一種根據文本抽取其主題相關的資訊技術,其核心算法是機率圖生成模型,典型的算法是LDA。雖然現在深度學習這麼火,但還有一種算法分析架構在NLP領域非常重要,就是機率圖模型。機率圖的重要一類是有向圖,其基本思路就是将問題抽象出不同的狀态,狀态之間存在符合一定分布的轉移機率。機率圖的目的就是求出關鍵的轉移機率來分析問題。下圖就是LDA算法的機率圖。
好吧,這個圖太抽象了,想要解釋清楚會比較複雜。這裡用一個簡單的例子說明一下。比如我們想抽取汪峰的每首歌詞的三個主題資訊的分布,我們姑且将它們命名為“情感、實物、行動”(嚴格來說LDA隻能找出三個主題的分布,并知道這三個主題是什麼意思,本質上是一種軟性聚類。)。
不同的歌詞的主題分布是不一樣的,比如有些歌是“情感”相關的主題比例更多一些,有些歌是“行動”相關的主題更多。主題模型的目的就是得到任何一篇歌詞的主題分布,提取其篇章層面資訊。
而LDA的基本假設是存在一個先驗分布(狄利克雷分布)其能夠産生各首歌的主題分布(多項分布)。而每個主題又能夠産生該主題下的每個詞語的分布(多項式分布)。最終得到每個歌詞裡所有詞的分布。這個假設比較符合人們對于主題的機率意義了解,符合文本充詞語是離散分布的特點。是以LDA在實際的應用中效果也比較好。
原文釋出時間為:2018-11-18本文作者:文摘菌本文來自雲栖社群合作夥伴“
大資料文摘”,了解相關資訊可以關注“
”。