Windows下安裝PyQt4+python2.7+(nltk+wordcloud+jieba+pyinstaller打包)——詞頻分析軟體
最近想寫個小demo,使用python實現文章的詞頻統計,並完成詞雲圖的繪製,然後需要具有互動介面,並且能夠在沒有python環境的電腦下執行,方便不懂程式設計的人直接使用。
主要使用的庫和軟體如下:
- python2.7 實驗演算法程式語言
- PyQt4.8 互動介面的搭建
- nltk 詞頻分析
- jieba 詞語分割
- wordcloud 繪製雲圖
- matplotlib.pyplot 顯示/儲存雲圖
注意,預設上述環境和庫以安裝完畢!
介面結構設計
首先介面如下:
介面使用pyqt4實現,主要要如下功能:
- 2個顯示框:用於顯示讀入資料和輸出結果
- 設定選卡:可以選擇最大顯示詞頻,顯示詞性
- 儲存按鈕:儲存結果(.txt),和顯示儲存雲圖
功能實現
每個功能主要分為2部分,演算法實現和事件繫結
開啟
讀入.txt格式檔案,由於檔案有不同的編碼方式,因此需要對讀入的字元進行解碼處理。主要程式碼如下:
def OpenData(self):
fname = QtGui.QFileDialog.getOpenFileName(self)
with open(fname, 'r') as f:
self.__data = f.read().replace('\n','').replace(' ','' )
# show data in window
if self.__data != "":
sample_str = self.__data[:10] if len(self.__data) > 10 else self.__data
type = chardet.detect(sample_str)
try:
self.inputData.setText(self.__data.decode(type["encoding"]))
finally :
self.inputData.setText(self.__data.decode('gb18030'))
使用import chardet
庫對字元編碼方式進行識別,可以針對不同的編碼格式進行處理(但是對於編碼中有特殊字元的處理不好!)
然後PyQt進行事件關聯:
self.openData.clicked.connect(self.OpenData)
其中,openData
為開啟按鈕的ID,OpenData
為實現開啟按鈕的方法。
分析
該按鈕主要實現對讀入的資料進行處理,最後以詞頻的方式顯示出來,需要使用到jieba
進行分詞,使用nltk進行詞頻統計,主要程式碼如下:
def AnalysisWord(self):
# analysis text data
lztext = self.fontsTools.getText(self.__data)
tokenstr = nltk.word_tokenize(lztext)
self.__resultFDOrigin = nltk.FreqDist(tokenstr)
self.outputResult.setText(self.DealResult())
def DealResult(self):
# deal with result
listKVL = [] #save key val flag
resultFDDelete = nltk.FreqDist() # delete result data of freq dist
orderFdist = enumerate(sorted(self.__resultFDOrigin.iteritems(), key=lambda x: (x[1], x[0]), reverse=True))
for index, (key, val) in orderFdist:
words = pseg.cut(key)
for w in words:
if (w.flag in self.__poSpeech) and (val > self.__maxFreq):
listKVL.append(key)
listKVL.append(str(val))
listKVL.append(w.flag)
listKVL.append('\n')
else:
resultFDDelete.setdefault(key, val)
break # forced end
# show progress
self.ShowProgress((index+1)/len(self.__resultFDOrigin)*100)
self.__resultFDCurrent = self.__resultFDOrigin - resultFDDelete
return '\t\t'.join(listKVL).replace('\t\t\n\t\t','\n')
首先呼叫fontsTools.getText()
方法進行分析,該方法主要使用jieba
進行處理,完整程式碼見WordCloudAnalysis。DealResult()
方法主要實現結果的篩選(詞頻、詞性),把該方法獨立出來是方便之後不同引數選擇時可以呼叫。
然後PyQt進行事件關聯:
self.analysisWord.clicked.connect(self.AnalysisWord)
其中,analysisWord
為開啟按鈕的ID,AnalysisWord
為實現開啟按鈕的方法。
設定
設定欄裡有詞頻選擇,使用Spin Box
元件實現。詞性選擇,使用Check Box
元件實現。
詞頻選擇和詞性選擇實現比較簡單,但是對於不同的詞性進行分類比較繁瑣。詳細程式碼見WordCloudAnalysis
儲存
儲存按鈕只需要把顯示結果框中的內容儲存下來就好:
def SaveResult(self):
fname = QtGui.QFileDialog.getSaveFileName(self, filter="Text Files (*.txt);;All Files (*)")
with open(fname, 'w') as f:
f.write(self.outputResult.toPlainText())
雲圖
使用wordcloud
庫把處理後詞頻繪製雲圖即可,這也是為什麼需要一直維護詞頻的原因,方便繪製雲圖:
def CalculationCloud(self):
font = r'simfang.ttf'
my_wordcloud = WordCloud(collocations=False, font_path=font, width=1400, height=1400,
margin=2).generate_from_frequencies(self.__resultFDCurrent)
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()
進度條
實現也非常簡單,使用Progress Bar
控制元件,然後傳入引數設定即可:
def ShowProgress(self, value):
self.progressAnalysis.setValue(value)
pyinstaller打包
以上功能對於一個程式設計師來說是非常容易的,但是對於不懂程式設計的來說,就比較困難,特別是其電腦沒用相關環境,無法執行(有環境也不會來折騰個介面了^_^!)。因此使用pyinstaller進行打包處理,使其在仍和電腦上可以執行。
pyinstaller的安裝和使用不多說了,見官方文件:pyinstaller manual
打包時程式碼也簡單:
pyinstaller --onefile xxx.py
打包是簡單,但是當你使用較多的其他庫時,會發生一大堆問題,同時也是打包一時爽,開啟5分鐘。主要遇到的問題和解決方法接下來指出。
pyinstaller打包問題處理
問題主要是針對pyinstaller對jieba
、wordcloud
、nltk
庫打包時出現的問題。
1. No such or directory: u’C:\user\LOOP\AppData\Local\Temp\_MEI12~1\jieba\dict.txt’
這是用於jieba
中呼叫了dict.txt
檔案,而pyinstaller在打包時不會自動把該檔案打包,定位到出現錯誤的檔案Lib\site-packages\jieba\_compat.py
的8行,可以看到如下:
try:
import pkg_resources
get_module_res = lambda *res: pkg_resources.resource_stream(__name__,
os.path.join(*res))
except ImportError:
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(__file__), *res)), 'rb')
該方法就是在當前檔案 (_compat.py) 目錄作為get_module_res
的目錄,在pyinstaller manual文件中解釋如下:
也就是說使用__file__
的相對路徑在打包完成後會變成絕對路徑,並且以_MEIxxxxx
檔名儲存在快取資料夾中。並且也給出解決方案,可以使用sys.executable
也就是當前的執行目錄,就是執行打包好的exe檔案目錄,如果是在使用python時,就是呼叫的python路徑。
因此,解決方法如下:
try:
import pkg_resources
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(sys.executable), *res)), 'rb')
except ImportError:
get_module_res = lambda *res: open(os.path.normpath(os.path.join(
os.getcwd(), os.path.dirname(__file__), *res)), 'rb')
同理,在打包wordcloud
也會出現相似的問題,定位到相關檔案(Lib\site-packages\wordcloud\wordcloud.py
)第29行:
FONT_PATH = os.environ.get("FONT_PATH", os.path.join(os.path.dirname(__file__),
"DroidSansMono.ttf"))
STOPWORDS = set([x.strip() for x in open(
os.path.join(os.path.dirname(__file__), 'stopwords')).read().split('\n')])
很明顯是__file__
問題,修改如下:
FONT_PATH = os.environ.get("FONT_PATH", os.path.join(os.path.dirname(sys.executable),
"DroidSansMono.ttf"))
STOPWORDS = set([x.strip() for x in open(
os.path.join(os.path.dirname(sys.executable), 'stopwords')).read().split('\n')])
注意:以上修改只是針對使用pyinstaller打包時,因為改變了其檔案路徑,在除錯和執行時會出錯
最後把dict.txt
和stopwords
檔案拷貝到與生成的.exe檔案同一目錄即可。
2. Please use the NLTK Downloader to obtain the resource:
該錯誤是由於使用了nltk_data()
, 打包時也沒有自動對其打包,因此增加nltk_data
的搜錯路徑,然後把該問價複製到該路徑下即可。
nltk.data.path.append('./nltk_data')
就是以當前.exe目錄為搜尋路徑,把nltk_data
放在當前目錄即可。
3. Inter MKL FATAL ERROR:Cannot load mk2_avx.dll or mk2_def.dll
缺少這兩個動態連結庫,複製過來即可。