python自然語言處理

<p align = "center">可以看我的博客 lmwen.top</p>
<p align = "center">或者訂閱我的公眾號</p>

懶寫作

簡介
因為公司項目的原因,最近花了點時間去研究NLP
自然語言處理是一門比較復雜的技術,說深了,它涉及到機器學習和神經網絡模型,說淺了,你會用他人實現好的工具就ok了。這么復雜的東西,當然首選python來實現啦!
本章我們來實現一個簡單的軟件,可以對word文檔、pdf文檔進行關鍵詞提取、自動摘要、中文分詞和短語提取,效果如下


環境配置
我使用的環境:python2.7+ubuntu16.04+java1.8.0
python使用了的第三方庫有:wxpython、Jpype、docx2txt、pdfminer
漢語處理庫:HanLP
簡單說說這些庫wxpython:一個跨平臺的python圖形界面庫,非常友好,使用它可以比較輕松的搭建一個界面還ok的圖形界面,可以通過pip下載,也可以直接去wxpython官網下載,它有很多中文教程,隨便搜搜就有了
Jpype:讓python可以調動Java程序,一般為jar包,Jpype不同Jython,Jython運行在JVM上,而Jpype依舊運行在python上,只是在運行期間嵌入了JVM,你依舊可以通過pip下載,ubuntu還可以通過apt-get下載,主要不同版本的python對應不同版本的Jpype,Python2.7對應Jpype1,Python3對應Jpype1-py3,這里使用這個庫的原因是,我們使用的自然語言處理算法使用java實現的,所以要通過Jpype來調用相應jar包中的方法
docx2txt:從庫的名字也可以輕易的看出,docx2txt用于將docx格式的文檔,也就是word文檔轉成txt,該庫使用起來非常簡單
pdfminer:pdfminer主要用于處理pdf格式的文件,可以將pdf格式的文件轉成txt
HanLP:一個中國開發者開發的漢語處理庫,這個庫很強大,而且完全開源,非常感謝這個開發者,非常感謝開源,只要使用庫,最核心的中文處理功能都可以輕松實現,你要的只是通過Python將實現好的JAVA語言,其核心算法都通過JAVA實現,可以去相應的github上了解該項目,HanLP
自然語言處理
雖說我們已經找到了第三方自然語言處理庫,但是為了更好的理解自然語言處理或跟好的利用這些工具,我覺得一些基本的理念還是要清楚的,下面我來總結一下這幾天學習到的
中文分詞工具
中華文化博大精深,精深到可以搞死我們,不同英文,每個單詞之間都一個空格隔開,這種特性讓英文分詞相對好實現,但是中文不一樣,中文之間是沒有間隔的,而且不同的分詞方式可以帶來完全不一樣的結果,如對春藥店進行分詞,會有兩個完全不同的結果
12

春/ 藥店/春藥/ 店/

正是因為中文具有這些復雜的特性,什么成語啊,一詞多義啊之類的,讓中文分詞變得非常難搞,需要研究出相應的算法,但是市面上已經有一些中文分詞工具可以使用了,除了前面提到的HanLP,還有哈工的LTP、中科院計算所的NLPIR、清華大學的THULAC和Jieba,這些都是比較優秀的分詞工具,因為我不是什么專業人士,所以對這些工具的效率啊,準確性啊無法評估,但是網上有人對這些工具做過評估,發現哈工的LTP和清華的THULAC不錯,但是我使用HanLP,主要是因為HanLP文檔友好,同時社區比較活躍,github上2000多個星,而且時常更新與維護
下面給出中文分詞工具對應的github網址哈工大LTP
中科院計算所NLPIR
清華大學THULAC
jieba
背景知識
在自然語言處理領域有一些很常見的術語,下面解釋一下這些術語
中文分詞
機器是無法識別出一句中文所表達的意義的,所以第一步要進行分詞,目的就是將一段話分割成一個個有意義的詞,要實現這個目的就要有一個優雅的語言模型和語料庫
語言模型
語言模型用大白話說就是一個算法,一個自然語言處理工具一般實現了多種語言模型,通過不同語言模型對內容極進行計算可以獲得不同的結果,所以我們應該根據需求來選擇不同的語言模型,可以閱讀下面的文章加深理解語言模型的基本概念
語料庫
語料庫其實就是經過整理的語言文本,將真實語言中出現的一些詞匯、語言材料整理起來,語料庫的質量十分重要,是分詞工具的根基,網上也有很多開源的語料庫,語料基本格式如下
1234567891011

一一 一一列舉 一一對應 一丁點 一丁點兒 一萬年 一丈紅 一下 一下子 一不做 一不小心 一專多能 一世 一丘之貉

詞向量
首先我們要明白向量的作用。向量是人把自然界的東西抽象出來交給機器處理的東西,基本上可以說向量是人對機器輸入的主要方式了。理解了上面那句話,那么詞向量也就好解釋了,所謂詞向量就是用來將語言中的詞進行數學化的一種方式??梢耘e個例子弄明白詞向量的作用,對于一個詞,可以將它抽象成為一個向量,如(0,1)(最簡單的一個形式),該向量在二維空間就是一條線,那么另外一個詞,同樣可以抽象成一個向量,如(0,2),它同樣在二維空間中是一條線,通過計算兩條線的夾角cos值,就可以判斷出兩個詞之間的相似性,這樣就解決了一個實際的問題,如何判斷兩個句子或兩篇文章的相似性,那么其中詞向量的作用就是將語言抽象成數學化的一種表示。
具體實現
那么下面我們就來看看如何具體實現它
首先明確軟件運行的成功流程,一開始,啟動圖形界面,然后用戶選擇文件,乳溝用戶選擇的是pdf或docx,那么點擊運算程序就進行運算處理,其中的步驟就是將pdf或docx轉成字符串,然后再進行分詞,最后顯示在圖形界面上,如果不是pdf也不是docx,那么給出相應的錯誤提示
PDF TO TXT
首先來完成PDF轉TXT,代碼比較簡單,學習一下如何使用pdfminer則可,基礎用法可以上網查查,這里直接上代碼了
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172

-- coding:utf-8 --from cStringIO import StringIOfrom pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreterfrom pdfminer.converter import TextConverterfrom pdfminer.layout import LAParamsfrom pdfminer.pdfpage import PDFPageimport osimport sys, getoptimport HanLP as ayuimport string# PDF轉txtdef convert(fname, pages=None): if not pages: pagenums = set() else: pagenums = set(pages) output = StringIO() manager = PDFResourceManager() converter = TextConverter(manager, output, laparams=LAParams()) interpreter = PDFPageInterpreter(manager, converter) infile = file(fname, 'rb') for page in PDFPage.get_pages(infile, pagenums): interpreter.process_page(page) infile.close() converter.close() text = output.getvalue() output.close return text# 構造文件路徑,進行分詞處理def convertMultiple(pdfDir, txtDir): if pdfDir == "": pdfDir = os.getcwd() + "http://" for pdf in os.listdir(pdfDir): # iterate through pdfs in pdf directory fileExtension = pdf.split(".")[-1] if fileExtension == "pdf": pdfFilename = pdfDir + pdf text = convert(pdfFilename) # get string of text content of pdf\ res = ayu.GetKeyWord(text,5) res2 = ayu.GetSummary(text,5) res3 = ayu.GetPhrase(text,5) p2tlist = list(); p2tlist.append(res) p2tlist.append(res2) p2tlist.append(res3) return p2tlist# i : info# p : pdfDir# t = txtDirdef main(argv,pdfDir = "",txtDir = ""): try: opts, args = getopt.getopt(argv, "ip:t:") except getopt.GetoptError: print("pdfToT.py -p <pdfdirectory> -t <textdirectory>") sys.exit(2) for opt, arg in opts: if opt == "-i": print("pdfToT.py -p <pdfdirectory> -t <textdirectory>") sys.exit() elif opt == "-p": pdfDir = arg elif opt == "-t": txtDir = arg return convertMultiple(pdfDir, txtDir)if name == "main": main("/home/ayuliao/HanLP/AyuZRYY/word2vec.pdf")

在該Python中,一開始調用main()方法,做一下預處理操作,使用了getopt,可以通過命令行參數來直接傳入PDF文件的路徑,然后就調用convertMultiple()方法,構建pdf文件的具體路徑,將路徑傳入convert()方法,將pdf轉成了相應的字符流,將這些字符流傳遞給分裝好的中文分詞方法,GetKeyWord()方法用于獲取關鍵字,GetSummary()方法用于獲得文章的簡述,GetPhrase()方法獲得文章的短語,將獲得的內容都添加都list中,回傳回去
DOCX TO TXT
接著將word文檔也就是docx類型的文檔轉成字符串,DOCX轉TXT其實比較麻煩,因為docx這個格式比較惡心,但是python太強大了,直接一個庫docx2txt,輕松搞定
1234567891011121314151617

-- coding:utf-8 --import docx2txtimport osimport HanLP as ayu# 將docx轉成字符串并進行分詞def WToT(filePath): text = docx2txt.process(filePath) res = ayu.GetKeyWord(text, 4) res2 = ayu.GetSummary(text, 4) res3 = ayu.GetPhrase(text, 4) w2tlist = list(); w2tlist.append(res) w2tlist.append(res2) w2tlist.append(res3) return w2tlist

直接使用docx2txt庫中的process()方法,將docx文件具體的路徑傳進去就ok了,有興趣可以看看具體是怎么實現的(反正我沒看;))
進行中文分詞
如果你自己仔細看完了HanLP這個開源項目的文檔,就會知道,使用這個庫其實十分簡單,唯一有點麻煩的是,它是java實現的,而我們編寫的python代碼,但HanLP社區非?;钴S,所以這個坑已經有前輩幫我踩過了,可以看https://github.com/yesseecity/hanLP-python這個項目,已經完美實現python調用HanLP了,只是他使用的是python3的版本,所以還是需要自己摸索一下,如果你使用過Jpype這個牛逼的庫,會發現實現python調用Java中的方法也不是特別麻煩,首先你要確定你的電腦中下載并配置了Java,比較HanLP里是Java代碼,要跑到JVM下的,確定java環境沒問題,就可以通過JPype來讓python調用Java中實現的代碼
可以通過下面的代碼測試一下python是否可以連接上Java
1234

from jpype import *startJVM(getDefaultJVMPath())java.lang.System.out.println("Hello ayuliao")shutdownJVM()

如果出現
1234

Hello ayuliaoJVM activity report : classes loaded : 31JVM has been shutdown

說明你可以通過python調用JAVA了,我在windows上嘗試了幾次沒有成功,懷疑過JAVA環境配置問題,但是環境似乎沒問題,所以最終還是在Ubuntu上運行,果然在意開發效率,遠離windows
在正式寫這部分核心代碼前,你需要下載HanLP的Java包,可以去這里下載HanLP Java包
下面就是正式的python代碼了
123456789101112131415161718192021222324252627282930313233

-- coding:utf-8 --from jpype import *import osimport sysreload(sys)# 因為解碼的時候會默認使用系統的編碼,一般是ascii,如果是中文就會出現編碼錯誤,直接將系統編碼改成utf8則可sys.setdefaultencoding('utf8')path = os.getcwd();# print(path)startJVM(getDefaultJVMPath(), "-Djava.class.path="+path+"/hanlp-portable-1.3.4.jar:"+path+"/hanlp", "-Xms1g", "-Xmx1g") # 啟動JVM,Windows需要將冒號:替換為分號;HanLP = JClass('com.hankcs.hanlp.HanLP')# 獲得分詞def GetFenWord(content): return HanLP.segment(content)# 獲得文章關鍵字def GetKeyWord(content,number): return HanLP.extractKeyword(content,number)# 獲得文章簡述def GetSummary(content,number): return HanLP.extractSummary(content,number)# 獲得文章短語def GetPhrase(content,number): return HanLP.extractPhrase(content, number)# 停止JVM運行def ShopJVM(): shutdownJVM()

python編寫圖像界面
python本身自帶有圖像界面庫Tkinter,對應Tkinter,網上的資料比較多,但是我沒有選它,因為感覺有點丑,所以選擇了wxPython發現其實也沒有漂亮到哪里去…..
學習了一下wxPython的用法,其實不難,就是一開始沒有概念,寫起來比較麻煩,但是wxPython封裝的非常好,而且通過wxPython開發圖形化界面還可以使用GUI可視化構建工具wxFormBuilder,有點像Android開發界面布局一樣了,哈哈
使用wxFormBuilder是不錯的選擇,但是我不怎么喜歡,我下載下來看了看看它生成的代碼,知道布局大概該怎么寫后,就不怎么用了,因為通過代碼來控制,感覺可以更精細點,可以看wxPython 基礎使用教程這篇博文來學習使用wxPython和wxFormBuilder
下面直接看代碼
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576

!/usr/bin/python# coding:utf-8import wximport osimport Pdf2Txt as p2timport Word2Txt as w2tdef OnOpen(event): wilcard = "Python source (.pdf)|.pdf|Compiled Python (.pdf)|.pdf|All files (.)|." wilcard = "" dialog = wx.FileDialog(None, "選擇一個文件", os.getcwd(), "", wilcard, wx.OPEN) if dialog.ShowModal() == wx.ID_OK: filename.SetValue(dialog.GetPath()) dialog.Destroy()def OnSave(event): if filename.GetValue() == '': contents.SetValue("必須選擇一個文件才可進行運算?。。?) else: filepath = filename.GetValue() fileExtension = filepath.split(".")[-1] if(fileExtension == "pdf"): res = p2t.main(filepath) if(fileExtension == "docx"): res = w2t.WToT(filepath) if(fileExtension != "pdf" or fileExtension != "docx"): contents.SetValue("只能運算pdf格式和docx格式的文件?。?!") str = "運算開始\n\n" y=0 for r in res: i = 0 for k in r: if(i==0): if(y==0): str += "文章關鍵詞:\n" if(y==1): str += "文章摘要:\n" if(y==2): str += "文章短語:\n" str += "-----"+k+"\n" i = i+1 y = y+1 str +="\n運算結束" contents.SetValue(str)app = wx.App()win = wx.Frame(None, title="文章摘要運算器 ayuliao", size=(600, 400))bkg = wx.Panel(win)loadButton = wx.Button(bkg, label='選擇文件')loadButton.Bind(wx.EVT_BUTTON, OnOpen)saveButton = wx.Button(bkg, label='運算')saveButton.Bind(wx.EVT_BUTTON, OnSave)filename = wx.TextCtrl(bkg)contents = wx.TextCtrl(bkg, style=wx.TE_MULTILINE | wx.HSCROLL)hbox = wx.BoxSizer()hbox.Add(filename, proportion=1, flag=wx.EXPAND)hbox.Add(loadButton, proportion=0, flag=wx.LEFT, border=5)hbox.Add(saveButton, proportion=0, flag=wx.LEFT, border=5)vbox = wx.BoxSizer(wx.VERTICAL)vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)vbox.Add(contents, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, border=5)bkg.SetSizer(vbox)win.Show()app.MainLoop()

在代碼中,我們構建了兩個Button按鈕,并給它設置了相應的點擊函數,分別是從系統中選擇文件(目的是得到文件的路徑)和進行中文分詞運算
結尾
代碼我已經上傳到github,我稱這個項目為GAS(Get Article Summary),方便你直接下載下來使用,別忘了給我一個star,畢竟我也很不容易
GAS下載
有代碼創造樂趣—ayuliao

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容