【挖掘篇】:文字分析

weixin_34402408發表於2017-05-22
# 詞頻統計(某一個給定的詞在該文件中出現次數)
    # 語料庫         分析的所有文件的集合
    # 中文分詞       一個漢字序列切分成一個個單詞
    # 停用詞         資料處理的時候,自動過濾掉的某些字或詞,包括氾濫的詞,如:web,網站,語氣助詞,副詞,介詞,連線詞
    # 檔案讀取API
        # 構建方法:os.walk(fileDir_資料夾路勁)
        # 檔案讀取:codecs.open(filePath_檔案路勁,method_檔案的開啟方式(r_只讀 w_寫 rw_讀寫),encoding_檔案的編碼,使用UTF-8)
            # 用codes 提供的open 方法來開啟檔案的語言編碼,讀取時候回自動換換unicode,不然是亂碼
    # 中文分詞API
        # 安裝方式: pip install jieba
        # 分詞方法: jieba.cut(connent_需要分詞的句子)
            # 返回  segments 分詞的陣列

    # 詞雲統計API
        # 安裝方式:pip install wordcloud
        # 繪製方法:
            # 生成wordcloud 物件
                # wordcloud = WordCloud(font_path = 'simhei.ttf_中文字型',background_color = ‘black_背景顏色黑色’)
            # 進行繪製
                # wordcloudImg = wordcloud.fit_words(tuples)

    # 關鍵詞  一篇文件的關鍵詞通常是幾個詞或者短語,作為對該文件主要內容提要
    # 詞頻 TF = 某個詞在該文件中出現的次數
    # 逆文件頻率 IDF就是每個詞的權重,它的大小與一個詞的常見程度成反比 IDF = log (文件總數/(包含該詞的文件數+1))
    # TF-IDF = TF * IDF  權衡某個分詞是否關鍵詞的指標,該值越大,是關鍵詞的可能性越大
    
    # 案例:馬爾科夫模型在中文分詞中的應用,“馬爾科夫模型” 和 "中文分詞" 的TF一樣,那個適合關鍵詞
    
        # 用統計學語言表達,就是在詞頻的基礎上,對每個詞分配一個權重
            # 常見的詞“的,是,在” 給予最小的權重
            # 較常見的詞 “中文分詞” 給予較小的權重
            # 較少見的詞 “馬爾科夫模型” 給予較大的權重

    # 自動摘要  全面準確的反映某一文獻中心內容地簡單連貫的短文 
     # 演算法步驟
         # 獲取到需要摘要的文章
         # 對文章進行詞頻統計
         # 對文中進行分句,根據中文的標點符號,一般我們採用“。”,“、”?” 分句
         # 計算分句和文章之間的餘弦相似度
         # 取相似度最高的分句,作為文章摘要

    # 相似文章推薦  使用者閱讀某篇文章的時候,為使用者推薦更多與在讀文章在內容相似的文章
    
    # 推薦 介紹好的人或者事物,希望被任用或接受,在目前的資料探勘領域,推薦包括相似推薦和協同過濾推薦
        # 相似推薦  當使用者對某人或者某物感興趣時,為它推薦與之相似的人或者物,人以群分,物以類聚
        # 協同過濾推薦 利用已有使用者群過去的行為或者意見,預測當前使用者最可能喜歡那些東西或者對哪些東西感興趣
    # 餘弦相似度 用向量空間中兩個向量夾角的餘弦值作為衡量兩個個體間差異的大小。餘弦值越接近1,說明夾角越相似,兩個向量越相似
        # cos(e) = ∑(xi * yi) / (√∑(xi)^2 * √∑(yi)^2)
    # 案例:
        # 文章A 放假我喜歡彈吉他,看書 --分詞--> 放假 我 喜歡 彈 吉他 看書
        # 文章B 放假我不喜歡看書,大球 --分詞--> 放假 我 不 喜歡 看書 喜歡 吉他
            # 語料庫 放假 我 喜歡 彈 吉他 看書 不 打球
        # 向量化(統計詞頻)
            # 文章A 【1 1 1 1 1 1 0 0】
            # 文章B 【1 1 2 0 0 1 1 1】
        # 計算
            # = (1*1+1*1+1*2+1*0+1*0+1*1+0*1+0*1)/√(1^2+1^2+1^2+1^2+1^2+1^2+0^2+0^2) * √(1^2+1^2+2^2+0^2+0^2+1^2+1^2+1^2)
            # 越小越相似

中文分詞

1208710-8162d74e34fb459a.png
Paste_Image.png
import jieba;

#http://pinyin.sogou.com/dict/    搜狗詞庫 ,下載為scel 檔案 --》深藍詞庫轉換(無拼音純單詞) --》 txt 檔案

seg_list = jieba.cut("真武七截陣和天罡北斗陣哪個更厲害呢?")
print(", ".join(seg_list)) # 將列表中的每個通過,列印出來

jieba.load_userdict('F:\\python 資料探勘分析實戰\\Code\\金庸武功招式.txt'); # 載入詞庫,正確的分詞

seg_list = jieba.cut("真武七截陣和天罡北斗陣哪個更厲害呢?")
print(", ".join(seg_list))

詞雲繪製

import os
import os.path
os.getcwd()
os.chdir('F:\\python 資料探勘分析實戰\\Code')
import codecs
import numpy
import pandas
import jieba

#建立語料庫
corpos = pandas.DataFrame(columns=['filePath', 'content'])

# 讀取一個資料夾中的txt
for root, dirs, files in os.walk(
# root_起始路徑   dirs_起始路徑資料夾   files_qisi
    "F:\\python 資料探勘分析實戰\\Data\\SogouC.mini\\Sample\\C000007\\"
):
    for name in files:
        filePath = root + '\\' + name;
        f = codecs.open(filePath, 'r', 'utf-8')
        content = f.read()
        f.close()
        corpos.loc[len(corpos)] = [filePath, content.strip()]; # 資料框自動增加一行值
        
import re
#匹配中文的分詞
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')

#進行分詞

filePaths = []
segments = []

for i in range(len(corpos)):
    filePath = corpos.loc[i].filePath  # corpos.loc[i] 第i行 .filePath 列
    segs = jieba.cut(corpos.loc[i].content)
    for seg in segs:
        if zhPattern.search(seg): # search方法可以返回第一個滿足要求的字串。一旦找到符合要求的內容,它就會停止查詢
            filePaths.append(filePath) # 當放入seg的迴圈時候,就可以實現一對多
            segments.append(seg)
            
segmentDF = pandas.DataFrame({'filePath':filePaths, 'segment':segments})

#進行詞頻統計        
segStat = segmentDF.groupby(
            by="segment"
        )["segment"].agg({
            "計數":numpy.size
        }).reset_index().sort(
            columns=["計數"],
            ascending=False
        );

#移除停用詞
stopwords = pandas.read_csv(
    "F:\\python 資料探勘分析實戰\\Code\\StopwordsCN.txt", 
    encoding='utf8', 
    index_col=False,
    quoting=3,
    sep="\t"
)

fSegStat = segStat[~segStat.segment.isin(stopwords.stopword)] # segStat.segment 在 stopwords.stopword

#繪畫詞雲
#http://www.lfd.uci.edu/~gohlke/pythonlibs/
# pip install wordcloud-1.2.1-cp35-cp35m-win32.whl
from wordcloud import WordCloud
import matplotlib.pyplot as plt

wordcloud = WordCloud(
    font_path='F:\\python 資料探勘分析實戰\\Code\\simhei.ttf', 
    background_color="black"
)

wordcloud = wordcloud.fit_words(fSegStat.itertuples(index=False))

plt.imshow(wordcloud)

plt.close()

關鍵詞提取

1208710-14893f414700620f.png
Paste_Image.png
import os
import os.path
import codecs
import numpy
import pandas
import jieba

#建立語料庫
corpos = pandas.DataFrame(columns=['filePath', 'content'])

for root, dirs, files in os.walk(
    "F:\\python 資料探勘分析實戰\\Data\\SogouC.mini\\Sample\\"
):
    for name in files:
        filePath = root + '\\' + name;
        f = codecs.open(filePath, 'r', 'utf-8')
        content = f.read()
        f.close()
        corpos.loc[len(corpos)] = [filePath, content.strip()];

import re
#匹配中文的分詞
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')  # 匹配中文

#進行分詞
filePaths = []
segments = []
for i in range(len(corpos)):
    filePath = corpos.loc[i].filePath
    segs = jieba.cut(corpos.loc[i].content)
    for seg in segs:
        if zhPattern.search(seg):
            filePaths.append(filePath); # 直接引用該層
            segments.append(seg);

segmentDF = pandas.DataFrame({'filePath':filePaths, 'segment':segments})

#移除停用詞
stopwords = pandas.read_csv(
    "F:\\python 資料探勘分析實戰\\Code\\StopwordsCN.txt", 
    encoding='utf8', 
    index_col=False,
    quoting=3,
    sep="\t"
)

segmentDF = segmentDF[~segmentDF.segment.isin(stopwords.stopword)]

#按文章進行詞頻統計,select filePath,segment,count(*) as 計數 from segmentDF group by filePath,segment
# 每個文章的詞頻
segStat = segmentDF.groupby(
            by=["filePath", "segment"]
        )["segment"].agg({
            "計數":numpy.size
        }).reset_index().sort(
            columns=["計數"],
            ascending=False
        );
        
"""
groupby(by = [分組列A,分組列B,...])[統計列A,統計列B,...].agg({統計列A別名:統計函式...)

    count(*) -->  size
    sum(*)   -->  sum
    avg(*)   -->  mean

reset_index() 重排index

"""

#把小部分的資料刪除掉
segStat = segStat[segStat.計數>1]

#進行文字向量計算,
#           columns = 'filePath'
#  index = segment   計數
textVector = segStat.pivot_table(
    index='segment', 
    columns='filePath', 
    values='計數',
    fill_value=0
) 

"""
交叉計數函式
    pivot_table(vaules,index,columns,aggfunc,fill_value)  --> 返回透視表中的結果
        values:資料透視表中的值
        index:資料透視表中的行
        columns:資料透視表中的列
        aggfunc:統計函式
        fill_value:NA值的統一替換
"""

TF = textVector.as_matrix(); # 使用matrix類建立的是矩陣物件

#hanlder = lambda x:(numpy.log2(len(corpos)/(numpy.sum(x>0)+1)))
def hanlder(x): 
    return (numpy.log2(len(corpos)/(numpy.sum(x>0)+1))) 
# log2(文件總數/包含該詞的文件書)

IDF = textVector.apply(hanlder).as_matrix();

TF_IDF = TF * IDF

TF_IDF_DF = pandas.DataFrame(TF_IDF) # 將矩陣轉為為資料框

tag1s = []
tag2s = []
tag3s = []
tag4s = []
tag5s = []
for i in range(len(corpos)):
    tagis = textVector.index[TF_IDF_DF.loc[:,i].order(ascending=False)[:5].index] # 第一列倒敘前5個
    tag1s.append(tagis[0])
    tag2s.append(tagis[1])
    tag3s.append(tagis[2])
    tag4s.append(tagis[3])
    tag5s.append(tagis[4])
# 形成 檔案路勁 文章內容 關鍵字
tagDF = pandas.DataFrame({'filePath':corpos.filePath, 'content':corpos.content, 'tag1':tag1s, 'tag2':tag2s, 'tag3':tag3s, 'tag4':tag4s, 'tag5':tag5s})    

相似文章推薦簡介

1208710-55842d985de33e92.png
Paste_Image.png
import os
import os.path
import codecs
import numpy
import pandas
import jieba

#建立語料庫
corpos = pandas.DataFrame(columns=['filePath', 'content'])

for root, dirs, files in os.walk(
    "F:\\python 資料探勘分析實戰\\Data\\SogouC.mini\\Sample\\"
):
    for name in files:
        filePath = root + '\\' + name;
        f = codecs.open(filePath, 'r', 'utf-8')
        content = f.read()
        f.close()
        corpos.loc[len(corpos)] = [filePath, content.strip()];

#進行分詞
filePaths = []
segments = []
for i in range(len(corpos)):
    filePath = corpos.loc[i].filePath
    segs = jieba.cut(corpos.loc[i].content)
    for seg in segs:
        if len(seg.strip())>1:
            filePaths.append(filePath);
            segments.append(seg);

segmentDF = pandas.DataFrame({'filePath':filePaths, 'segment':segments})

#移除停用詞
stopwords = pandas.read_csv(
    "F:\\python 資料探勘分析實戰\\Code\\StopwordsCN.txt", 
    encoding='utf8', 
    index_col=False,
    quoting=3,
    sep="\t"
)

segmentDF = segmentDF[~segmentDF.segment.isin(stopwords.stopword)]

#按文章進行詞頻統計
segStat = segmentDF.groupby(
            by=["filePath", "segment"]
        )["segment"].agg({
            "計數":numpy.size
        }).reset_index().sort(
            columns=["計數"],
            ascending=False
        );

segStat = segStat[segStat.計數>1]

#進行文字向量計算
textVector = segStat.pivot_table(
    index='segment', # 分詞為索引
    columns='filePath', # 文章路徑為觀測
    values='計數', # 分詞對應文章為索引
    fill_value=0
)

def cosineDist(col1, col2): 
    # 計算餘弦相似度
    return numpy.sum(col1 * col2)/(
        numpy.sqrt(numpy.sum(numpy.power(col1, 2))) * 
        numpy.sqrt(numpy.sum(numpy.power(col2, 2)))
    ) 

distance_df = textVector.apply(
    lambda col1: textVector.apply(
        lambda col2: cosineDist(col1, col2)
    ) # 計算每列列對應的餘弦相似度
)

for i in range(len(corpos)):
    tagis = distance_df.iloc[:,i].order(ascending=False)[1:6].index 
    print("與 " + distance_df.index[i] + " 相似的文章:")
    print("\n".join(tagis))
    print("\n")
# 獲取前六列的前餘弦相似度文章

自動摘要

1208710-a009199652d4e44c.png
Paste_Image.png
import os
import os.path
import codecs
import numpy
import pandas
import jieba

#建立語料庫
corpos = pandas.DataFrame(columns=['filePath', 'content'])

for root, dirs, files in os.walk(
    "F:\\python 資料探勘分析實戰\\Data\\SogouC.mini\\Sample\\"
):
    for name in files:
        filePath = root + '\\' + name;
        f = codecs.open(filePath, 'r', 'utf-8')
        content = f.read()
        f.close()
        corpos.loc[len(corpos)] = [filePath, content.strip()];

#移除停用詞
stopwords = pandas.read_csv(
    "F:\\python 資料探勘分析實戰\\Code\\StopwordsCN.txt", 
    encoding='utf8', 
    index_col=False,
    quoting=3,
    sep="\t"
)

def cosineDist(col1, col2): 
    return numpy.sum(col1 * col2)/(
        numpy.sqrt(numpy.sum(numpy.power(col1, 2))) * 
        numpy.sqrt(numpy.sum(numpy.power(col2, 2)))
    )

import re
"""
m = "
  以禁止女兵穿低腰褲
  已有120名女兵因違規被關禁閉
  據新華社電 以軍日前正在開展一場“全方位作戰行動”。這次作戰的目標可不是巴勒斯坦,而是女兵的低腰褲。
  以軍一位發言人7日說:“根據以色列國防軍軍紀,北方司令部決定實施更加嚴格的政策,使士兵的穿著符合紀律規定。”以色列女兵紛紛抱怨說,軍裝不能很好地展示她們的身材。為了追趕時尚潮流,這些女兵們經常重新設計自己的軍裝,有些人甚至把它們改成了低腰褲。然而,女兵們愛美的天性並沒有獲得軍隊指揮官的同情,他們認為,低腰褲嚴重威脅著以軍的紀律基礎。
  以軍要求女兵們把那些改過的低腰褲交到軍需商店,以換回符合規定的軍褲。此外,目前已經約有120名女兵因穿著違規低腰褲而被關禁閉。
n = [m] + re.split(r'[。?!\n]\s*', m)  
"""

#進行分詞,一篇篇文章列印出來
for i in range(len(corpos)):
    #i = 0
    filePath = corpos.loc[i].filePath # 第i行第filePath列
    #建立子語料庫,以該文件和該文件的分句組成
    subCorpos = [corpos.loc[i].content] + re.split(r'[。?!\n]\s*', corpos.loc[i].content) # 列表+列表
    # 內容+通過將第I行的內容將(.?!)分割為列表
    sub = []
    segments = []
    
    for j in range(len(subCorpos)):
        segs = jieba.cut(subCorpos[j])
        for seg in segs:
            if len(seg.strip())>1:
                sub.append(subCorpos[j]);
                segments.append(seg);
    # 文章,分句,分詞
    segmentDF = pandas.DataFrame({'sub':sub, 'segment':segments})        

    segmentDF = segmentDF[~segmentDF.segment.isin(stopwords.stopword)]

    #按文章進行詞頻統計   group by 列,分詞數--》計數
    segStat = segmentDF.groupby(
                by=["sub", "segment"]
            )["segment"].agg({
                "計數":numpy.size
            }).reset_index().sort(
                columns=["計數"],
                ascending=False
            );
    
    #進行文字向量計算
    textVector = segStat.pivot_table(
        index='segment', # 分詞為索引
        columns='sub', # 句子為列/觀測
        values='計數', # 分詞在句子之間出現的次數
        fill_value=0
    )
    # 計算距離,apply(numpy.sum) 按列相加
    target = textVector.ix[:, textVector.apply(numpy.sum)==textVector.apply(numpy.sum).max()] 
    # 按列相加,最大的列,就是內容列
    textVector = textVector.ix[:, textVector.apply(numpy.sum)!=textVector.apply(numpy.sum).max()]
    # 這就是分句列
    distance = textVector.apply(lambda col: cosineDist(target.ix[:, 0], col)) 
    # 計算分句列和內容列之間的餘弦相似度
    
    tagis = distance.order(ascending=False)[0:1].index # 找預先相似度最大的列
    print(corpos.loc[i].content) # 因為是迴圈的關係,可以形成一一對應的關係
    print(filePath + " 的摘要是:") 
    print(tagis) # ok

參考文獻
作者A:ken

相關文章