2019年10月23日更新

应用场景

在搜狗实验室上下载样例数据 搜狗实验室全网新闻数据(SogouCA)

下载解压之后,文件名为news_tensite_xml.dat的数据文件,大小约为1.5GB,里面是类似HTML的标签文本。

将这些标签内的中文提取出来,使用python第三方库 jieba分词,并使用python第三方库wordcloud制作词云图。

图片.png

实现目标

  • 1小时内处理使用代码处理七百行新闻数据并生成词云
  • 使用多进程的方法加快数据处理速度,充分利用CPU资源
  • 生成的词云图冗杂数据较少,尽量减少如下几种情况的垃圾数据
    • 乱码造成的数据(比如锟斤拷…)
    • 不能代表新闻热点的数据(省委书记、市委书记、人民网….)
    • 停词(不仅、而且、还是…)
    • 标点符号和英文

解决方案

根据数据格式和最后要求输出的结果,制定如下解决方案。

  1. 整个程序需要运行两个.py脚本,一个是文件预处理脚本,处理的方式如下:
    1. 获取全部标签里面的内容(1100000行)之后,对每一行数据进行去content标签、保留汉字和去重复的操作。(使用filter、正则、和set去重)
    2. 将这个大文件分为4个小文件(280000行),使用进程并发操作缩短速度。
  2. 另外一个文件是分词和制作词云脚本,在这个.py文件里面:
    1. 在自定义词典中获取停词和冗余词汇,导入wordcloud库里面的STOPWORD模块,将停词加入这个模块并传入词云构造方法里面去。
    2. 开启进程池,进程池大小为4,每个进程处理一个28万行的小文件。每一个进程需要做的是:将每一行数据jieba分词之后放入列表中去,最后返回给main函数。
    3. 将四个列表合并成字符串之后,放入词云对象,生词词云图片。

具体实现

最后工程为10个文件

  1. file_processor.py
  2. wc_generator.py
  3. splited_data1.dat
  4. splited_data2.dat
  5. splited_data3.dat
  6. splited_data4.dat
  7. news_tensite_xml.dat
  8. stop_words.txt
  9. news_word_cloud.png

其中1、2为.py脚本文件,其余为数据文件和生成的图片

词云图片

图片.png

代码

file_processor.py

  1. import re
  2. import time
  3. import multiprocessing as mp
  4. tic = time.time()
  5. source_dir = 'news_tensite_xml.dat'
  6. target_dir = 'splited_data'
  7. file_encoding = 'gbk'
  8. line_counter = 0
  9. order = 1
  10. lines = []
  11. with open(source_dir, 'r',encoding='gbk',errors='ignore') as f:
  12. # 遍历这个文件的每一行
  13. for line in f:
  14. # 选用长度>50,并在<content>标签内的文本文件
  15. if len(line)>=50 and line.startswith('<content>') and line.endswith('</content>\n'):
  16. lines.append(line[9:-11]+'\n')
  17. line_counter += 1 # 行数+1
  18. # 长度超过28w,分文件
  19. if line_counter == 280000:
  20. with open(target_dir+ str(order) + ".dat", 'w',encoding=file_encoding,errors='ignore') as f_target:
  21. for data in lines:
  22. f_target.write(data) # 写入
  23. order += 1 #文件计数器+1
  24. line_counter = 0 #行数计数器+1
  25. lines = []
  26. # 处理最后一批行数少于28w行的
  27. with open(target_dir+ str(order) + ".dat", 'w',encoding=file_encoding,errors='ignore') as f_target:
  28. for data in lines:
  29. f_target.write(data) # 写入
  30. toc = time.time()
  31. print('数据去content标签完成,当前'+"已经运行:" + str(toc - tic) + '秒')
  32. tic1 = time.time()
  33. def process_job(file_order):
  34. with open(target_dir+ file_order + ".dat", 'r', encoding=file_encoding, errors='ignore') as f_target:
  35. for data in f_target:
  36. pattern = re.compile(r'[^\u4e00-\u9fa5]')#仅保留中文汉字
  37. chi_content = re.sub(pattern, '', data)
  38. lines.append(chi_content+'\n')
  39. content_set =set(lines)#set去重
  40. with open(target_dir+ file_order + ".dat", 'w', encoding=file_encoding, errors='ignore') as f_target:
  41. for line in content_set:
  42. f_target.write(line)
  43. # 开启进程
  44. p1 = mp.Process(target=process_job,args=('1',))
  45. p2 = mp.Process(target=process_job,args=('2',))
  46. p3 = mp.Process(target=process_job,args=('3',))
  47. p4 = mp.Process(target=process_job,args=('4',))
  48. p1.start()
  49. p2.start()
  50. p3.start()
  51. p4.start()
  52. p1.join()
  53. p2.join()
  54. p3.join()
  55. p4.join()
  56. toc1 = time.time()
  57. print("正则去除非中文完成,当前已经运行:" + str(toc1 - tic1) + '秒')
  58. print("文件预处理总共需要:" + str((toc - tic)+(toc1 - tic1))+'秒')

运行结果

图片.png


wc_generator.py

  1. import multiprocessing as mp
  2. import time
  3. import wordcloud
  4. from wordcloud import STOPWORDS
  5. import jieba_fast
  6. def process_job(file_order):
  7. lines = []
  8. with open('splited_data' + str(file_order) + '.dat', 'r', encoding='gbk', errors='ignore') as f:
  9. for line in f:
  10. lines += jieba_fast.lcut(line)
  11. # 返回空格作为分隔符的字符串
  12. return ' '.join(lines)
  13. def mult_process():
  14. po = mp.Pool(processes=4) #进程池大小4,每个进程处理一份数据
  15. # 分配文件到进程
  16. multi_res = [po.apply_async(process_job, (i+1,)) for i in range(4)]
  17. # 进程关闭
  18. po.close()
  19. po.join()
  20. all_words = ''# 组装全部进程处理的字符串
  21. for res in multi_res:
  22. all_words+=res.get()
  23. return all_words
  24. def wold_cloud_generator( ):
  25. # 添加停词,对停词词典中的词语不在图中显示
  26. stopwords = STOPWORDS.update(my_stopwords)
  27. # 配置词云图
  28. w = wordcloud.WordCloud(font_path="TTTGB-Medium.ttf",width=1000,height=700,background_color="white",stopwords=stopwords)
  29. w.generate(all_words) # 向wordcloud对象中添加txt文本
  30. w.to_file("news_word_cloud.png") # 将词云输出成图像文件
  31. if __name__ == '__main__':
  32. tic = time.time()
  33. # 计时开始
  34. with open('stop_words.txt', 'r', encoding='utf8', errors='ignore') as f:
  35. my_stopwords = f.read().split('\n')
  36. # 多线程处理数据
  37. all_words = mult_process()
  38. # 将all_words制作词云图
  39. wold_cloud_generator()
  40. # 计时结束
  41. toc = time.time()
  42. print("程序运行时间:"+str(toc-tic)+'秒,约为'+str((toc-tic)//60)+'分钟')

运行结果

图片.png


总结

通过这次词云图制作,学会了:

  • 处理文本读取和写入的错误忽略和字符编码选择
  • 多进程处理占用cpu时间较长的程序,加快程序运行速度。
  • 了解了正则在处理大字符串的时候,由于时间复杂度的原因处理耗时可能会非常不理想,如果有更好的替代方案就不使用。
  • jieba、worldcloud、time、multprocessing库的基本使用方法