获取并处理中文维基百科语料
By 苏剑林 | 2017-01-06 | 108865位读者 |中文语料库中,质量高而又容易获取的语料库,应该就是维基百科的中文语料了,而且维基百科相当厚道,每个月都把所有条目都打包一次(下载地址在这里:https://dumps.wikimedia.org/zhwiki/),供全世界使用,这才是真正的“取之于民,回馈于民”呀。遗憾的是,由于天朝的无理封锁,中文维基百科的条目到目前只有91万多条,而百度百科、互动百科都有千万条了(英文维基百科也有上千万了)。尽管如此,这并没有阻挡中文维基百科成为几乎是最高质量的中文语料库。(百度百科、互动百科它们只能自己用爬虫爬取,而且不少记录质量相当差,几乎都是互相复制甚至抄袭。)
门槛 #
尽量下载很容易,但是使用维基百科语料还是有一定门槛的。直接下载下来的维基百科语料是一个带有诸多html和markdown标记的文本压缩包,基本不能直接使用。幸好,已经有热心的高手为我们写好了处理工具,主要有两个:1、Wikipedia Extractor;2、gensim的wikicorpus库。它们都是基于python的。
然而,这两个主流的处理方法都不能让我满意。首先,Wikipedia Extractor提取出来的结果,会去掉{{}}标记的内容,这样会导致下面的情形
西方语言中“数学”(;)一词源自于古希腊语的()
这是因为括号里的词带有{{}}标记,被清空了;而按照网上的教程,直接用gensim.corpora.wikicorpus.WikiCorpus处理,问题更严重,因为它连所有标点都去掉了。对于追求一份高质量语料库的、具有强迫症的笔者来说,这都是不能接受的。因此,自己动手结合gensim,写了一个处理脚本。
代码 #
from gensim.corpora.wikicorpus import extract_pages,filter_wiki
import bz2file
import re
import opencc
from tqdm import tqdm
import codecs
wiki = extract_pages(bz2file.open('zhwiki-latest-pages-articles.xml.bz2'))
def wiki_replace(d):
s = d[1]
s = re.sub(':*{\|[\s\S]*?\|}', '', s)
s = re.sub('<gallery>[\s\S]*?</gallery>', '', s)
s = re.sub('(.){{([^{}\n]*?\|[^{}\n]*?)}}', '\\1[[\\2]]', s)
s = filter_wiki(s)
s = re.sub('\* *\n|\'{2,}', '', s)
s = re.sub('\n+', '\n', s)
s = re.sub('\n[:;]|\n +', '\n', s)
s = re.sub('\n==', '\n\n==', s)
s = u'【' + d[0] + u'】\n' + s
return opencc.convert(s).strip()
i = 0
f = codecs.open('wiki.txt', 'w', encoding='utf-8')
w = tqdm(wiki, desc=u'已获取0篇文章')
for d in w:
if not re.findall('^[a-zA-Z]+:', d[0]) and d[0] and not re.findall(u'^#', d[1]):
s = wiki_replace(d)
f.write(s+'\n\n\n')
i += 1
if i % 100 == 0:
w.set_description(u'已获取%s篇文章'%i)
f.close()
注释 #
可见,代码的主要部分是正则表达式。首先通过bz2file直接不解压来读取下载下来的语料,然后用gensim的extract_pages来提取每个页面,提取后,先处理页面的一些特殊的、非文本的标记,然后将部分有用的{{}}标记替换为[[]],因为[[]]标记不会被完全清空(具体原理读者得自己测试了),然后用gensim的filter_wiki函数直接清理,接着再处理一下换行的问题,最后通过opencc将繁体转化为简体。
后面的循环中,re.findall('^[a-zA-Z]+:', d[0])这个条件是去掉那些帮助页面,re.findall(u'^#', d[1])这个条件是去掉重定向的页面,最后得到大概就是91.9万个页面。tqdm是用来显示进度的,这个必须有。程序在我的机器上运行了大概40分钟,得到了1.5G左右的纯文本语料。运行时间不重要,因为预处理是一次性的。
值得注意的是,opencc不能用sudo apt-get install opencc来安装,这个默认版本太低,要用源码编译安装,然后pip install opencc安装python接口,这时候在python中调用opencc可能会报“段错误”,这时候要运行
cp /usr/lib/libopencc.so.1.0.0 /usr/lib/x86_64-linux-gnu/
副产品 #
上面提到了重定向,重定向意味着两个词具有同样的意思,这样我把中文维基里边所有的重定向都提取出来了,做了个匹配表。也就是说,词表中每一行的两个词都是相同含义的。这算是一个副产品了。
基于中文维基重定向的同义词表:wiki_cn_mapping.7z
转载到请包括本文地址:https://www.kexue.fm/archives/4176
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Jan. 06, 2017). 《获取并处理中文维基百科语料 》[Blog post]. Retrieved from https://www.kexue.fm/archives/4176
@online{kexuefm-4176,
title={获取并处理中文维基百科语料},
author={苏剑林},
year={2017},
month={Jan},
url={\url{https://www.kexue.fm/archives/4176}},
}
May 24th, 2017
请帮忙看看,单独测试繁体转简体是ok的。
但return opencc.convert(s).strip()好像缺什么包
感谢!
D:\Anaconda2\lib\site-packages\gensim\utils.py:855: UserWarning: detected Windows; aliasing chunkize to chunkize_serial
warnings.warn("detected Windows; aliasing chunkize to chunkize_serial")
已获取0篇文章: 0it [00:00, ?it/s]Traceback (most recent call last):
File "D:/mycode/nlp/wiki_cn/process_wiki_kexue.py", line 31, in
s = wiki_replace(d)
File "D:/mycode/nlp/wiki_cn/process_wiki_kexue.py", line 23, in wiki_replace
return opencc.convert(s).strip()
AttributeError: 'module' object has no attribute 'convert'
可以试试这个 opencc.OpenCC("t2s").convert(s).strip()
这个办法可行
以上为目前 20200815 可以运行的代码(最新的opencc已经修改了接口)
from gensim.corpora.wikicorpus import extract_pages,filter_wiki
import bz2file
import re
import opencc
from tqdm import tqdm
import codecs
wiki = extract_pages(bz2file.open('zhwiki-latest-pages-articles.xml.bz2'))
def wiki_replace(d,converter):
[\s\S]*?s = d[1]
s = re.sub(':*{\|[\s\S]*?\|}', '', s)
s = re.sub('
', '', s)
s = re.sub('(.){{([^{}\n]*?\|[^{}\n]*?)}}', '\\1[[\\2]]', s)
s = filter_wiki(s)
s = re.sub('\* *\n|\'{2,}', '', s)
s = re.sub('\n+', '\n', s)
s = re.sub('\n[:;]|\n +', '\n', s)
s = re.sub('\n==', '\n\n==', s)
s = u'【' + d[0] + u'】\n' + s
return converter.convert(s).strip()
i = 0
f = codecs.open('wiki.txt', 'w', encoding='utf-8')
w = tqdm(wiki, desc=u'已获取0篇文章')
converter = opencc.OpenCC('t2s.json')
for d in w:
if not re.findall('^[a-zA-Z]+:', d[0]) and d[0] and not re.findall(u'^#', d[1]):
s = wiki_replace(d,converter)
f.write(s+'\n\n\n')
i += 1
if i % 100 == 0:
w.set_description(u'已获取%s篇文章'%i)
f.close()
好的,谢谢。
您好!我在尝试您的代码之后发现不能正常输出到wiki.txt中。(https://i.loli.net/2020/12/18/H4TvuJsNgwfXkRy.png),您能帮忙看一下原因吗,感谢!
不能,请自行debug,抱歉。
June 12th, 2017
https://github.com/skydark/nstools/tree/master/zhtools
繁转简可以用这个
December 19th, 2017
不错!副产品的脚本有吗?
March 19th, 2018
为嘛跑起来就死了!
March 20th, 2018
苏神,纯中文的能不能分享一份!
当然不能~
都是自己下载自己处理,我也没整理好的文件~
September 29th, 2018
副产品代码可否分享一下?
June 17th, 2020
有针对表格进行特殊处理吗,使用wikiextractor还有个问题就是,会有大量表格相关的文本
没有
October 9th, 2020
太优秀了,感谢,点赞~
September 17th, 2021
苏神的匠心精神真是值得点赞,谢谢
谢谢
November 5th, 2021
我观察到一个现象,现不确定是bug还是有意为之。
数据源:zhwiki-20211101-pages-articles-multistream.xml.bz2
我在提取后的数据中使用如下命令检索
shell:cat zhwiki_2.txt |grep -nw 即时天气预报
搜索结果为:24297394:* 即时天气预报(ConvLSTM)
shell:cat zhwiki_2.txt |grep -nw 国土安全(Angela)
搜索结果为:26595927:* 国土安全(Angela)
凭直觉应该能看出来上面的中英文相关性程度不高,于是我直接取源文件检索
shell:cat zhwiki-20211101-pages-articles-multistream.xml |grep -nw 即时天气预报
搜索结果:无
对于另一个例子,【国土安全】有很多返回结果,于是我分两次检索
cat zhwiki-20211101-pages-articles-multistream.xml |grep -nw 国土安全|grep Angela
搜索结果:无
你的意思是,处理后的文件出现了原始文件没有的词?
从表面上来看是这样,而且我可以确定甚至不在一行。
-----
这个邮箱是比较迷惑的,我留了邮件,但是没收到通知(垃圾邮件类别中也没有....)
该词在原来的文件里可能被一些标记符号分隔开了
-----
你是说没有收到回复提醒邮件吗?暂时没搞定这个功能~