代码:https://github.com/Kingsea442/nlp_word/tree/master
生成词汇top1000:http://www.wanglh.top/post/blog/kao-yan-ying-yu-gao-pin-ci-hui
使用wordcloud分析前1000个重要词汇生成的词云图。
核心思想
想法:首先一般阅读中出现的不认识的词汇可能就那么几个不常见的,所以过滤掉常见的词,比如the,and,if,you等,剩下的应该就是比较重要的词汇。所以可以直接采用TF-IDF简单粗暴提取英语阅读中的重要词汇。
TF-IDF算法介绍
TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。
TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
TF是词频(Term Frequency)
词频(TF)表示词条(关键字)在文本中出现的频率。这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。
向文件频率 (IDF) :某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到。如果包含词条t的文档越少, IDF越大,则说明词条具有很好的类别区分能力。
:
import re
p1 = re.compile(r'-\{.*?(zh-hans|zh-cn):([^;]*?)(;.*?)?\}-')
p2 = re.compile(r'[(][: @ . , ?!\s][)]')
p3 = re.compile(r'[「『]')
p4 = re.compile(r'[\s+\.\!\/_,$%^*(+\"\')]+|[+——()?【】“”!,。?、~@#¥%……&*()0-9 , : ; \-\ \[\ \]\ ]')
txt = p1.sub(r' ', txt)
txt = p2.sub(r' ', txt)
txt = p3.sub(r' ', txt)
txt = p4.sub(r' ', txt)
return txt
分词
采用nltk对文档进行分词。
from nltk.tokenize import word_tokenize
tokenize_words = word_tokenize(txt, language='english', preserve_line=True)
自定义停用词库
使用nltk自带的停用词只能过滤掉一些语气词比如emm,还远不能过滤掉我们想过滤掉的词比如 the,and,he,you这些简单词汇。从两方面处理,假设文档出现次数最多的词肯定不是我们不认识的词,可以过滤掉,假设4个字母一下的单词我们也都认识,可以直接过滤掉。这样只保留长度在四个以上,出现次数并不是很多的单词。然后用自己准备的停用词库,再去分词。
分析词的原型
分完词之后,取词的原型进行后续的计算,有待优化。
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize('cats')
# 输出cat
统计词频和TF和逆文档频率IDF
采用nltk的FreqDist生成词典,进一步分析单词,算出tf-idf,最终得到一个分值。
from __future__ import division
import math
import os
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
import constant
from file_utils import FileUitls
from stopwords import PapperStopWords
from txt_utils import TxtUtils
def dist(txt):
tokenize_words = word_tokenize(txt, language='english', preserve_line=True)
filter_tokenize_word = [w for w in tokenize_words if not w in stop_words]
return nltk.FreqDist(filter_tokenize_word)
def count_word_document(word, document_freq_dists):
count = 0
for fd in document_freq_dists:
if fd.get(word) is not None:
# count = count + 1
count = count + fd.get(word)
return count
def top200(word_dict):
for k, v in word_dict.items():
if v > 0.01 and v < 0.1:
print(k, v)
if __name__ == '__main__':
file_parent_path = constant.paper_data_file_path
stop_words = set(stopwords.words('english'))
for word in PapperStopWords.load_stop_words():
stop_words.add(word)
dir = os.listdir(file_parent_path)
document_count = len(dir)
print(document_count)
freq_dist = []
for f in dir:
f_content = open(file_parent_path + f, 'r').read()
f_content = TxtUtils.clean_txt(f_content)
fd = dist(f_content)
freq_dist.append(fd)
word_tf_idf = {}
word_freq = {}
for fd in freq_dist:
items = fd.items()
total_word_count = fd.N()
for k, v in items:
tf = v / total_word_count
word_in_document_count = count_word_document(k, freq_dist)
idf = math.log((document_count / (word_in_document_count + 1)))
tf_idf = tf * idf + math.log(min(10, len(k)))
word_tf_idf[k] = [tf, idf, tf_idf]
result = sorted(word_tf_idf.items(), key=lambda d: d[1][2])
result.reverse()
lemmatizer = WordNetLemmatizer()
for k, v in result:
k = lemmatizer.lemmatize(k)
if len(k) >= 4:
word_freq[k] = v[2]
print(k, v)
final_result = ''
for k, v in word_freq.items():
line = str.format('{} {}\n', k, round(v, 7))
final_result = final_result + line
FileUitls.write(final_result, constant.result_file)
一般单词越长,一般会越陌生,所以这里可以把单词的长度作为一个影响因素计算到单词总分值中,这样最后排序,保存结果
生成词云
用wordcloud可以定制生成词语。
import src.constant
from file_utils import FileUitls
lines = FileUitls.reade_lines(src.constant.result_file)
result_cn = ''
word_freq = {}
for l in lines:
l = str.replace(l, '\n', '')
split = l.split(' ')
word_freq[split[0]] = float(split[1])
w = WordCloud(background_color='white', width=800, height=450, scale=1.5)
w.generate_from_frequencies(word_freq)
w.to_file("top_word.jpg")
根据给定的图片生成词云
import FileUitls
from wordcloud import WordCloud, ImageColorGenerator
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
lines = FileUitls.reade_lines(src.constant.result_file)
result_cn = ''
word_freq = {}
for l in lines[0:500]:
l = str.replace(l, '\n', '')
split = l.split(' ')
word_freq[split[0]] = float(split[1])
print(word_freq)
color_mask = np.array(Image.open("/Users/wlh/asea/workspace/python/nlp_word/data/wlh.png"))
w = WordCloud(mask=color_mask, background_color='white', width=1000, height=1000)
w.generate_from_frequencies(word_freq)
image_colors = ImageColorGenerator(color_mask)
# 在只设置mask的情况下 会得到一个拥有图片形状的词云 axis默认为on 会开启边框
plt.imshow(w, interpolation="bilinear")
plt.axis("on")
plt.savefig("a.jpg")
# 直接在构造函数中直接给颜色 这种方式词云将会按照给定的图片颜色布局生成字体颜色策略
plt.imshow(w.recolor(color_func=image_colors), interpolation="bilinear")
plt.axis("on")
plt.savefig("w_i.jpg")
w.to_file("w.jpg")
单词翻译
直接调用百度api,翻译top n的单词即可。
待优化
使用nltk分析单词命名实体,去掉单词中人名,地名等专有名词。
代码