1. 程式人生 > >基於SNS的文字資料探勘

基於SNS的文字資料探勘

今年上半年,我在人人網實習了一段時間,期間得到了很多寶貴的資料,並做了一些還算有意義的事情,在這裡和大家一塊兒分享。感謝人人網提供的資料與工作環境,感謝趙繼承博士、詹衛東老師的支援和建議。在這項工作中,我得到了很多與眾人交流的機會,特別感謝 OpenParty 、 TEDxBeijing 提供的平臺。本文已發表在了《程式設計師》雜誌,分上下兩部分刊於 2012 年 7 月刊和 8 月刊,在此感謝盧鶇翔編輯的辛勤工作。由於眾所周知的原因,《程式設計師》刊出的文章被和諧過(看到後面大家就自動地知道被和諧的內容是什麼了),因而我決定把完整版發在 Blog 上,同時與更多的人一同分享。對此感興趣的朋友可以給我發郵件繼續交流。好了,開始說正文吧。

    作為中文系應用語言學專業的學生以及一名數學 Geek ,我非常熱衷於用計算的方法去分析漢語資料。漢語是一種獨特而神奇的語言。對漢語資料進行自然語言處理時,我們會遇到很多其他語言不會有的困難,比如分詞——漢語的詞與詞之間沒有空格,那計算機怎麼才知道,“已結婚的和尚未結婚的青年都要實行計劃生育”究竟說的是“已/結婚/的/和/尚未/結婚/的/青年”,還是“已/結婚/的/和尚/未/結婚/的/青年”呢?這就是所謂的分詞歧義難題。不過,現在很多語言模型已經能比較漂亮地解決這一問題了。但在中文分詞領域裡,還有一個比分詞歧義更令人頭疼的東西——未登入詞。中文沒有首字母大寫,專名號也被取消了,這叫計算機如何辨認人名地名之類的東西?更慘的則是機構名、品牌名、專業名詞、縮略語、網路新詞等等,它們的產生機制似乎完全無規律可尋。最近十年來,中文分詞領域都在集中攻克這一難關。自動發現新詞成為了關鍵的環節。

    挖掘新詞的傳統方法是,先對文字進行分詞,然後猜測未能成功匹配的剩餘片段就是新詞。這似乎陷入了一個怪圈:分詞的準確性本身就依賴於詞庫的完整性,如果詞庫中根本沒有新詞,我們又怎麼能信任分詞結果呢?此時,一種大膽的想法是,首先不依賴於任何已有的詞庫,僅僅根據詞的共同特徵,將一段大規模語料中可能成詞的文字片段全部提取出來,不管它是新詞還是舊詞。然後,再把所有抽出來的詞和已有詞庫進行比較,不就能找出新詞了嗎?有了抽詞演算法後,我們還能以詞為單位做更多有趣的資料探勘工作。這裡,我所選用的語料是人人網 2011 年 12 月前半個月部分使用者的狀態。非常感謝人人網提供這份極具價值的網路語料。


 
 
    要想從一段文字中抽出詞來,我們的第一個問題就是,怎樣的文字片段才算一個詞?大家想到的第一個標準或許是,看這個文字片段出現的次數是否足夠多。我們可以把所有出現頻數超過某個閾值的片段提取出來,作為該語料中的詞彙輸出。不過,光是出現頻數高還不夠,一個經常出現的文字片段有可能不是一個詞,而是多個詞構成的片語。在人人網使用者狀態中,“的電影”出現了 389 次,“電影院”只出現了 175 次,然而我們卻更傾向於把“電影院”當作一個詞,因為直覺上看,“電影”和“院”凝固得更緊一些。

    為了證明“電影院”一詞的內部凝固程度確實很高,我們可以計算一下,如果“電影”和“院”真的是各自獨立地在文字中隨機出現,它倆正好拼到一起的概率會有多小。在整個 2400 萬字的資料中,“電影”一共出現了 2774 次,出現的概率約為 0.000113 。“院”字則出現了 4797 次,出現的概率約為 0.0001969 。如果兩者之間真的毫無關係,它們恰好拼在了一起的概率就應該是 0.000113 × 0.0001969 ,約為 2.223 × 10-8 次方。但事實上,“電影院”在語料中一共出現了 175 次,出現概率約為 7.183 × 10-6 次方,是預測值的 300 多倍。類似地,統計可得“的”字的出現概率約為 0.0166 ,因而“的”和“電影”隨機組合到了一起的理論概率值為 0.0166 × 0.000113 ,約為 1.875 × 10-6 ,這與“的電影”出現的真實概率很接近——真實概率約為 1.6 × 10-5 次方,是預測值的 8.5 倍。計算結果表明,“電影院”更可能是一個有意義的搭配,而“的電影”則更像是“的”和“電影”這兩個成分偶然拼到一起的。

    當然,作為一個無知識庫的抽詞程式,我們並不知道“電影院”是“電影”加“院”得來的,也並不知道“的電影”是“的”加上“電影”得來的。錯誤的切分方法會過高地估計該片段的凝合程度。如果我們把“電影院”看作是“電”加“影院”所得,由此得到的凝合程度會更高一些。因此,為了算出一個文字片段的凝合程度,我們需要列舉它的凝合方式——這個文字片段是由哪兩部分組合而來的。令 p(x) 為文字片段 x 在整個語料中出現的概率,那麼我們定義“電影院”的凝合程度就是 p(電影院) 與 p(電) · p(影院) 比值和 p(電影院) 與 p(電影) · p(院) 的比值中的較小值,“的電影”的凝合程度則是 p(的電影) 分別除以 p(的) · p(電影) 和 p(的電) · p(影) 所得的商的較小值。

    可以想到,凝合程度最高的文字片段就是諸如“蝙蝠”、“蜘蛛”、“彷徨”、“忐忑”、“玫瑰”之類的詞了,這些詞裡的每一個字幾乎總是會和另一個字同時出現,從不在其他場合中使用。

 
    光看文字片段內部的凝合程度還不夠,我們還需要從整體來看它在外部的表現。考慮“被子”和“輩子”這兩個片段。我們可以說“買被子”、“蓋被子”、“進被子”、“好被子”、“這被子”等等,在“被子”前面加各種字;但“輩子”的用法卻非常固定,除了“一輩子”、“這輩子”、“上輩子”、“下輩子”,基本上“輩子”前面不能加別的字了。“輩子”這個文字片段左邊可以出現的字太有限,以至於直覺上我們可能會認為,“輩子”並不單獨成詞,真正成詞的其實是“一輩子”、“這輩子”之類的整體。可見,文字片段的自由運用程度也是判斷它是否成詞的重要標準。如果一個文字片段能夠算作一個詞的話,它應該能夠靈活地出現在各種不同的環境中,具有非常豐富的左鄰字集合和右鄰字集合。

    “資訊熵”是一個非常神奇的概念,它能夠反映知道一個事件的結果後平均會給你帶來多大的資訊量。如果某個結果的發生概率為 p ,當你知道它確實發生了,你得到的資訊量就被定義為 - log(p) 。 p 越小,你得到的資訊量就越大。如果一顆骰子的六個面分別是 1 、 1 、 1 、 2 、 2 、 3 ,那麼你知道了投擲的結果是 1 時可能並不會那麼吃驚,它給你帶來的資訊量是 - log(1/2) ,約為 0.693 。知道投擲結果是 2 ,給你帶來的資訊量則是 - log(1/3) ≈ 1.0986 。知道投擲結果是 3 ,給你帶來的資訊量則有 - log(1/6) ≈ 1.79 。但是,你只有 1/2 的機會得到 0.693 的資訊量,只有 1/3 的機會得到 1.0986 的資訊量,只有 1/6 的機會得到 1.79 的資訊量,因而平均情況下你會得到 0.693/2 + 1.0986/3 + 1.79/6 ≈ 1.0114 的資訊量。這個 1.0114 就是那顆骰子的資訊熵。現在,假如某顆骰子有 100 個面,其中 99 個面都是 1 ,只有一個面上寫的 2 。知道骰子的拋擲結果是 2 會給你帶來一個巨大無比的資訊量,它等於 - log(1/100) ,約為 4.605 ;但你只有百分之一的概率獲取到這麼大的資訊量,其他情況下你只能得到 - log(99/100) ≈ 0.01005 的資訊量。平均情況下,你只能獲得 0.056 的資訊量,這就是這顆骰子的資訊熵。再考慮一個最極端的情況:如果一顆骰子的六個面都是 1 ,投擲它不會給你帶來任何資訊,它的資訊熵為 - log(1) = 0 。什麼時候資訊熵會更大呢?換句話說,發生了怎樣的事件之後,你最想問一下它的結果如何?直覺上看,當然就是那些結果最不確定的事件。沒錯,資訊熵直觀地反映了一個事件的結果有多麼的隨機。

    我們用資訊熵來衡量一個文字片段的左鄰字集合和右鄰字集合有多隨機。考慮這麼一句話“吃葡萄不吐葡萄皮不吃葡萄倒吐葡萄皮”,“葡萄”一詞出現了四次,其中左鄰字分別為 {吃, 吐, 吃, 吐} ,右鄰字分別為 {不, 皮, 倒, 皮} 。根據公式,“葡萄”一詞的左鄰字的資訊熵為 - (1/2) · log(1/2) - (1/2) · log(1/2) ≈ 0.693 ,它的右鄰字的資訊熵則為 - (1/2) · log(1/2) - (1/4) · log(1/4) - (1/4) · log(1/4) ≈ 1.04 。可見,在這個句子中,“葡萄”一詞的右鄰字更加豐富一些。

    在人人網使用者狀態中,“被子”一詞一共出現了 956 次,“輩子”一詞一共出現了 2330 次,兩者的右鄰字集合的資訊熵分別為 3.87404 和 4.11644 ,數值上非常接近。但“被子”的左鄰字用例非常豐富:用得最多的是“晒被子”,它一共出現了 162 次;其次是“的被子”,出現了 85 次;接下來分別是“條被子”、“在被子”、“床被子”,分別出現了 69 次、 64 次和 52 次;當然,還有“疊被子”、“蓋被子”、“加被子”、“新被子”、“掀被子”、“收被子”、“薄被子”、“踢被子”、“搶被子”等 100 多種不同的用法構成的長尾⋯⋯所有左鄰字的資訊熵為 3.67453 。但“輩子”的左鄰字就很可憐了, 2330 個“輩子”中有 1276 個是“一輩子”,有 596 個“這輩子”,有 235 個“下輩子”,有 149 個“上輩子”,有 32 個“半輩子”,有 10 個“八輩子”,有 7 個“幾輩子”,有 6 個“哪輩子”,以及“n 輩子”、“兩輩子”等 13 種更罕見的用法。所有左鄰字的資訊熵僅為 1.25963 。因而,“輩子”能否成詞,明顯就有爭議了。“下子”則是更典型的例子, 310 個“下子”的用例中有 294 個出自“一下子”, 5 個出自“兩下子”, 5 個出自“這下子”,其餘的都是隻出現過一次的罕見用法。事實上,“下子”的左鄰字資訊熵僅為 0.294421 ,我們不應該把它看作一個能靈活運用的詞。當然,一些文字片段的左鄰字沒啥問題,右鄰字用例卻非常貧乏,例如“交響”、“後遺”、“鵝卵”等,把它們看作單獨的詞似乎也不太合適。我們不妨就把一個文字片段的自由運用程度定義為它的左鄰字資訊熵和右鄰字資訊熵中的較小值。

 
    在實際運用中你會發現,文字片段的凝固程度和自由程度,兩種判斷標準缺一不可。只看凝固程度的話,程式會找出“巧克”、“俄羅”、“顏六色”、“柴可夫”等實際上是“半個詞”的片段;只看自由程度的話,程式則會把“吃了一頓”、“看了一遍”、“睡了一晚”、“去了一趟”中的“了一”提取出來,因為它的左右鄰字都太豐富了。

 
 
    我們把文字中出現過的所有長度不超過 d 的子串都當作潛在的詞(即候選詞,其中 d 為自己設定的候選詞長度上限,我設定的值為 5 ),再為出現頻數、凝固程度和自由程度各設定一個閾值,然後只需要提取出所有滿足閾值要求的候選詞即可。為了提高效率,我們可以把語料全文視作一整個字串,並對該字串的所有後綴按字典序排序。下表就是對“四是四十是十十四是十四四十是四十”的所有後綴進行排序後的結果。實際上我們只需要在記憶體中儲存這些字尾的前 d + 1 個字,或者更好地,只儲存它們在語料中的起始位置。


十十四是十四四十是四十
十是十十四是十四四十是四十
十是四十
十四是十四四十是四十
十四四十是四十
是十十四是十四四十是四十
是十四四十是四十
是四十
是四十是十十四是十四四十是四十
四十
四十是十十四是十四四十是四十
四十是四十
四是十四四十是四十
四是四十是十十四是十四四十是四十
四四十是四十

    這樣的話,相同的候選詞便都集中在了一起,從頭到尾掃描一遍便能算出各個候選詞的頻數和右鄰字資訊熵。將整個語料逆序後重新排列所有的字尾,再掃描一遍後便能統計出每個候選詞的左鄰字資訊熵。另外,有了頻數資訊後,凝固程度也都很好計算了。這樣,我們便得到了一個無需任何知識庫的抽詞演算法,輸入一段充分長的文字,這個演算法能以大致 O(n · logn) 的效率提取出可能的詞來。

 
    對不同的語料進行抽詞,並且按這些詞的頻數從高到低排序。你會發現,不同文字的用詞特徵是非常明顯的。下面是對《西遊記》上冊的抽詞結果:

行者、師父、三藏、八戒、大聖、菩薩、悟空、怎麼、和尚、唐僧、老孫、潰骸、什麼、沙僧、太宗、徒弟、袈裟、妖精、玉帝、今日、兄弟、公主、玄奘、陛下、寶貝、性命、曉得、門外、妖魔、光蕊、觀音、花果山、土地、木叉、東土、變化、變做、伯欽、判官、多少、真君、齊天大聖、蟠桃、丞相、魏徵、扯住、潰骸澳、擡頭、揭諦、言語、豬八戒、兵器、吩咐、安排、叩頭、清風、哪吒、左右、美猴王、釘鈀、孩兒、女婿、金箍棒、二郎、東西、許多、奈何、人蔘果、收拾、近前、太保、明月、南海、水簾洞、門首、弼馬溫、李天王⋯⋯

    《資本論》全文:

商品、形式、貨幣、我們、過程、自己、機器、社會、部分、表現、沒有、流通、需要、增加、已經、交換、關係、先令、積累、必須、英國、條件、發展、麻布、兒童、進行、提高、消費、減少、任何、手段、職能、土地、特殊、實際、完全、平均、直接、隨著、簡單、規律、市場、增長、上衣、決定、什麼、制度、最後、支付、許多、雖然、棉紗、形態、棉花、法律、絕對、提供、擴大、獨立、世紀、性質、假定、每天、包含、物質、家庭、規模、考察、剝削、經濟學、甚至、延長、財富、紡紗、購買、開始、代替、便士、怎樣、降低、能夠、原料、等價物⋯⋯

    《聖經》全文:

以色列、沒有、自己、一切、面前、大衛、知道、什麼、猶大、祭司、摩西、看見、百姓、吩咐、埃及、聽見、弟兄、告訴、基督、已經、先知、掃羅、父親、雅各、永遠、攻擊、智慧、榮耀、臨到、潔淨、離開、怎樣、平安、律法、支派、許多、門徒、打發、好像、仇敵、原文作、名叫、巴比倫、今日、首領、曠野、所羅門、約瑟、兩個、燔祭、法老、衣服、脫離、二十、公義、審判、十二、亞伯拉罕、石頭、聚集、按著、禱告、罪孽、約書亞、事奉、指著、城邑、進入、彼此、建造、保羅、應當、摩押、聖靈、懼怕、應許、如今、幫助、牲畜⋯⋯

    《時間簡史》全文:

黑洞、必須、非常、任何、膨脹、科學、預言、太陽、觀察、定律、運動、事件、奇點、坍縮、問題、模型、方向、區域、知道、開始、輻射、部分、牛頓、產生、夸克、無限、軌道、解釋、邊界、甚至、自己、類似、描述、最終、旋轉、愛因斯坦、繞著、什麼、效應、表明、溫度、研究、收縮、吸引、按照、完全、增加、開端、基本、計算、結構、上帝、進行、已經、發展、幾乎、仍然、足夠、影響、初始、科學家、事件視界、第二、改變、歷史、世界、包含、準確、證明、導致、需要、應該、至少、剛好、提供、通過、似乎、繼續、實驗、複雜、伽利略⋯⋯

    哦,對了,還有我最喜歡的,《人民日報》 2000 年 4 月新聞版的抽詞結果:

發展、我們、經濟、主席、江澤民、領導、建設、關係、教育、幹部、企業、問題、主義、政治、群眾、改革、政府、思想、加強、臺灣、地區、北京、總統、世界、記者、代表、民族、組織、歷史、訪問、原則、努力、管理、今天、技術、市場、世紀、堅持、社會主義、財政、江澤民主席、增長、積極、精神、同志、雙方、自己、友好、領導幹部、進一步、基礎、提高、必須、不斷、制度、政策、解決、取得、表示、活動、支援、通過、研究、沒有、學習、穩定、舉行、歡迎、農村、生活、促進、科技、投資、科學、環境、領域、公司、情況、充分⋯⋯

    當然,我也沒有忘記對人人網使用者狀態進行分析——人人網使用者狀態中最常出現的詞是:

哈哈、什麼、今天、怎麼、現在、可以、知道、喜歡、終於、這樣、覺得、因為、如果、感覺、開始、回家、考試、老師、幸福、朋友、時間、發現、東西、快樂、為什麼、睡覺、生活、已經、希望、最後、各種、狀態、世界、突然、手機、其實、那些、同學、孩子、尼瑪、木有、然後、以後、學校、所以、青年、晚安、原來、電話、加油、果然、學習、中國、最近、應該、需要、居然、事情、永遠、特別、北京、他媽、傷不起、必須、呵呵、月亮、畢業、問題、謝謝、英語、生日快樂、工作、雖然、討厭、給力、容易、上課、作業、今晚、繼續、努力、有木有、記得⋯⋯

    事實上,程式從人人網的狀態資料中一共抽出了大約 1200 個詞,裡面大多數詞也確實都是標準的現代漢語詞彙。不過別忘了,我們的目標是新詞抽取。將所有抽出來的詞與已有詞庫作對比,於是得到了人人網特有的詞彙(同樣按頻數從高到低排序):

尼瑪、傷不起、給力、有木有、掛科、坑爹、神馬、淡定、老爸、臥槽、牛逼、腫麼、苦逼、無語、微博、六級、高數、選課、悲催、基友、蛋疼、很久、人人網、情何以堪、童鞋、哇咔咔、腦殘、吐槽、猥瑣、奶茶、我勒個去、刷屏、妹紙、胃疼、飄過、考研、弱爆了、太準了、搞基、忽悠、羨慕嫉妒恨、手賤、柯南、狗血、秒殺、裝逼、真特麼、碎覺、奧特曼、內牛滿面、鬥地主、騰訊、灰常、偶遇、拉拉、屌絲、九把刀、高富帥、阿內爾卡、魔獸世界、線代、三國殺、林俊杰、速速、臭美、花痴⋯⋯

 
    我還想到了更有意思的玩法。為什麼不拿每一天狀態裡的詞去和前一天的狀態作對比,從而提取出這一天裡特有的詞呢?這樣一來,我們就能從人人網的使用者狀態中提取出每日熱點了!從手裡的資料規模看,這是完全有可能的。我選了 12 個比較具有代表性的詞,並列出了它們在 2011 年 12 月 13 日的使用者狀態中出現的頻數(左列的數),以及 2011 年 12 月 14 日的使用者狀態中出現的頻數(右列的數):

下雪 33 92
那些年 139 146
李宇春 1 4
看見 145 695
魔獸 23 20
高數 82 83
生日快樂 235 210
今天 1416 1562
北半球 2 18
脖子 23 69
悲傷 61 33
電磁爐 0 3

    大家可以從直覺上迅速判斷出,哪些詞可以算作是 12 月 14 日的熱詞。比方說,“下雪”一詞在 12 月 13 日只出現了 33 次,在 12 月 14 日卻出現了 92 次,後者是前者的 2.8 倍,這不大可能是巧合,初步判斷一定是 12 月 14 日真的有什麼地方下雪了。“那些年”在 12 月 14 日的頻數確實比 12 月 13 日更多,但相差並不大,我們沒有理由認為它是當日的一個熱詞。

    一個問題擺在了我們面前:我們如何去量化一個詞的“當日熱度”?第一想法當然是簡單地看一看每個詞的當日頻數和昨日頻數之間的倍數關係,不過細想一下你就發現問題了:它不能解決樣本過少帶來的偶然性。 12 月 14 日“李宇春”一詞的出現頻數是 12 月 13 日的 4 倍,這超過了“下雪”一詞的 2.8 倍,但我們卻更願意相信“李宇春”的現象只是一個偶然。更麻煩的則是“電磁爐”一行, 12 月 14 日的頻數是 12 月 13 日的無窮多倍,但顯然我們也不能因此就認為“電磁爐”是 12 月 14 日最熱的詞。

    忽略所有樣本過少的詞?這似乎也不太好,樣本少的詞也有可能真的是熱詞。比如“北半球”一詞,雖然它在兩天裡的頻數都很少,但這個 9 倍的關係確實不容忽視。事實上,人眼很容易看出哪些詞真的是 12 月 14 日的熱詞:除了“下雪”以外,“看見”、“北半球”和“脖子”也應該是熱詞。你或許堅信後三個詞異峰突起的背後一定有什麼原因(並且迫切地想知道這個原因究竟是什麼),但卻會果斷地把“李宇春”和“電磁爐”這兩個“異常”歸結為偶然原因。你的直覺是對的—— 2011 年 12 月 14 日發生了極其壯觀的雙子座流星雨,此乃北半球三大流星雨之一。白天網友們不斷轉發新聞,因而“北半球”一詞熱了起來;晚上網友們不斷髮訊息說“看見了”、“又看見了”,“看見”一詞的出現頻數猛增;最後呢,仰望天空一晚上,脖子終於出毛病了,於是回家路上一個勁兒地發“脖子難受”。

    讓計算機也能聰明地排除偶然因素,這是我們在資料探勘過程中經常遇到的問題。我們經常需要對樣本過少的專案進行“平滑”操作,以避免分母過小帶來的奇點。這裡,我採用的是一個非常容易理解的方法:一個詞的樣本太少,就給這個詞的熱度打折扣。為了便於說明,我們選出四個詞為例來分析。

    下表截取了前四個詞,右邊四列分別表示各詞在 12 月 13 日出現的頻數,在 12 月 14 日出現的頻數,在兩天裡一共出現的總頻數,以及後一天的頻數所佔的比重。第三列數字是前兩列數字之和,第四列數字則是第二列數字除以第三列數字的結果。最後一列應該是一個 0 到 1 之間的數,它表明對應的詞有多大概率出現在了 12 月 14 日這一天。最後一列可以看作是各詞的得分。可以看到,此時“下雪”的得分低於“李宇春”,這是我們不希望看到的結果。“李宇春”的樣本太少,我們想以此為緣由把它的得分拖下去。

下雪 33 92 125 0.736
那些年 139 146 285 0.512
李宇春 1 4 5 0.8
看見 145 695 840 0.827
(平均) 313.75 0.719

    怎麼做呢?我們把每個詞的得分都和全域性平均分取一個加權平均!首先計算出這四個詞的平均總頻數,為 313.75 ;再計算出這四個詞的平均得分,為 0.719 。接下來,我們假設已經有 313.75 個人預先給每個詞都打了 0.719 分,換句話說每個詞都已經收到了 313.75 次評分,並且所有這 313.75 個評分都是 0.719 分。“下雪”這個詞則還有額外的 125 個人評分,其中每個人都給了 0.736 分。因此,“下雪”一詞的最終得分就是:

下雪 (0.736 × 125 + 0.719 × 313.75) / (125 + 313.75) ≈ 0.724

    類似地,其他幾個詞的得分依次為:

那些年 (0.512 × 285 + 0.719 × 313.75) / (285 + 313.75) ≈ 0.62
李宇春 (0.8 × 5 + 0.719 × 313.75) / (5 + 313.75) ≈ 0.7202
看見 (0.827 × 840 + 0.719 × 313.75) / (840 + 313.75) ≈ 0.798

    容易看出,此時樣本越大的詞,就越有能力把最終得分拉向自己本來的得分,樣本太小的詞,最終得分將會與全域性平均分非常接近。經過這麼一番調整,“下雪”一詞的得分便高於了“李宇春”。實際運用中, 313.75 這個數也可以由你自己來定,定得越高就表明你越在意樣本過少帶來的負面影響。這種與全域性平均取加權平均的思想叫做 Bayesian average ,從上面的若干式子裡很容易看出,它實際上是最常見的平滑處理方法之一——分子分母都加上一個常數——的一種特殊形式。

    利用之前的抽詞程式抽取出人人網每一天內使用者狀態所含的詞,把它們的頻數都與前一天的作對比,再利用剛才的方法加以平滑,便能得出每一天的熱詞了。我手上的資料是人人網 2011 年 12 月上半月的資料,因此我可以得出從 12 月 2 日到 12 月 15 日的熱詞(選取每日前 5 名,按得分從高到低)。

2011-12-02:第一場雪、北京、金隅、週末、新疆
2011-12-03:荷蘭、葡萄牙、死亡之組、歐洲盃、德國
2011-12-04:那些年、宣傳、期末、男朋友、升旗
2011-12-05:教室、老師、視帝、體育課、質量
2011-12-06:喬爾、星期二、攝影、經濟、音樂
2011-12-07:陳超、星巴克、優秀、童鞋、投票
2011-12-08:曼聯、曼城、歐聯杯、皇馬、凍死
2011-12-09:保羅、月全食、交易、火箭、黃蜂
2011-12-10:變身、羅伊、穿越、皇馬、巴薩
2011-12-11:皇馬、巴薩、卡卡、梅西、下半場
2011-12-12:淘寶、阿內爾卡、雙十二、申花、老師
2011-12-13:南京、南京大屠殺、勿忘國恥、默哀、警報
2011-12-14:流星雨、許願、願望、情人節、幾顆
2011-12-15:快船、保羅、巴薩、昨晚、龍門飛甲

    看來, 12 月 14 日果然有流星雨發生。

    注意,由於我們僅僅對比了相鄰兩天的狀態,因而產生了個別實際上是由工作日/休息日的區別造成的“熱詞”,比如“教室”、“老師”、“星期二”等。把這樣的詞當作熱詞可能並不太妥。結合上週同日的資料,或者乾脆直接與之前整個一週的資料來對比,或許可以部分地解決這一問題。

    事實上,有了上述工具,我們可以任意比較兩段不同文字中的用詞特點。更有趣的是,人人網狀態的大多數釋出者都填寫了性別和年齡的個人資訊,我們為何不把狀態重新分成男性和女性兩組,或者 80 後和 90 後兩組,挖掘出不同屬性的人都愛說什麼?要知道,在過去,這樣的問題需要進行大規模語言統計調查才能回答!然而,在網際網路海量使用者生成內容的支援下,我們可以輕而易舉地挖掘出答案來。

    我真的做了這個工作(基於另一段日期內的資料)。男性愛說的詞有:

兄弟、籃球、男籃、米蘭、曼聯、足球、蛋疼、皇馬、比賽、國足、超級盃、球迷、中國、老婆、政府、航母、踢球、賽季、股市、砸蛋、牛逼、鐵道部、媳婦、國際、美國、連敗、魔獸、斯內德、紅十字、經濟、腐敗、程式、郭美美、英雄、民主、鳥巢、米蘭德比、官員、內涵、歷史、訓練、評級、金融、體育、記者、事故、程式設計師、媒體、投資、事件、社會、專案、伊布、主義、決賽、操蛋、納尼、領導、喝酒、民族、新聞、言論、和諧、農民、體制、城管⋯⋯

    下面則是女性愛說的詞:

一起玩、蛋糕、加好友、老公、嗚嗚、姐姐、嘻嘻、老虎、討厭、媽媽、嗚嗚嗚、啦啦啦、便宜、減肥、男朋友、老孃、逛街、無限、帥哥、禮物、互相、奶茶、委屈、各種、高跟鞋、指甲、城市獵人、閨蜜、巧克力、第二、爸爸、寵物、箱子、吼吼、大黃蜂、獅子、胃疼、玫瑰、包包、裙子、遊戲、遇見、嘿嘿、灰常、眼睛、各位、媽咪、化妝、玫瑰花、藍精靈、幸福、陪我玩、任務、怨念、捨不得、害怕、狗狗、眼淚、溫暖、面膜、收藏、李民浩、神經、土豆、零食、痘痘、戒指、巨蟹、晒黑⋯⋯

    下面是 90 後用戶愛用的詞:

加好友、作業、各種、乖乖、蛋糕、來訪、臥槽、通知書、麻將、聚會、補課、歡樂、刷屏、錄取、無限、互相、速度、一起玩、啦啦啦、晚安、求陪同、基友、美女、矮油、巨蟹、五月天、第二、唱歌、老虎、扣扣、嘖嘖、帥哥、哈哈哈、尼瑪、便宜、苦逼、斯內普、寫作業、勞資、孩紙、哎喲、炎亞綸、箱子、無聊、求來訪、查分、上課、果斷、處女、首映、遮蔽、混蛋、暑假、嚇死、新東方、組隊、下學期、陪我玩、打雷、妹紙、水瓶、射手、搞基、吐槽、同學聚會、出去玩、嗚嗚、白羊、表白、做作業、簽名、姐姐、停機、伏地魔、物件、哈哈、主頁、情侶、無壓力、共同、摩羯、碎覺、腫麼辦⋯⋯

    下面則是 80 後用戶愛用的詞:

加班、培訓、週末、工作、公司、各位、值班、砸蛋、上班、任務、公務員、工資、領導、包包、辦公室、校內、郭美美、時尚、企業、股市、新號碼、英國、常聯絡、實驗室、論文、忙碌、專案、部門、祈福、邀請、招聘、順利、朋友、紅十字、男朋友、媒體、產品、標準、號碼、存錢、牛仔褲、曼聯、政府、簡單、立秋、事故、伯明翰、博士、辭職、健康、銷售、深圳、奶茶、搬家、實驗、投資、節日快樂、堅持、規則、考驗、生活、體制、客戶、發工資、忽悠、提供、教育、處理、惠存、溝通、團購、缺乏、腐敗、啟程、紅十字會、結婚、管理、環境、暴跌、服務、變形金剛、祝福、銀行⋯⋯

    不僅如此,不少狀態還帶有地理位置資訊,因而我們可以站在空間的維度對資訊進行觀察。這個地方的人都愛說些什麼?愛說這個詞的人都分佈在哪裡?藉助這些包含地理位置的簽到資訊,我們也能挖掘出很多有意思的結果來。例如,對北京使用者的簽到資訊進行抽詞,然後對於每一個抽出來的詞,篩選出所有包含該詞的簽到資訊並按地理座標的位置聚類,這樣我們便能找出那些地理分佈最集中的詞。結果非常有趣:“考試”一詞集中分佈在海淀眾高校區,“天津”一詞集中出現在北京南站,“逛街”一詞則全都在西單附近扎堆。北京首都國際機場也是一個非常特別的地點,“北京”、“登機”、“終於”、“再見”等詞在這裡出現的密度極高。

    從全國範圍來看,不同區域的人也有明顯的用詞區別。我們可以將全國地圖劃分成網格,統計出所有簽到資訊在各個小格內出現的頻數,作為標準分佈;然後對於每一個抽出來的詞,統計出包含該詞的簽到資訊在各個小格內出現的頻數,並與標準分佈進行對比(可以採用餘弦距離等公式),從而找出那些分佈最反常的詞。程式執行後發現,這樣的詞還真不少。一些明顯具有南北差異的詞,分佈就會與整個背景相差甚遠。例如,在節假日的時候,“滑雪”一詞主要在北方出現,“登山”一詞則主要在南方出現。地方特色也是造成詞語分佈差異的一大原因,例如“三里屯”一詞幾乎只在北京出現,“熱乾麵”一詞集中出現在武漢地區,“地鐵”一詞明顯只有個別城市有所涉及。這種由當地人的用詞特徵反映出來的真實的地方特色,很可能是許多旅遊愛好者夢寐以求的資訊。另外,方言也會導致用詞分佈差異,例如“咋這麼”主要分佈在北方地區,“搞不懂”主要分佈在南方城市,“伐”則非常集中地出現在上海地區。當資料規模足夠大時,或許我們能通過計算的方法,自動對中國的方言區進行劃分。

    其實,不僅僅是釋出時間、使用者年齡、使用者性別、地理位置這四個維度,我們還可以對瀏覽器、使用者職業、使用者活躍度、使用者行為偏好等各種各樣的維度進行分析,甚至可以綜合考慮以上維度,在某個特定範圍內挖掘熱點事件,或者根據語言習慣去尋找出某個特定的人群。或許這聽上去太過理想化,不過我堅信,有了合適的演算法,這些想法終究會被一一實現。