利用Word2Vec判断文言、白话文

640?wx_fmt=jpeg

4个小节,预计用时30分钟

请打开您的电脑,按照步骤一步步完成哦!

本教程基于Python 3.5

原创者:SofaSofa TeamM | 修改校对:SofaSofa TeamC |

0. 前言

我们将用最最简短的语言告诉大家word2vec是什么,并且使用gensim来获得词向量。最后利用词向量来判断一个语句是文言文还是白话文,也就是完成“机器读中文2:辨古识今”。

1. 什么是Word2Vec?

Word2Vec是一种自然语言处理的模型,简单说来,就是把一个word表示为一个vector,所以叫Word2Vec。对于中文,一个Word可以是一个单词,也可以是一个词。

把词表示为向量,这样做有什么好处呢?第一是可以降维,如果把每个词都做one-hot编码,那么维度会特别大,如果把每个词都表示为长度为nn的向量,就可以完全省去one-hot带来的高维度。第二点,是可以挖掘词与词的联系。如果训练样本够大,我们会发现向量“猫”和向量“喵”会更相似,而不是“狗”。在英文中一个经典例子是,向量“Queen”-向量“Female”=向量“King”-向量“Male”。

Word2Vec模型是一个只有一个隐藏层的神经网络模型(如下)。每个词是一条数据,目的是预测这个词的后一个(或者kk个词)。输入数据是one-hot的向量,输出层的结果是预测该词后面出现的词。那么Word2Vec中的vector在哪里呢?这个向量其实就是隐藏层的数值。640?wx_fmt=jpeg

2. 利用gensim计算Word2Vec

gensim是python中自然语言处理非常强大的包,而且极易使用。首先,我们在python中引用该包。

from gensim.models import Word2Vec

下面我们来读取“机器读中文2:辨古识今”中的数据集。

import pandas as pd
train = pd.read_csv('train.txt')
test = pd.read_csv('test.txt')
texts = list(train['text']) + list(test['text'])

不妨先看看texts里的内容有哪些。

print(texts[:10])
['来扰乱天子的边防', '崤山以东地区虽然混乱', '秦昭王闻之 使人遗赵王书 愿以十五城请易璧', '臣不胜受恩感激', '现在如果把东西寄存在别人处', '南北朝所以不治 文采胜质厚也', '而流贼进攻更急 城里有许多不同的意见', '吾上有三兄 皆不幸早世', '没有人不讲究熏衣剃面', '王曰 善']

接下来,就可以训练Word2Vec模型了。这里我们把每一个作为一个word,每个字都会被表示为一个向量。一键完成,非常方便。

ndims = 50
model = Word2Vec(sentences=texts, size=ndims, window=5)

模型中sentences是训练素材,size是指vector的长度,window是指窗长,也就是预测该词之后的5个词。这样,每个字都被表示成了一个长度为50的向量。下面我们不妨试几个词。

print(model.wv['之'])
[-0.02306273  0.7689658  -0.23238362 -0.36329043  0.14156663  0.29761788
 -0.45338956 -0.7482197  -0.06813935 -0.4105922  -0.3896525  -0.5217305
  0.11865879 -0.32430476 -0.53716886  0.25903523  0.11261824 -0.3138387
 -0.46736085 -0.04374949 -0.2901372   0.04580646 -0.24377792  0.36069182
  0.45043638 -0.82071906 -0.77037716  0.65637636  0.45035675 -0.05211991
  0.6374315  -0.52816385  0.09859632 -0.41244134  0.7426563   0.01779771
  0.10559028 -0.04655827  0.26579723 -0.48558313  0.38831276 -0.3439704
  0.26713774 -0.267362   -0.22380458  0.99069804 -0.28053552  0.16005835
  0.05433292  0.40896153]	
print(model.wv['的'])
[-5.1170345e-02  7.3522794e-01 -2.1519105e-01 -3.3946022e-01
  1.1915052e-01  3.1610066e-01 -4.1824239e-01 -7.6163346e-01
 -4.0698811e-02 -4.0355769e-01 -3.0365336e-01 -4.8146579e-01
  1.3719502e-01 -3.8396400e-01 -4.9982443e-01  2.2536282e-01
  8.1103407e-02 -2.8362677e-01 -4.9123862e-01  7.8462285e-04
 -3.2690132e-01  6.6004813e-02 -2.5450531e-01  3.4221938e-01
  4.4872758e-01 -7.7068639e-01 -7.8395563e-01  6.9241500e-01
  5.3227925e-01 -3.4683388e-02  6.6531086e-01 -5.2474988e-01
  1.8498762e-01 -4.4998875e-01  7.4666858e-01  7.6578781e-02
  1.6198398e-01 -8.5742459e-02  2.8727862e-01 -4.8327830e-01
  3.2108101e-01 -3.9720288e-01  2.3086597e-01 -3.2169360e-01
 -2.2850281e-01  1.0791894e+00 -2.7565178e-01  1.5590596e-01
 -3.6102833e-04  4.3195924e-01]

那么,哪些字和“之”最相近呢?答案如下,果不其然,最接近的也都是文言文中的常用字。

print(model.wv.most_similar('之', topn=5))
[('其', 0.9995831847190857), ('者', 0.9995520114898682), ('以', 0.9995492696762085), ('此', 0.9995350241661072), ('欲', 0.9994945526123047)]

再看看“的”,最接近“的”的字也都是白话文中的常用字。

print(model.wv.most_similar('的', topn=5))
[('了', 0.9994625449180603), ('就', 0.9994519352912903), ('这', 0.9994337558746338), ('个', 0.999407172203064), ('都', 0.9993969798088074)]

3. 利用词向量进行数据可视化

我们可以利用Word2Vec对文本进行数据可视化处理。首先,我们把每个字表示为长度为2的向量(也就是ndims=2),然后对每一句话中所有字的向量求均值。这样每句话都会被表示成平面上的一个点。

ndims = 2
model = Word2Vec(sentences=texts, size=ndims, window=5)

total = len(texts)
vecs = np.zeros([total, ndims])for i, sentence in enumerate(texts):
    counts, row = 0, 0
    for char in sentence:
        try:
            if char != ' ':
                row += model.wv[char]
                counts += 1
        except:
            pass
    if counts == 0:
        print(sentence)
    vecs[i, :] = row / counts

根据上面代码,我们得到了训练集train的向量表达vecsvecs中每一行代表一句话,用一个长度为2的向量表示。结合训练集中的真实标签train['y'],我们可以在坐标系中绘出词向量。

import matplotlib.pyplot as plt
plt.figure(figsize=(8, 8))
plt.axis([-1, 1.5, 1.5, 3])
colors = list(map(lambda x: 'red' if x == 1 else 'blue', train['y']))
plt.scatter(vecs[:, 0], vecs[:, 1], c=colors, alpha=0.2, s=30, lw=0)print('Word2Vec: 白话文(蓝色)与文言文(红色)')
plt.show()

640?wx_fmt=png

尽管只用了长度为2的向量,文言文(红色)和白话文(蓝色)已经可以较好区分。

4. 利用Word2Vec建立文言、白话分类器

首先,引用包、读取数据。

import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifierfrom gensim.models import Word2Vec

train = pd.read_csv('train.txt')
test = pd.read_csv('test.txt')
submit = pd.read_csv('sample_submit.csv')

获取texts

total = len(train) + len(test)
n_train = len(train)

labeled_texts = []

texts = list(train['text']) + list(test['text'])

利用Word2Vec,将每句话转成长度为100的数值向量。

ndims = 100
model = Word2Vec(sentences=texts, size=ndims)

vecs = np.zeros([total, ndims])for i, sentence in enumerate(texts):
    counts, row = 0, 0
    for char in sentence:
        try:
            if char != ' ':
                row += model.wv[char]
                counts += 1
        except:
            pass
    if counts == 0:
        print(sentence)
    vecs[i, :] = row / counts

利用sklearn中的DecisionTreeClassifier,建立决策树分类模型并得到最终的分类结果,保存至my_prediction.csv

clf = DecisionTreeClassifier(max_depth=3, random_state=100)
clf.fit(vecs[:n_train], train['y'])
submit['y'] = clf.predict_proba(vecs[n_train:])[:, 1]
submit.to_csv('my_prediction.csv', index=False)

我们不妨看看,我们的预测效果如何。(为了方便,我们把预测值大于0.5的标为1文言文,小于0.5的标为0白话文。)

test['pred'] = (submit['y'] > 0.5).astype(int)
test.head(20)

idtextpred
05000后来又合并为七个强国0
15001与吾父居者 今其室十无二三焉1
25002那么政局就会安定了0
35003我资米若薪于百姓 后之人必尔乎索之1
45004昔虞国宫之奇少长於君 君狎之1
55005我们怎能学他那种穷途的哭泣0
65006迫而视之 乃前寄辞者1
75007但后来执掌法律的官员却以耗费国家资财的罪名上书弹劾0
85008你们因为张公的智慧得到了生存 他就是你们的再生父母0
95009以父荫补弘文校书郎 擢累谏议大夫1
105010操蛇之神闻之 惧其不已也 告之于帝1
115011夫不通礼义之旨 至于君不君1
125012今老矣 无能为也已1
135013这难道不是得到它的好处却背叛它的恩惠吗0
145014念诸父与诸兄 皆康强而早世1
155015晋侯 秦伯围郑 以其无礼于晋 且贰于楚也1
165016陈王闻 乃使武平君畔为将军 监郯下军1
175017汗流浃背 吃不下东西 说0
185018业已整齐门内 提撕子孙1
195019只要有胜过我的地方 就很可贵0

这个分类结果还是比较让人满意的。上传到排行榜看看结果如何吧!

整个分类过程的完整代码如下:

# -*- coding: utf-8 -*-import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifierfrom gensim.models import Word2Vec

train = pd.read_csv('train.txt')
test = pd.read_csv('test.txt')
submit = pd.read_csv('sample_submit.csv')

total = len(train) + len(test)
n_train = len(train)

labeled_texts = []

texts = list(train['text']) + list(test['text'])

ndims = 100
model = Word2Vec(sentences=texts, size=ndims)

vecs = np.zeros([total, ndims])for i, sentence in enumerate(texts):
    counts, row = 0, 0
    for char in sentence:
        try:
            if char != ' ':
                row += model.wv[char]
                counts += 1
        except:
            pass
    if counts == 0:
        print(sentence)
    vecs[i, :] = row / counts

clf = DecisionTreeClassifier(max_depth=3, random_state=100)
clf.fit(vecs[:n_train], train['y'])
submit['y'] = clf.predict_proba(vecs[n_train:])[:, 1]
submit.to_csv('my_prediction.csv', index=False)

猜你可能喜欢

640?wx_fmt=jpeg

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值