1.原始语料获取
http://download.wikipedia.com/zhwiki/latest/zhwiki-latest-pages-articles.xml.bz2下载语料。
2.使用Wikipedia Extractor抽取正文文本
拿到wikiextractor
git clone https://github.com/attardi/wikiextractor.git wikiextractor
到拿到的项目目录下,安装
python setup.py install
用WikiExtractor.py处理维基百科语料
python WikiExtractor.py -b 1024M -o extracted zhwiki-latest-pages-articles.xml.bz2
等半小时左右处理完,该目录下生成extracted文件,打开里面AA文件夹,发现里面有wiki_00和wiki_01两个文件,就是处理后的语料。处理后两个文件一个1G,一个100多M,仍然很大打不开,可以写代码读取文件的一小部分看。格式大概如下:
<doc id="5202230" url="https://zh.wikipedia.org/wiki?curid=5202230" title="AMX 10 RC裝甲車">
AMX 10 RC裝甲車
AMX 10 RC裝甲車是一款由法國GIAT公司製造的輕型輪式偵察裝甲車,目前共有約300輛服役於法國陸軍,另有108輛外銷至摩洛哥、12輛外銷至卡達。AMX 10 RC名稱中的RC是法語"Roues-Canon"的縮寫,意為輪式火炮。
值得注意的是,AMX 10 RC裝甲車與AMX-10P步兵戰車不應被混淆;它們除了使用共通的動力套件外,其他設計及在戰場上的角色定位都大不相同。AMX 10 RC是兩棲裝甲車,並擁有相當優秀的機動性能。它通常被用於於危險環境中執行偵察任務,或是提供直接火力支援。
AMX 10 RC的最初設計工作始於1970年;量產作業於1976年展開。第一輛AMX 10 RC於1981年交付予法國陸軍第2驃騎兵團(法語:2e régiment de hussards)。該車的特色是一門裝載於鋁製焊接炮塔上且火力強大的GIAT 105毫米主炮,以及一具用以協助火炮瞄準的COT
AC火控系統。炮塔內部可容納三名乘員,而駕駛席則位於底盤前方。該車的六個路輪皆可被獨立驅動;車體上另外安裝了滑動轉向裝置來協助車輛轉向。
AMX 10 RC的105毫米線膛炮可發射四種炮彈,分別為:尾翼穩定脫殼穿甲彈、高爆彈、反戰車高爆彈以及煙霧彈。105毫米的尾翼穩定脫殼穿甲彈可以在2000公尺的距離外穿透NATO裝甲標靶中的第三層重甲。
在AMX 10 RC的服役生涯中,法國軍方已經對其進行過多次的現代化改裝。其中最值得注意的,是一款新的戰場管理系統終端機。當法國於1991年參與波斯灣戰爭時,AMX 10 RC更加裝了許多附掛裝甲,以及反戰車飛彈誘導干擾系統。另一項曾被提出的改良方案是以NATO規格的105毫米火炮替換法國原產的GI
AT 105毫米線膛炮,這是由於法國原裝的105毫米炮無法發射NATO的標準彈藥,但這項改良計畫終究沒有實行。法國軍方亦於AMX 10 RC上加裝了從已退役的AMX-30B2主戰坦克上取下的熱成像系統。另外,AMX 10 RC也擁有中央路輪充氣系統,用以提供車輛行駛於軟性地形(如泥濘路面)時更好的抓
地能力。所有的AMX 10 RC都安裝了核生化防護系統,這使它能於被放射線汙染的環境中執行偵察任務。
GIAT目前已不再製造AMX 10 RC裝甲車。
2010年,Nexter集團(即前GIAT)已將256輛AMX 10 RC裝甲車改裝至RCR規格(法語:Rénové,意為裝修),一種能整合多種系統的程式,另外還增加了額外的附加裝甲、主動防禦系統、SIT V1戰場管理系統(法語:Système d'Information Terminal,意為資訊
系統終端機)、ASP發射裝置(發射Galix煙霧彈)、改良核生化防護系統以及懸吊系統,並改良變速箱及泰勒斯通訊及安全公司的PR4G VS4戰術通訊系統。整體整合是由法國陸軍中央軍備局(法語:Direction Centrale du Matériel de l'Armée de Terre, DCM
AT)主導的。
</doc>
<doc id="5202245" url="https://zh.wikipedia.org/wiki?curid=5202245" title="密钥延期">
密钥延期
密钥延期是电影版权方通过延长电子密钥的有效期,来延长影片上映时间的一种手段。
院线在影片公映前可以获得加密的数字拷贝文件,该文件的版权受到密钥保护。只有在公映时获得密钥,才可实现正常放映,从而避免了片源提前泄露被盗版的可能性。密钥不仅可以用于文件解码,其本身还包含了档期信息,自带时间属性,可控制影片在影院的上映时间。中国发行放映协会技术分会副会长马秉超将密钥解释为:“一部电影
在一台放映机上放映时所对应的‘钥匙’,并且必须是一一对应无误,这是保证电影安全的必需要素。”每个影厅的服务器,都需要各自匹配的密钥,才能顺利放映。
在中国大陆,密钥由专门的单位制作,制作密钥只授权两家,一是国家新闻出版广电总局数字节目管理中心,另一个是中影股份数字电影发行(院线)公司。在电影上映前,中影股份数字电影发行(院线)公司会将密钥公布于官网的下载区,供电影院下载。一般而言,密钥的有效期为1个月,具体到每部影片,都会有所不同。
密钥是否延期、延期多久,由片方或发行方自行决定。延期需要征得国家新闻出版广电总局的同意,此外因为需要制作一批新的密钥,还需向上述两家单位缴纳额外的延期费用(一般称作服务费),每部影片的费用并不一样。
密钥延期的影片可以晚于同档期影片下线,对于院线电影来说,上映时间越长,通常也意味着更高的票房。但延期放映的票房能否成功取决于很多因素,包括影片的热度、口碑,以及延期后的档期有没有强大的竞争对手。
可以看到,语料繁简掺杂。需要将繁体转为简体。
3.繁简转换
使用opencc工具。 到https://bintray.com/package/files/byvoid/opencc/OpenCC下载opencc-1.0.1-win64.7z。解压到自定义目录,并把刚刚生成的wiki_00和wiki_01移到该目录下。控制台进入该目录然后输入:
opencc -i wiki_00 -o res00 -c t2s.json
opencc -i wiki_01 -o res01 -c t2s.json
每条命令大约等一分钟左右,wiki_00、wiki_01分别在该目录下生成对应的简体中文版本res00和res01。
4.特殊字符替换
# -*- coding: utf-8 -*-
import os
import re
import codecs
def replace_func(input_file):
p1 = re.compile(r'-\{.*?(zh-hans|zh-cn):([^;]*?)(;.*?)?\}-')
p2 = re.compile(r'[(][,;。?!\s]∗[)][,;。?!\s]∗[)]')
p3 = re.compile(r'[「『]')
p4 = re.compile(r'[」』]')
outfile = codecs.open(input_file + "_updated", 'w', 'utf-8')
with codecs.open(input_file, 'r', 'utf-8') as myfile:
for line in myfile:
line = p1.sub(r'\2', line)
line = p2.sub(r'', line)
line = p3.sub(r'“', line)
line = p4.sub(r'”', line)
outfile.write(line)
outfile.close()
def run():
data_path = 'D:\\MyData\\HUYI5\\opencc-1.0.1-win64\\'
data_names = ['res00', 'res01']
for data_name in data_names:
replace_func(data_path + data_name)
print('{0} has been processed !'.format(data_name))
if __name__ == '__main__':
run()
这样就得到了res00_updated和res01_updated两个处理后的文件。
5.分句、分词
先将长文本按标点符号分为短句,对每个短句用ansj分词,去停用词,短句分词结果小于5的去掉,一个短句的分词结果占一行,词用空格隔开。java代码如下:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.library.UserDefineLibrary;
import org.ansj.splitWord.analysis.ToAnalysis;
/**
* @author 作者 E-mail: Yi
* @date 创建时间:2018年5月30日 下午2:02:01
*/
public class SegmentTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
FileWriter writer;
writer = new FileWriter("D:\\我的目录\\输出结果.txt", true);
BufferedWriter bw = new BufferedWriter(writer);
String splitRule = "[\\?!:,.,。?!: ;;、]";
Set<String> stopwords = readFile2Set("D:\\我的目录\\中文停用词.txt");
InputStream in = null;
try {
in = new FileInputStream("D:\\我的目录\\res01_updated");
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String str = "";
while ((str = br.readLine()) != null) {
if(isDocTag(str)) continue;
String[] phrases = str.split(splitRule);
for(String phrase : phrases){
List<String> words = cut(phrase);
List<String> line = new LinkedList<>();
for(String word : words){
if(!stopwords.contains(word)){
line.add(word);
}
}
if(line.size() < 5) continue;
String res = "";
for(String word : line){
res += word + " ";
}
res = res.substring(0, res.length() - 1);
bw.write(res + "\n");
}
}
br.close();
} catch (Exception e) {
}
bw.close();
writer.close();
}
//判断该行是否有doc标签
public static boolean isDocTag(String sentence){
String pattern = "</?doc.*>";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(sentence);
if (m.find()) return true;
return false;
}
//读取文件为set
public static Set<String> readFile2Set(String inputpath) {
Set<String> data = new HashSet<String>();
InputStream in = null;
try {
in = new FileInputStream(inputpath);
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String str = "";
// read
while ((str = br.readLine()) != null) {
data.add(str);
}
br.close();
} catch (Exception e) {
}
return data;
}
//切词并存入List
public static List<String> cut(String str) throws Exception{
List<String> wordList = new ArrayList<String>();
Result result = ToAnalysis.parse(str);
List<Term> terms = result.getTerms();
for(Term term : terms){
String word = term.getRealName();
wordList.add(word);
}
return wordList;
}
}
6.训练word2vec模型
用分词后的得到的文件作输入,训练word2vec模型。会跑一天左右,要耐心。
import org.deeplearning4j.models.embeddings.loader.WordVectorSerializer;
import org.deeplearning4j.models.word2vec.Word2Vec;
import org.deeplearning4j.text.sentenceiterator.BasicLineIterator;
import org.deeplearning4j.text.sentenceiterator.SentenceIterator;
import org.deeplearning4j.text.tokenization.tokenizerfactory.DefaultTokenizerFactory;
import org.deeplearning4j.text.tokenization.tokenizerfactory.TokenizerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
public class TrainWord2VecModel {
private static Logger log = LoggerFactory.getLogger(TrainWord2VecModel.class);
public static void main(String[] args) throws IOException {
String corpusPath = "D:\\嘿嘿\\words.txt";
String vectorsPath = "D:\\嘿嘿\\word2vec";
log.info("Start Training...");
long st = System.currentTimeMillis();
log.info("Load & vectorize sentences...");
SentenceIterator iter = new BasicLineIterator(new File(corpusPath));
TokenizerFactory t = new DefaultTokenizerFactory();
// t.setTokenPreProcessor(new CommonPreprocessor());
log.info("Building model...");
Word2Vec vec = new Word2Vec.Builder()
.minWordFrequency(5) //小于该词频的词不纳入
.epochs(50) //迭代次数
.layerSize(300) //词向量大小
.seed(42)
.windowSize(5)
.iterate(iter)
.tokenizerFactory(t)
.build();
log.info("Fitting word2vec model...");
vec.fit();
log.info("Writing word vectors to text file...");
// WordVectorSerializer.writeWord2VecModel(vec, vectorsPath);
WordVectorSerializer.writeWordVectors(vec, vectorsPath);
log.info("Closest words:");
Collection<String> bydWordList = vec.wordsNearest("洗碗", 10);
Collection<String> changanWordList = vec.wordsNearest("电商", 10);
System.out.print(bydWordList);
System.out.println(changanWordList);
log.info("10 words closest to '洗碗': {}", bydWordList);
log.info("10 words closest to '电商': {}", changanWordList);
long et = System.currentTimeMillis();
log.info("Training is completed, and the time taken is " + (et-st) + " ms.");
System.out.println("Training is completed, and the time taken is " + (et-st) + " ms.");
}
}
参考:
http://licstar.net/archives/262
https://blog.csdn.net/wangyangzhizhou/article/details/78348949
http://www.mamicode.com/info-detail-1699780.html
https://blog.csdn.net/u013421941/article/details/68947622