?最近筆者在做文本挖掘項目時候,寫了一些小演算法,不過寫的比較重,沒有進行效率優化,針對大數據集不是特別好用,不過在小數據集、不在意性能的情況下還是可以用用的。

本次練習題中可以實現的功能大致有三個:

  • 短語發現
  • 新詞發現
  • 詞共現

短語發現、新詞發現跟詞共現有些許區別:

[『舉』,個,『例子』,『來說』]
  • 短語發現、新詞發現,是詞-詞連續共現的頻率,窗口範圍為1,也就是:『舉』,『例子』;個,『例子』;『例子』,『來說』,探究挨得很近的詞之間的關係
  • 詞共現是詞-詞離散出現,詞共現包括了上面的內容,探究:『舉』,『來說』,不用挨著的詞出現的次數

code可見我的github:mattzheng/LangueOne


一、數據集介紹

練習數據來源:今日頭條中文新聞(文本)分類數據集

今日頭條是最近開源的數據集,38w,其中的數據格式為:

6552391948794069256_!_106_!_news_house_!_新手買房,去售樓部該如何諮詢?_!_
6552263884172952072_!_106_!_news_house_!_南京90後這麼有錢嗎?南京百分之四五十都是小杆子買了_!_公積金,江寧,麒麟鎮,南京90後,大數據
6552313685874835726_!_106_!_news_house_!_漲價之前買房的人,現在是什麼心情?_!_
6552447172724392456_!_106_!_news_house_!_這種凸陽台房子萬萬不要買,若不是售樓閨蜜說,我家就吃大虧_!_凸陽台,售樓,買房

每行為一條數據,以_!_分割的個欄位,從前往後分別是 新聞ID,分類code(見下文),分類名稱(見下文),新聞字元串(僅含標題),新聞關鍵詞


二、短語發現、新詞發現演算法介紹

2.1 理論介紹

短語發現、新詞發現,內容與演算法基礎源於該博客:基於凝聚度和自由度的非監督詞庫生成

評估詞之間的幾個指標,出了頻率還有:

  • 凝聚度:

該詞語為S,首先計算該詞語出現的概率P(S),然後嘗試S的所有可能的二切分,即分為左半部分sl和右半部分sr並計算P(sl)和P(sr),

例如雙漢字詞語存在一種二切分、三漢字詞語存在兩種二切分。接下來計算所有二切分方案中,P(S)/(P(sl)×P(sr))的最小值,取對數之後即可作為聚合度的衡量。 以雙漢字詞語為例,可以想像到,如果該詞語的聚合度很低,說明其第一個字和第二個字的相關性很弱,甚至是不相關的,那麼P(S)和P(sl)×P(sr)將處於同一個數量級。 相反,如果該詞語的聚合度很高,「齊天」、「大聖」和「齊天大聖」三者的概率都很接近,因此P(S)/(P(sl)×P(sr))將是一個遠大於1的數值。

  • 自由度:

用熵來衡量一個詞語的自由度。假設一個詞語一共出現了N次,其左邊共出現過n個漢字,每個漢字依次出現N1,N2,……,Nn次,則滿足N = N1 + N2 + …… + Nn,因此可以計算該詞語左邊各個漢字出現的概率,

並根據熵公式計算左鄰熵。熵越小則自由度越低,例如「天大聖」的左鄰熵接近於0,因為「齊」字的概率幾乎為1;熵越大則自由度越高,表示用詞搭配越混亂、越自由、越多樣。

因為「天大聖」的左鄰熵很小,而右鄰熵則相對較大,因此我們將一個詞語左鄰熵和右鄰熵中較小者作為最終的自由度。

  • IDF:

逆文檔詞頻

2.2 主函數參數

演算法的參數描述:

class termsRecognition(object):
def __init__(self, content=, topK=-1, tfreq=10, tDOA=0, tDOF=0, is_jieba= False,mode = [1]):

其中的參數::

  • content: 待成詞的文本
  • maxlen: 詞的最大長度
  • topK: 返回的詞數量
  • tfreq: 頻數閾值
  • tDOA: 聚合度閾值
  • tDOF: 自由度閾值
  • mode:詞語生成模式,一共四種模式,其中第二種模式比較好,一定要寫成[1]
  • diction:字典,第一批Jieba分詞之後的內容
  • idf_diction:在第一批字典之後,又生成一批tuple words 的idf,計算方式是,兩個詞語的平均
  • punct:標點符號,Jieba分詞之後刪除

演算法步驟:

  • jieba_tuples_generator, 利用Jieba分詞,並去除標點符號,去除清除(寫入self.jieba_content),利用wordsGenerator函數生成詞語對(四種模式)(寫入self.tuple_content)
  • word_get_frequency_idf,計算freq 以及貼idf,同時生成left/right框,把詞語對(self.tuple_content))寫入result( 主要寫入部分)
  • get_doa:只輸入result,計算數據的doa,直接更新result中的[doa]
  • word_get_dof:只輸入result,計算數據的dof,直接更新result中的[dof],左熵的文字,右熵的文字
  • get_score,只輸入result,更新result中的[scores]

可用的函數:

  • get_idf,文檔的IDF計算
  • wordsGenerator,生成詞語對
  • get_entropy計算左、右熵值,填充result


三、詞共現演算法介紹

就是計算詞語共同出現的概率,一般用在構建詞條網路的時候用得到,之前看到這邊博客提到他們自己的演算法:《python構建關鍵詞共現矩陣》看著好麻煩,於是乎自己簡單寫了一個,還是那個問題....效率比較低...

之前一般的做法是先生成一個基於詞-詞矩陣,然後去累計詞-詞之間的出現次數。

我這邊只是簡單利用笛卡爾積:

  • permutations 排列
  • combinations 組合,沒有重複
  • combinations_with_replacement 組合,有重複

>>> import itertools
>>> for i in itertools.product(ABCD, repeat = 2):
... print i,
...
(A, A) (A, B) (A, C) (A, D) (B, A) (B, B) (B, C) (B, D) (C, A) (C, B) (C, C) (C, D) (D, A) (D, B) (D, C) (D, D)
>>> for i in itertools.permutations(ABCD, 2):
... print i,
...
(A, B) (A, C) (A, D) (B, A) (B, C) (B, D) (C, A) (C, B) (C, D) (D, A) (D, B) (D, C)
>>> for i in itertools.combinations(ABCD, 2):
... print i,
...
(A, B) (A, C) (A, D) (B, C) (B, D) (C, D)
>>> for i in itertools.combinations_with_replacement(ABCD, 2):
... print i,
...
(A, A) (A, B) (A, C) (A, D) (B, B) (B, C) (B, D) (C, C) (C, D) (D, D)


四、練習題

文件夾介紹:

  • 短語發現、新詞發現演算法:termsRecognition.py
  • 今日頭條數據38w:toutiao_data.csv
  • 二元組演算法:tuplewords.py

先來看看數據長啥樣:

廢話不多說,直接使用一下:

4.1 短語發現、新詞發現模塊

該模塊可以允許兩種內容輸入,探究的是詞-詞之間連續共現,一種數據格式是沒有經過分詞的、第二種是經過分詞的。

其中,演算法會提到全部發現以及部分發現兩種模式,這兩種模式的區別主要在於考察指標的多少。
  • 全部發現會考察:凝聚度、自由度、IDF、詞頻
  • 部分發現會考察:IDF、詞頻

4.1.1 沒有經過分詞的原始語料

在今日頭條數據之中就是標題數據了,一般用來新詞發現,這邊整體運行很慢,就截取前10000個。

data = pd.read_csv(toutiao_data.csv,encoding = utf-8)

generator = termsRecognition(content = data[new_title][:10000] ,is_jieba=False, topK = 20 , mode = [1]) # 文字版
# 全部發現
result_dict = generator.generate_word()
result_dataframe = generator.get_result()
# 部分發現
result_dataframe = generator.part_found()

得到的結論,如圖:

這邊其實可以在Jieba分詞的時候,預先載入一些停用詞。這邊來看,發現的有:對下聯、王者榮耀新詞發現的能力還不夠好。

4.1.2 經過分詞的原始語料

比較適合用在已經分完詞的語料比較適合:[[經過,分詞],[的,原始],[原始,語料],...]

當然,探究的是詞-詞之間的連續共現的情況。此時,我用今日頭條的關鍵詞其實不是特別合適,因為關鍵詞之間沒有前後邏輯關係在其中。在此只是簡單給觀眾看一下功能點。

data = pd.read_csv(toutiao_data.csv,encoding = utf-8)
def not_nan(obj):
return obj == obj

keywords = []
for word in tqdm(data.new_keyword):
if not_nan(word):
keywords.append(word.split(,))

generator = termsRecognition(content = keywords[:1000] , is_jieba=True , topK = 20,mode = [1]) #圖像版
# 部分發現
result_dataframe = generator.part_found()

得到的結論:

其中發現了的規律都沒啥用,大家看看就行。。

4.2 詞共現模塊

二元組模塊跟4.1中,分完詞之後的應用有點像,但是這邊是離散的,之前的那個考察詞-詞之間的排列需要有邏輯關係,這邊詞共現會更加普遍。

該模塊較多會應用在基於關鍵詞的SNA社交網路發現之中,給張好看的圖:

其中,在該模塊寫入了兩種:
  • 熱詞統計
  • 詞共現統計

data = pd.read_csv(toutiao_data.csv,encoding = utf-8)

def not_nan(obj):
return obj == obj

keywords = []
for word in tqdm(data.new_keyword):
if not_nan(word):
keywords.append(word.split(,))

# 設置停用詞
stop_word = [方法,結論]
tw = TupleWords(stop_word)

# 得到結果
id_pools,tuple_pools = tw.CoOccurrence(keywords[:1000])

# 內容變成dataframe
CoOccurrence_data = tw.tansferDataFrame(tuple_pools)
CoOccurrence_data

# 熱詞統計模塊
hotwords_dataframe = tw.Hotwords(keywords[:1000])
hotwords_dataframe

該模塊輸入的是keywords,List形:

[[保利集團, 馬未都, 中國科學技術館, 博物館, 新中國],
[林風眠,
黃海歸來步步雲,
秋山圖,
計白當黑,
山水畫,
江山萬里圖,
張大千,
巫峽清秋圖,
活眼,
山雨欲來圖],
[牡丹, 收藏價值],
[葉淺予, 田世光, 李苦禪, 花鳥畫, 中央美術學院]

tw.CoOccurrence就是對上面的內容進行解析,得到了:

發現,快樂大本營-謝娜的組合比較多,詹姆斯-猛龍嘛,看客們懂的,詹皇血克猛龍,哈哈~

熱詞發現這個很常規:


後續拓展——SNA社交網路發現網路圖:

得到了CoOccurrence_data 的表格,有了詞共現,就可以畫社交網路圖啦,有很多好的博客都有這樣的介紹,推薦幾篇:

基於共現發現人物關係的python實現

python簡單實戰項目:《冰與火之歌1-5》角色關係圖譜構建——人物關係可視化


推薦閱讀:
相关文章