1.jieba分詞
注意:使用jieba以前,數據預處理很重要,清除空值重複值以後,同時也要判斷數據是否為字符串,如果不是字符應該刪除該條數據。
如果讀取出現中文亂碼可以直接這樣打開,python2X3X通用
import codecs
with codecs.open('h.csv', 'rb', 'gb2312') as csvfile:
for line in csvfile:
print line
文本預處理的一般流程
#讀取數據
df1 = pd.read_excel('ManMade.xlsx')
#選出文本部分並且把非字符串索引存到列表
#如果只需要去除缺失值的話,有下面兩種方法:
#第一種把非空部分另存一列再處理
#df1['data'] = df['content'][df['content'].notnull()]
#第二種用dropna函數以后再重新排序
#df = df.dropna(subset=["content"])#subset代表需要看的列,如果content列中某一行為空,刪除該行
#重新排序,drop默認為False則索引列會被還原為普通列,否則會丟失。改為True,刪除原先的索引使用新的從0開始的索引
#df = df.reset_index(drop = True)
list0 = df1.content.apply(lambda x: len(x) > 2)
#統計長度小于二的個數並且記錄下他們的索引(因為如果文件是CSV格式,
#所有非空內容讀出來都是字符串格式,比如錯誤的記錄導致的空格或者數字用pandas讀取出來都是字符串格式,
#例如' '或者'0',用isinstance(x, str)無法分辨,雖然jieba分詞只要是字符串格式都能切詞,
#但是如果jieba分詞來讀取,則會把它當成int或者float格式,剔除這種數據,最簡單的方法就是去除長度過小的數據,
#但是如果是xlsx格式,0讀取出來就是int格式,用len(x)就會報錯
#那么就可以先用list1中的isinstance(x, str)來篩選)
list1 = df1.content.apply(lambda x: isinstance(x, str))
#另外:null部分會直接跳過,所以一開始一定要先dropna去掉空白部分)
#統計非字符串的個數並且記錄下他們的索引
count_a = 0
list2 = []
for i in range(len(list1)):
if list1[i]==False:
list2.append(i)
count_a += 1
else:
pass
#刪除所有非字符串的部分
df2 = df1.drop(list2,axis=0)
#重新排序
df2.reset_index()
#把列表里的內容存到一個字符串里
list_content = [i for i in df2.content]
content = ''.join(list_content)
print(len(content))
##如果有需要也可以對每個文章只選出他的漢字部分,介紹兩種常用方法:
#方法1:
#漢字的編碼范圍是['\u4e00','\u9fa5'],取出一個切完詞的文本列表中的全部漢字可以用范圍來限定
list1 = ['一堆','漢字','和','?!#','符號']
X,Y = ['\u4e00','\u9fa5']
list2 = [i for i in list1 if X <= i <= Y and i not in stopwords]
#方法2:
#正則表達式
import re
test='fuck you! 8婆婊子!要啥bike自行車啊!'
result1=re.findall(u'[\u4e00-\u9fa5]',test)
print (result1)
print (''.join(result1))
#['婆', '婊', '子', '要', '啥', '自', '行', '車', '啊']
#婆婊子要啥自行車啊
result2=re.findall(r'[0-9]',test)
print (''.join(result2))
#8
result3=re.findall(r'[a-z]',test)
print (''.join(result3))
#fuckyoubike
使用 suggest_freq(segment, tune=True) 可調節單個詞語的詞頻,使其能(或不能)被分出來。
jieba.cut 方法接受三個輸入參數: 需要分詞的字符串;cut_all 參數用來控制是否采用全模式;HMM 參數用來控制是否使用 HMM 模型。
jieba.cut_for_search 方法接受兩個參數:需要分詞的字符串;是否使用 HMM 模型。該方法適合用于搜索引擎構建倒排索引的分詞,粒度比較細。
待分詞的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建議直接輸入 GBK 字符串,可能無法預料地錯誤解碼成 UTF-8。
jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 循環來獲得分詞后得到的每一個詞語(unicode),或者用
jieba.lcut 以及 jieba.lcut_for_search 直接返回 list。
jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定義分詞器,可用于同時使用不同詞典。jieba.dt 為默認分詞器,所有全局分詞相關函數都是該分詞器的映射。
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業于中國科學院計算所,后在日本京都大學深造") # 搜索引擎模式
print(", ".join(seg_list))
#結果:
#【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
#【精確模式】: 我/ 來到/ 北京/ 清華大學
#【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈 (此處,“杭研”并沒有在詞典中,但是也被Viterbi算法識別出來了)
#【搜索引擎模式】: 小明, 碩士, 畢業, 于, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 后, 在, 日本, 京都, 大學, 日本京都大學, 深造
并行分詞
原理:將目標文本按行分隔后,把各行文本分配到多個 Python 進程并行分詞,然后歸并結果,從而獲得分詞速度的可觀提升
基于 python 自帶的 multiprocessing 模塊,目前暫不支持 Windows
-
用法:
-
jieba.enable_parallel(4)
# 開啟并行分詞模式,參數為并行進程數 -
jieba.disable_parallel()
# 關閉并行分詞模式
-
例子:https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py
實驗結果:在 4 核 3.4GHz Linux 機器上,對金庸全集進行精確分詞,獲得了 1MB/s 的速度,是單進程版的 3.3 倍。
注意:并行分詞僅支持默認分詞器
jieba.dt
和jieba.posseg.dt
。
特點:
-
支持三種分詞模式
–精確模式,試圖將句子最精確地切開,適合文本分析;
–全模式,把句子中所有的可以成詞的詞語都掃描出來,速度非常快,但不能解決歧義;
–搜索引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。
-支持繁體分詞
-支持自定義詞典
算法:
基于前綴詞典實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)
采用動態規劃查找最大概率路徑,找出基于詞頻的最大切分組合
對于未登錄詞,采用了基于漢字成詞能力的HMM模型,使用了Viterbi算法
添加自定義詞典:
開發者可以指定自己自定義的詞典,以便包含jieba詞庫里沒有的詞。雖然jieba有新詞識別能力,但是自行添加新詞可以保證更高的正確率
用法:jieba.load_userdict(file_name)#file_name為文件類對象 或自定義詞典的路徑
詞典格式:一個詞一行:詞語,詞頻(可省略),詞性(可省略),用空格隔開,順序不可顛倒。UTF-8編碼。
2.關鍵詞提取:
基于TF-IDF算法的關鍵詞抽取
import jieba.analyse
-
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
sentence 為待提取的文本
topK 為返回幾個 TF/IDF 權重最大的關鍵詞,默認值為 20
withWeight 為是否一并返回關鍵詞權重值,默認值為 False
allowPOS 僅包括指定詞性的詞,默認值為空,即不篩選
常用詞性有:["ns", "n", "vn", "v", "nr"]
注意:選取單個詞性時結尾要用逗號,
例如["ns",],如果不加逗號,實際上是按照["n","s"]來取詞的。
詞性表
- jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 實例,idf_path 為 IDF 頻率文件
關鍵詞提取所使用逆向文件頻率(IDF)文本語料庫可以切換成自定義語料庫的路徑
- 用法:jieba.analyse.set_idf_path(file_name) file_name為自定義語料庫的路徑
關鍵詞提取所使用停止詞(Stop Words)文本語料庫可以切換成自定義語料庫的路徑
- 用法: jieba.analyse.set_stop_words(file_name) file_name為自定義語料庫的路徑
基于TextRank算法的關鍵詞提取
- jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意默認過濾詞性。
-
jieba.analyse.TextRank() 新建自定義 TextRank 實例
–基本思想:
1,將待抽取關鍵詞的文本進行分詞
2,以固定窗口大小(默認為5,通過span屬性調整),詞之間的共現關系,構建圖
3,計算圖中節點的PageRank,注意是無向帶權圖
下面寫出jieba關鍵詞提取方法例子
# -*- coding: utf-8 -*-
#基于詞語共現圖提取方法
import jieba
#import jieba.posseg as psg
import itertools as it
import pandas as pd
#import json
#from elasticsearch import Elasticsearch
#from pyquery import PyQuery as pq
import time
def wordweight(wc1,wc2,samecounts):
weight = samecounts/(wc1+wc2-samecounts) # Jaccard係數,交集與並集比值
return weight
#def wordweight(wc1,wc2,samecounts):
# weight = samecounts/(wc1*wc2) # PMI,互信息
# return weight
t1 = time.time()
#讀數據&清洗數據
list_content = []
df1 = pd.read_excel('ManMade20.xlsx')
list1 = df1.content.apply(lambda x: isinstance(x, str))
count_a = 0
list2 = []
for i in range(len(list1)):
if list1[i]==False:
list2.append(i)
count_a += 1
else:
pass
df2 = df1.drop(list2,axis=0)
df2.reset_index()
list_content = [i for i in df2.content]
content = ''.join(list_content)
print(len(content))
#print(content)
t2 = time.time()
#提取關鍵詞
#1.用jieba自帶的提取關鍵詞
#一百篇文章做速度測試
#Running time:615.9178113937378 Seconds
#詞性限制集合為["ns", "n", "vn", "v", "nr"],表示只能從詞性為地名、名詞、動名詞、動詞、人名這些詞性的詞中抽取關鍵詞。
allow_pos = ('ns', 'nr', 'n', 'vn', 'v', 'an', 'nz', 'vg')
tags = jieba.analyse.extract_tags(content,topK = 100,allowPOS = allow_pos) # 基於 TF-IDF 算法的關鍵詞提取
# tags = jieba.analyse.textrank(content,topK=100) # 基於 TextRank 算法的關鍵字提取
t3 = time.time()
sentence = content.split('\n') # '\n'換行,段落
sentence = [e for e in sentence if e not in ('', ' ')] # 去出空格之類的噪聲
wordraw = []
t4 = time.time()
for i in range(len(sentence)):
#words = [e.word for e in psg.cut(sentence[i]) if e.flag.startswith(('n','a','v'))]
words = jieba.lcut(sentence[i])
cleanwords = [e for e in words if e in tags]
wordraw.append(cleanwords)
wordlist = [list(set(x)) for x in wordraw] # 文章段落同個詞可能出現多次(詞頻統計基本單位:段落)
#map(lambda x: list(set(x)), wordlist) #去除第二層list裡面重複值
wordlist = [x for x in wordlist if len(x) > 1]
#filter(lambda x: len(x) > 1, wordlist) #過濾掉空格和len1的字符串
#把3個以上的詞拆分進行兩兩組合
wordlist1 = [list(it.combinations(x,2)) for x in wordlist]
#map(lambda x: list(it.combinations(x,2)), wordlist)
#拆分組合中的list加到大list中
wordcorpus = [wordlist1[i][j] for i in range(len(wordlist1)) for j in range(len(wordlist1[i]))]
wordcorpus = [sorted(x) for x in wordcorpus]
#print(len(wordcorpus))
#map(lambda x: sorted(x), wordcorpus) #對list名詞進行排序
#wordcorpus = sorted(wordcorpus) #對list中元組進行排序
#wordcorpus = [tuple(x) for x in wordcorpus]
#map(lambda x: tuple(x), wordcorpus)#對名詞進行tuple轉化
#corpus = list(set(wordcorpus)) #排重得到新list,方便后面計算count
keywords={}
#countwords = jieba.lcut(content)
countwords = []
t5 = time.time()
for i in wordraw:
countwords.extend(i)
t6 = time.time()
for i in tags:
keywords[i] = countwords.count(i)
source = []
target = []
weight = []
t7 = time.time()
for j in range(len(wordcorpus)):
source.append(list(wordcorpus[j])[0])
target.append(list(wordcorpus[j])[1])
weight.append(wordweight(keywords[wordcorpus[j][0]],keywords[wordcorpus[j][1]],wordcorpus.count(wordcorpus[j])))
df={'source':source,'target':target,'weight':weight}
frame = pd.DataFrame(df,columns=['source','target','weight'])
sourceFreq = []
targetFreq = []
t8 = time.time()
for i in range(len(frame)):
sourceFreq.append(keywords[frame['source'][i]])
targetFreq.append(keywords[frame['target'][i]])
frame.insert(3,'sourceFreq',sourceFreq)
frame.insert(4,'targetFreq',targetFreq)
jsondata = frame.to_dict(orient='records')
t9 = time.time()
print(jsondata)
print('Running time1: %s Seconds'%(t2-t1))
print('Running time2: %s Seconds'%(t3-t2))
print('Running time3: %s Seconds'%(t4-t3))
print('Running time4: %s Seconds'%(t5-t4))
print('Running time5: %s Seconds'%(t6-t5))
print('Running time6: %s Seconds'%(t7-t6))
print('Running time7: %s Seconds'%(t8-t7))
print('Running time8: %s Seconds'%(t9-t8))
print('Running time0: %s Seconds'%(t9-t1))