2019年10月23日更新
应用场景
在搜狗实验室上下载样例数据 搜狗实验室全网新闻数据(SogouCA)
下载解压之后,文件名为news_tensite_xml.dat的数据文件,大小约为1.5GB,里面是类似HTML的标签文本。
将这些标签内的中文提取出来,使用python第三方库 jieba分词,并使用python第三方库wordcloud制作词云图。
实现目标
- 1小时内处理使用代码处理七百行新闻数据并生成词云
- 使用多进程的方法加快数据处理速度,充分利用CPU资源
- 生成的词云图冗杂数据较少,尽量减少如下几种情况的垃圾数据
- 乱码造成的数据(比如锟斤拷…)
- 不能代表新闻热点的数据(省委书记、市委书记、人民网….)
- 停词(不仅、而且、还是…)
- 标点符号和英文
解决方案
根据数据格式和最后要求输出的结果,制定如下解决方案。
- 整个程序需要运行两个.py脚本,一个是文件预处理脚本,处理的方式如下:
- 获取全部标签里面的内容(1100000行)之后,对每一行数据进行去content标签、保留汉字和去重复的操作。(使用filter、正则、和set去重)
- 将这个大文件分为4个小文件(280000行),使用进程并发操作缩短速度。
- 另外一个文件是分词和制作词云脚本,在这个.py文件里面:
- 在自定义词典中获取停词和冗余词汇,导入wordcloud库里面的STOPWORD模块,将停词加入这个模块并传入词云构造方法里面去。
- 开启进程池,进程池大小为4,每个进程处理一个28万行的小文件。每一个进程需要做的是:将每一行数据jieba分词之后放入列表中去,最后返回给main函数。
- 将四个列表合并成字符串之后,放入词云对象,生词词云图片。
具体实现
最后工程为10个文件
- file_processor.py
- wc_generator.py
- splited_data1.dat
- splited_data2.dat
- splited_data3.dat
- splited_data4.dat
- news_tensite_xml.dat
- stop_words.txt
- news_word_cloud.png
其中1、2为.py脚本文件,其余为数据文件和生成的图片
词云图片
代码
file_processor.py
import re
import time
import multiprocessing as mp
tic = time.time()
source_dir = 'news_tensite_xml.dat'
target_dir = 'splited_data'
file_encoding = 'gbk'
line_counter = 0
order = 1
lines = []
with open(source_dir, 'r',encoding='gbk',errors='ignore') as f:
# 遍历这个文件的每一行
for line in f:
# 选用长度>50,并在<content>标签内的文本文件
if len(line)>=50 and line.startswith('<content>') and line.endswith('</content>\n'):
lines.append(line[9:-11]+'\n')
line_counter += 1 # 行数+1
# 长度超过28w,分文件
if line_counter == 280000:
with open(target_dir+ str(order) + ".dat", 'w',encoding=file_encoding,errors='ignore') as f_target:
for data in lines:
f_target.write(data) # 写入
order += 1 #文件计数器+1
line_counter = 0 #行数计数器+1
lines = []
# 处理最后一批行数少于28w行的
with open(target_dir+ str(order) + ".dat", 'w',encoding=file_encoding,errors='ignore') as f_target:
for data in lines:
f_target.write(data) # 写入
toc = time.time()
print('数据去content标签完成,当前'+"已经运行:" + str(toc - tic) + '秒')
tic1 = time.time()
def process_job(file_order):
with open(target_dir+ file_order + ".dat", 'r', encoding=file_encoding, errors='ignore') as f_target:
for data in f_target:
pattern = re.compile(r'[^\u4e00-\u9fa5]')#仅保留中文汉字
chi_content = re.sub(pattern, '', data)
lines.append(chi_content+'\n')
content_set =set(lines)#set去重
with open(target_dir+ file_order + ".dat", 'w', encoding=file_encoding, errors='ignore') as f_target:
for line in content_set:
f_target.write(line)
# 开启进程
p1 = mp.Process(target=process_job,args=('1',))
p2 = mp.Process(target=process_job,args=('2',))
p3 = mp.Process(target=process_job,args=('3',))
p4 = mp.Process(target=process_job,args=('4',))
p1.start()
p2.start()
p3.start()
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()
toc1 = time.time()
print("正则去除非中文完成,当前已经运行:" + str(toc1 - tic1) + '秒')
print("文件预处理总共需要:" + str((toc - tic)+(toc1 - tic1))+'秒')
运行结果
wc_generator.py
import multiprocessing as mp
import time
import wordcloud
from wordcloud import STOPWORDS
import jieba_fast
def process_job(file_order):
lines = []
with open('splited_data' + str(file_order) + '.dat', 'r', encoding='gbk', errors='ignore') as f:
for line in f:
lines += jieba_fast.lcut(line)
# 返回空格作为分隔符的字符串
return ' '.join(lines)
def mult_process():
po = mp.Pool(processes=4) #进程池大小4,每个进程处理一份数据
# 分配文件到进程
multi_res = [po.apply_async(process_job, (i+1,)) for i in range(4)]
# 进程关闭
po.close()
po.join()
all_words = ''# 组装全部进程处理的字符串
for res in multi_res:
all_words+=res.get()
return all_words
def wold_cloud_generator( ):
# 添加停词,对停词词典中的词语不在图中显示
stopwords = STOPWORDS.update(my_stopwords)
# 配置词云图
w = wordcloud.WordCloud(font_path="TTTGB-Medium.ttf",width=1000,height=700,background_color="white",stopwords=stopwords)
w.generate(all_words) # 向wordcloud对象中添加txt文本
w.to_file("news_word_cloud.png") # 将词云输出成图像文件
if __name__ == '__main__':
tic = time.time()
# 计时开始
with open('stop_words.txt', 'r', encoding='utf8', errors='ignore') as f:
my_stopwords = f.read().split('\n')
# 多线程处理数据
all_words = mult_process()
# 将all_words制作词云图
wold_cloud_generator()
# 计时结束
toc = time.time()
print("程序运行时间:"+str(toc-tic)+'秒,约为'+str((toc-tic)//60)+'分钟')
运行结果
总结
通过这次词云图制作,学会了:
- 处理文本读取和写入的错误忽略和字符编码选择
- 多进程处理占用cpu时间较长的程序,加快程序运行速度。
- 了解了正则在处理大字符串的时候,由于时间复杂度的原因处理耗时可能会非常不理想,如果有更好的替代方案就不使用。
- jieba、worldcloud、time、multprocessing库的基本使用方法