NLP&ML入門:數據分析of zhihu.com

大家好。

剛剛接觸NLP和ML,用Python做了一點東西,也有了一點成果,就分享一下。

這個實驗的初衷是想做一個書上示例的重複:我想知道昵稱和性別的關係——通過昵稱來猜性別(我想不少人肯定都做過)。我選擇了知乎,因為知乎網我比較熟悉,也比較好爬(水平太差)。我發現知乎新頁面幾乎都採用了前端渲染,數據是存在一個叫react-data的屬性裡面的。這是一個JSON,直接解包即可。然後我們就很容易地獲得了用戶基本信息,還可以用同樣的方法獲得一些文章數據之類的。由於此文不是講爬蟲,這裡不作展開討論。

由於知乎(可能)存在一定的反爬機制,爬蟲的速度是非常不理想的。5個爬蟲在3台伺服器運行了大約100多個小時,爬到了80870個用戶和132385篇文章。基本屬於小數據,但我也只是做個小實驗哈?

性別和昵稱關係

用簡單的書上示例代碼和樸素貝葉斯分類器就可以獲得。分類特徵用的是:

def gender_features(word): return {last_letter: word[-1], last_second_letter: word[-2:], # first_letter: word[0] }

為什麼把第一個字去掉了呢?因為真的沒啥用。。。我不知道這個是不是。。可能也許叫。。過度訓練?

只說結論:比random guess稍微好那麼一點點。

accuracy = 0.6588993554784334Most Informative Featureslast_letter = 姐 female : male = 73.5 : 1.0last_second_letter = 小姐 female : male = 38.6 : 1.0last_letter = 娘 female : male = 34.8 : 1.0last_letter = 女 female : male = 30.7 : 1.0last_second_letter = 姑娘 female : male = 30.6 : 1.0last_letter = 麗 female : male = 25.2 : 1.0last_letter = 茜 female : male = 24.3 : 1.0last_letter = 妮 female : male = 21.7 : 1.0last_letter = 玲 female : male = 20.6 : 1.0last_letter = 瑤 female : male = 20.6 : 1.0

我們可以看到,女性的特徵是非常明顯的。我們再來看看錯誤的記錄:

correct=female guess=male name=層層c correct=female guess=male name=SoniaShen correct=male guess=female name=上善若水 correct=male guess=female name=為什麼會這樣呢 correct=female guess=male name=二十八畫生 correct=female guess=male name=Lvat2000 correct=female guess=male name=子有說 correct=female guess=male name=秭歸 correct=male guess=female name=爆穿腸 correct=female guess=male name=Zenobia Yao correct=female guess=male name=小小z correct=male guess=female name=唐公子

很多錯誤……好吧,我覺得我也猜不出來……或者說我也會猜錯?

我又試著加上了description作為特徵。這次使用了jieba分詞器,把其中出現的辭彙全部提取出來。

def gender_description_features(description): features = dict() if description: for word in list(jieba.cut(description)): if word.strip() != "": features[contains(%s) % word.strip()] = True return features

我試著運行了很多次,準確率也一直在0.6-0.7之間徘徊。看上去是真的不大行了。。。

知乎獲贊分布

我們首先要知道獲贊的分布情況。

在我獲得的數據集中,有將近一半是「無贊用戶」(當然這個比例是不準確的,因為我採用的是順藤摸瓜式爬取,人與人之間是緊密相關的)。在小於10^4贊這個比例內,積累用戶總數,與獲贊的對數幾乎是線性關係。也就是說一旦獲贊,獲贊的數目幾乎是指數級增長的

作為項目的一個小福利,我也分析了Related Users的數目,所謂Related Users就是關注和被關注之和。但我後來發現這個是不準確的。因為我爬蟲寫錯了,導致這個數字不會超過100……QAQ(有興趣的去閱讀源碼)

猜猜你有多少個贊?

贊數到底與什麼有關呢?我首先想到的是Description,就是Profile裡面的那個詳細信息。這個猜測好像非常不靠譜,但是由於我剛開始做的時候數據十分有限,所以……

還要解決的一個問題就是,如果還採用貝葉斯分類器,必須對用戶的獲贊數進行離散化處理,才可以進行分類。這裡我採用的標籤是獲贊總數取對數,再取下整。這種方案大概會產生從0開始的6到7個類別。

特徵選擇跟剛才是一致的。我們直接看結果:

accuracy = 0.308Most Informative Featurescontains(妖) = True 6 : 0 = 5431.8 : 1.0contains(餅) = True 6 : 0 = 5431.8 : 1.0contains(搜) = True 6 : 0 = 5431.8 : 1.0contains(暫停) = True 6 : 2 = 1324.1 : 1.0contains(酸奶) = True 6 : 1 = 1321.8 : 1.0contains(師兄) = True 6 : 1 = 1321.8 : 1.0contains(寫字) = True 6 : 0 = 958.5 : 1.0contains(姿勢) = True 6 : 0 = 857.6 : 1.0contains(分答) = True 6 : 3 = 804.1 : 1.0contains(悶騷) = True 6 : 0 = 776.0 : 1.0

可以看到,在高贊用戶中某些詞出現的是相當頻繁的。為什麼會是這樣的結果,我覺得可能與高贊用戶戰線的一致性vs低贊用戶的零散性有關。我們很難從低贊用戶中找到共同的特徵。

另外一方面,accuracy雖然是0.308,比random guess稍微高一點,但注意到分布是嚴重不均勻的,全猜是0,正確率可能也會高達50%!

實驗證明,上面的猜測是非常不靠譜的。

猜猜你有多少個贊?(高級版)

一些不換特徵稍加改進的方法,包括使用LinearSVC分類器,不對贊數進行強要求,而簡單的分高贊和低贊兩類,都能夠提高準確率。

僅僅改變分類器,可以獲得0.516的準確率;使用二元分法,準確率更高,接近0.7。

具體原理不作展開討論(我也不懂)。

從分析人到分析文章

對文章中出現頻率最高的辭彙進行提取,加上文章的長度,作為特徵;標籤仍然跟上面一致,採用獲贊數的對數。

def cut_analyzer(text): features = {length: int(len(text) / 100)} counter = Counter() if text: for word in list(jieba.cut(text)): if word.strip() != "": counter[word.strip()] += 1 for key in counter.most_common(15): if counter[key] < 3: break features[key] = True return features

分析結果顯示:文章長度與獲贊數有很大關係,用詞與獲贊數關係不大。

0.7410484967517752Most Informative Featureslength = 73 4 : 0 = 629.4 : 1.0length = 74 4 : 0 = 449.6 : 1.0length = 158 4 : 0 = 269.7 : 1.0length = 78 4 : 0 = 269.7 : 1.0length = 84 4 : 0 = 269.7 : 1.0length = 100 4 : 0 = 269.7 : 1.0length = 101 4 : 0 = 269.7 : 1.0length = 61 4 : 0 = 269.7 : 1.0length = 50 3 : 0 = 209.8 : 1.0length = 71 3 : 0 = 205.0 : 1.0

(這裡的length都是以100為單位的)

文章長度和獲贊數的關係到底多大呢?

上圖擬合了一條四次方曲線,從曲線中可以看到,在萬級規模的文章當中,基本是越長贊越多的……(看來本文也要寫長點)但是我們可以看到在兩萬以後,贊數發生了一次驟降。個人認為這可能是數據當中存在的某些干擾導致的。我也嘗試過使用五次方六次方曲線,但均無濟於事。

為什麼有的回答那麼(不)受歡迎?

有如下猜測:

  • 邏輯清晰,觀點鮮明(遠超本入門文討論範圍)
  • 激情(有沒有真情實感)
  • 標點使用(???)
  • 垃圾信息(廣告等)
  • 作者受到的關注

對於其中的一些猜測,我們是可以進行驗證的。

在源碼中有一個標點符號的使用(???)的實驗,但由於實驗結果not helpful,我就不把它列舉在這邊了。

我們主要關注的有兩個。一個是作者受到的關注多不多,還有一個是文章夠不夠激情。

首先我對作者總獲贊數和單篇文章做了一個關係分析。有兩個圖,前一個是30%數據,後一個是90%。至於後10%的數據,樣本太小,參考性不大。

我們可以看到,對於小贊用戶,單篇文章獲贊數與總獲贊數是密切相關的。然而,單篇文章獲贊高的,總獲贊也可能不高;由於圖二左上的空白和空白右側的密集,很多popular的文章的作者可能也就這一篇popular的文章。相反,popular的作者的每篇文章都是優秀的嗎?其實也不然,很多還是集中在下方的低贊區——他們可能只是寫了很多文章而已(或者他們的高贊文章爬蟲沒有統計到)。

至於文章內包含了多少情感,BosonNLP sentiment score提供了很多幫助。通過分詞系統產生的每一個詞的情感趨向的平方和進行累加,除以文本長度,我們就得到了情感偏離值。情感偏離值和獲贊數的關係如下:

這個分布很像鐘形曲線,但個人認為參考價值略低。我們來看看分類的一些樣本:

  • (1.299291868814027, [求個opengl公司])
  • (3.7892459802902576, [不太好賣!!!])
  • (10.274760629713104, [你是什麼樣的人,你就會遇到什麼樣的人。])
  • (12.201216876972543, [警察人數太少])
  • (12.832526582097051, [謝邀!首先,先天的性善或者性惡並不重要,重要的是社會需要懲惡揚善。其次,人的動物性決定了人的本性是趨利避害。再次,懲惡揚善是為了綜合的群體利益,這可能會傷及群體中某些個體的短期利益。])
  • (15.56526918836185, [因為王小能撒貝南時期一去不復返 今日說法從一個普法類節目敗落為一個宣傳警世類節目])
  • (15.629396733694772, [屬相相刑,近幾年雙方流年不吉,堅持幾年到2020有緣分結婚。])
  • (76.32018283200652, [畫畫將來能幹什麼啊你不會想當畫家吧,畫家都是死了才出名的(出你媽…)])
  • (84.36073472927028, [可以加QQ595972391. 提升銷量,打造爆款,引流])
  • (101.58486034804461, [數學家的美妙情懷])
  • (138.63839574453257, [都是很可愛的藍孩子啊可愛可憐沒人愛 :)])

還有一些偏離值異常高的文本,卻只有幾個字:

  • [餓]

  • [煩]

  • [簡約]

這些文本的偏離值都超過了800。

項目源碼:ultmaster/nlp-2017

參考文獻:

  • Steven Bird, Evan Klein & Edward Loper, Natural Language Processing with Python
  • Python做文本情感分析之情感極性分析

推薦閱讀:

關於神經網路參數初始化為全0的思考
自然語言處理透析希拉里和特朗普各自的「演講范兒」
《Dialogue Act Sequence Labeling using Hierarchical encoder with CRF》閱讀筆記
自然語言處理入門學習<七>HMM模型解析

TAG:自然語言處理 | 機器學習 | 知乎 |