前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GolVe向量化做文本分类向量化文本分类

GolVe向量化做文本分类向量化文本分类

作者头像
sladesal
发布2018-10-08 11:07:53
1.7K0
发布2018-10-08 11:07:53
举报
文章被收录于专栏:机器学习之旅机器学习之旅

向量化

在之前,我对向量化的方法一直局限在两个点,

第一种是常规方法的one-hot-encoding的方法,常见的比如tf-idf生成的0-1的稀疏矩阵来代表原文本:

这种方法简单暴力,直接根据文本中的单词进行one-hot-encoding,但是数据量一但大了,这个单句话的one-hot-encoding结果会异常的长,而且没办法得到词与词之间的关系。

第二种是基于神经网络的方法,常见的比如word2vec,YouTubeNet:

这种方法(这边以CBOW为例子)都是初始一个固定长度的随机向量作为每个单词的向量,制定一个目标词的向量,以上下文词向量的sum结果作为input进行前向传递,使得传递的结果和目标词向量尽可能一致,以修正初始的随机向量。 换句话说,就是刚开始,我随意定义生成一个vector代表一个词,然后通过上下文的联系去修正这个随机的vector。好处就是我们可以得到词与词之间的联系,而且单个词的表示不复杂,坏处就是需要大量的训练样本,毕竟涉及到了神经网络。

最近,我们突然发现了第三种方法,GolVe向量化。它也是开始的时候随机一个vector作为单词的表示,但是它不利用神经网络去修正,而是利用了一个自己构造的损失函数:

通过我们已有的文章内容,去是的这个损失函数最小,这就变成了一个机器学习的方法了,相比较暴力的前馈传递,这也高快速和高效的多。同时,它还兼具了word2vec最后结果里面vector方法的优点,得到词与词之间的联系,而且单个词的表示不复杂。

这边就不展开GolVe算法的细节了,后面有空和大家补充,这个算法的构造非常巧妙,值得大家借鉴一下。

文本分类

刚才开门见山的聊了蛮久向量化,看起来和文本分类没什么关系,确实在通常意义上来讲,我们的最简单最常用的方法并不是向量化的方法,比如通过朴素贝叶斯,N-Grams这些方法来做分类识别。

tfidf+N-grams

1.其实很简单,首先对语料库进行切词,维护自己的词典,做高频词的人工复审,将无意词进行stop_words归总

对公司内部信息进行了一下处理,主要看分布趋势

可以看到,高频词其实是非常非常少的,而且如果你真的去做了,你就会发现,"了"、“的”、“啊”这种语气词,和一些你公司相关的领域词汇会非常靠前,这些词作为stop_words会有效的降低训练成本、提高模型效果。

2.进行tf-idf,将词进行重赋权,字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降,有效的将向量化中的one hot encoding结果进行了修正。但是依然存在问题:在TFIDF算法中并没有体现出单词的位置信息。

代码语言:javascript
复制
# sublinear_tf:replace tf with 1 + log(tf)
# max_df:用来剔出高于词频0.5的词
# token_pattern:(?u)\b\w+\b是为了匹配出长度为1及以上的词,默认的至少需要词长度为2
# ngram_range:这边我做了3-grams处理,如果只想朴素计算的话(1,1)即可
# max_features:随着我做了各种宽松的条件,最后生成的词维度会异常大,这边限制了前3万
vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf=True, max_df=0.5, token_pattern=r"(?u)\b\w+\b",ngram_range=(1, 3), max_features=30000)

不得不说,python处理机器学习,深度学习的便捷程度是异常的高。

3.在经过TfidfVectorizer处理之后的结果是以稀疏矩阵的形式来存的,如果想看内容的话,可以用todense()转化为matrix来看。接下来,用贝叶斯来训练刚才得到的矩阵结果就可以了。

代码语言:javascript
复制
mnb_tri = MultinomialNB(alpha=0.001)
mnb_tri.fit(tri_train_set.tdm, tri_train_set.label)

tf-idf + n-grams + naive-bayes + lr

这种方法是上面方法的升级版本,我们先看下架构:

对公司内部信息进行了一下处理,主要看算法架构

其实主要差异在于右侧的算法模型详细部分,我们做了一个由3-grams到3-grams+naive-bayes+lr的扩充,提升精度。

在模型的过程中,上面的第一步,都是一样的,在第二、三步有所差异: 2.在第二步中,我们除了要构造出一个3-grams的sparse matrix也需要构造出一个朴素的sparse matrix

代码语言:javascript
复制
# 朴素结果
vectorizerby = TfidfVectorizer(stop_words=stpwrdlst, token_pattern=r"(?u)\b\w+\b", max_df=0.5, sublinear_tf=True,ngram_range=(1, 1), max_features=100000)

3.不仅仅用bayes进行一次分类,而是根据3-grams和朴素情况下的sparse matrix进行预测,再用logistics regression来合并两个的结果做个stack进行0-1压缩。

代码语言:javascript
复制
# 构造出一个3-grams的sparse matrix也需要构造出一个朴素的sparse matrix
mnb_tri = MultinomialNB(alpha=0.001)
mnb_tri.fit(tri_train_set.tdm, tri_train_set.label)
mnb_by = MultinomialNB(alpha=0.001)
mnb_by.fit(by_train_set.tdm, by_train_set.label)
代码语言:javascript
复制
# 加bias,cv选择最优正则结果,lbfgs配合l2正则
lr = LogisticRegressionCV(multi_class="ovr", fit_intercept=True, Cs=np.logspace(-2, 2, 20), cv=2, penalty="l2",solver="lbfgs", tol=0.01)
re = lr.fit(adv_data[['f1', 'f2']], adv_data['rep_label'])

总结一下上面两种方法,我觉得是入门快,效果也不错的小练手,也是完全可以作为我们开始一个项目的时候,用来做baseline的方法,主要是快啊~/斜眼笑

GolVe+lr

因为我目前的带标签数据比较少,所以之前一直没有敢用word2vec去向量化作死,但是GolVe不存在这个问题啊,我就美滋滋的进行了一波。 首先,先讲下GolVe的使用:

  • https://github.com/stanfordnlp/GloVe 在最大的代码抄袭网站下载(git clone)坦福大佬的代码,友情提醒,不要作死自己看了理论就觉得自己会写,自己搞个GloVe。(别问我是怎么知道的)
  • cd到对应目录下,vim demo.sh这个文件
代码语言:javascript
复制
#!/bin/bash
set -e

# Makes programs, downloads sample data, trains a GloVe model, and then evaluates it.
# One optional argument can specify the language used for eval script: matlab, octave or [default] python

# 请把make这边注释掉,这个是让你去下个demo,我们直接改成自己的数据
# make
# if [ ! -e text8 ]; then
#   if hash wget 2>/dev/null; then
#     wget http://mattmahoney.net/dc/text8.zip
#   else
#     curl -O http://mattmahoney.net/dc/text8.zip
#   fi
#   unzip text8.zip
#   rm text8.zip
# fi

# CORPUS需要对应自己的欲训练的文档
CORPUS=content.txt
VOCAB_FILE=vocab.txt
COOCCURRENCE_FILE=cooccurrence.bin
COOCCURRENCE_SHUF_FILE=cooccurrence.shuf.bin
BUILDDIR=build
SAVE_FILE=vectors
VERBOSE=2
MEMORY=4.0
# 单词至少出现几次
VOCAB_MIN_COUNT=3
# 向量长度
VECTOR_SIZE=128
# 迭代次数
MAX_ITER=30
# 窗口长度
WINDOW_SIZE=15
BINARY=2
NUM_THREADS=8
X_MAX=10

echo
echo "$ $BUILDDIR/vocab_count -min-count $VOCAB_MIN_COUNT -verbose $VERBOSE < $CORPUS > $VOCAB_FILE"
$BUILDDIR/vocab_count -min-count $VOCAB_MIN_COUNT -verbose $VERBOSE < $CORPUS > $VOCAB_FILE
echo "$ $BUILDDIR/cooccur -memory $MEMORY -vocab-file $VOCAB_FILE -verbose $VERBOSE -window-size $WINDOW_SIZE < $CORPUS > $COOCCURRENCE_FILE"
$BUILDDIR/cooccur -memory $MEMORY -vocab-file $VOCAB_FILE -verbose $VERBOSE -window-size $WINDOW_SIZE < $CORPUS > $COOCCURRENCE_FILE
echo "$ $BUILDDIR/shuffle -memory $MEMORY -verbose $VERBOSE < $COOCCURRENCE_FILE > $COOCCURRENCE_SHUF_FILE"
$BUILDDIR/shuffle -memory $MEMORY -verbose $VERBOSE < $COOCCURRENCE_FILE > $COOCCURRENCE_SHUF_FILE
echo "$ $BUILDDIR/glove -save-file $SAVE_FILE -threads $NUM_THREADS -input-file $COOCCURRENCE_SHUF_FILE -x-max $X_MAX -iter $MAX_ITER -vector-size $VECTOR_SIZE -binary $BINARY -vocab-file $VOCAB_FILE -verbose $VERBOSE"
$BUILDDIR/glove -save-file $SAVE_FILE -threads $NUM_THREADS -input-file $COOCCURRENCE_SHUF_FILE -x-max $X_MAX -iter $MAX_ITER -vector-size $VECTOR_SIZE -binary $BINARY -vocab-file $VOCAB_FILE -verbose $VERBOSE
if [ "$CORPUS" = 'text8' ]; then
   if [ "$1" = 'matlab' ]; then
       matlab -nodisplay -nodesktop -nojvm -nosplash < ./eval/matlab/read_and_evaluate.m 1>&2 
   elif [ "$1" = 'octave' ]; then
       octave < ./eval/octave/read_and_evaluate_octave.m 1>&2
   else
       echo "$ python eval/python/evaluate.py"
       python eval/python/evaluate.py
   fi
fi

这边多说一下,CORPUS=content.txt这边content.txt里面的格式需要按照空格为分隔符进行存储,我之前一直以为是\t

  • 直接sh demo.sh,你会得到vectors.txt,这个里面就对应每个词的向量表示
代码语言:javascript
复制
天气 -0.754142 0.386905 -1.200074 -0.587121 0.758316 0.373824 0.342211 -1.275982 -0.300846 0.374902 -0.548544 0.595310 0.906426 0.029255 0.549932 -0.650563 -0.425185 1.689703 -1.063556 -0.790254 -1.191287 0.841529 1.080641 -0.082830 1.062107 -0.667727 0.573955 -0.604460 -0.601102 0.615299 -0.470923 0.039398 1.110345 1.071094 0.195431 -0.155259 -0.781432 0.457884 1.093532 -0.188207 -0.161646 0.246220 -0.346529 0.525458 0.617904 -0.328059 1.374414 1.020984 -0.959817 0.670894 1.091743 0.941185 0.902730 0.609815 0.752452 1.037880 -1.522382 0.085098 0.152759 -0.562690 -0.405502 0.299390 -1.143145 -0.183861 0.383053 -0.013507 0.421024 0.025664 -0.290757 -1.258696 0.913482 -0.967165 -0.131502 -0.324543 -0.385994 0.711393 1.870067 1.349140 -0.541325 -1.060084 0.078870 0.773146 0.358453 0.610744 0.407547 -0.552853 1.663435 0.120006 0.534927 0.219279 0.682160 -0.631311 1.071941 -0.340337 -0.503272 0.150010 1.347857 -1.024009 -0.181186 0.610240 -0.218312 -1.120266 -0.486539 0.264507 0.266192 0.347005 0.172728 0.613503 -0.131925 -0.727304 -0.504488 1.773406 -0.700505 -0.159963 -0.888025 -1.358476 0.540589 -0.243272 -0.236959 0.391855 -0.133703 -0.071120 1.050547 -1.087613 -0.467604 1.779341 -0.449409 0.949411
好了 1.413075 -0.226177 -2.024229 -0.192003 0.628270 -1.227394 -1.054946 -0.900683 -1.958882 -0.133343 -1.014088 -0.434961 0.026207 -0.066139 0.608682 -0.362021 0.314323 0.261955 -0.571414 1.738899 -1.013223 0.503853 -0.536511 -0.212048 0.611990 -0.627851 0.297657 -0.187690 -0.565871 -0.234922 -0.845875 -0.767733 0.032470 1.508012 -0.204894 -0.495031 -0.159262 0.181380 0.050582 -0.333469 0.454832 -2.091174 0.448453 0.940212 0.882077 -0.617093 0.616782 -0.993445 -0.385087 0.251711 0.259918 -0.222614 -0.595131 0.661472 0.194740 0.619222 -1.253610 -0.838179 0.781428 -0.396697 -0.530109 0.022801 -0.558296 -0.656034 0.842634 -0.105293 0.586823 -0.603681 -0.605727 -0.556468 0.924275 -0.299228 -1.121538 0.237787 0.498935 -0.045423 0.171536 -1.026385 -0.262225 0.390662 1.263240 0.352172 0.261121 0.915840 1.522183 -0.498536 2.046169 0.012683 -0.073264 -0.361662 0.759529 -0.713268 0.281747 -0.811104 -0.002061 -0.802508 0.520559 0.092275 -0.623098 0.199694 -0.134896 -1.390617 0.911266 -0.114067 1.274048 1.108440 -0.266002 1.066987 0.514556 0.144796 -0.606461 0.197114 0.340205 -0.400785 -0.957690 -0.327456 1.529557 -1.182615 0.431229 -0.084865 0.513266 -0.022768 -0.092925 -0.553804 -2.269741 -0.078390 1.376199 -1.163337
随意 0.410436 0.776917 -0.381131 0.969900 -0.804778 -0.785379 -0.887346 -1.463543 -1.574851 0.313285 0.685253 -0.918359 0.199073 -0.305374 -0.642721 0.098114 -0.723331 0.353159 0.042807 0.369208 -1.534930 -0.084871 0.020417 -0.384782 0.276833 -0.160028 1.107051 0.884343 -0.204381 -0.459738 -0.387128 0.125867 0.093569 1.192471 -0.473752 -0.314541 -1.029249 0.481447 1.358753 -1.688778 -0.113080 -0.401443 -0.958206 0.605638 1.083126 0.131617 0.092507 0.476506 0.801755 1.096883 -0.102036 0.461804 0.820297 -0.104053 -0.126638 0.957708 -0.722038 0.223686 0.583582 0.201246 -1.254708 0.770717 -1.271523 -0.584094 -1.142426 1.066567 0.071951 -0.182649 0.014365 -0.577141 0.037340 -0.166832 -0.247827 0.165994 1.143665 -0.258421 -0.335195 0.170218 -0.212838 0.013709 0.088847 0.663238 -0.597439 0.632847 0.370871 0.652707 0.306935 0.195127 -0.252443 0.588479 0.191633 -1.587564 0.564600 -0.306158 -0.648177 -0.488595 1.532795 -0.462473 -0.643878 1.292369 -0.051494 -1.032738 0.453587 0.411327 -0.469373 0.428398 -0.020839 0.307422 0.518331 -0.860913 -2.170098 -0.277532 -0.966210 0.615336 -0.924783 0.042679 1.289640 1.272992 1.367773 0.426600 -0.187254 -0.781009 1.331301 -0.088357 -1.113550 -0.262879 0.300137 0.437905
..
  • 有了每个词的向量,我们这边采取了借鉴YoutubeNet网络的想法:

举个例子:存在一句话"我爱中国",“我”的向量是[0.3,0.2,0.3],"爱"的向量是[0.1,0.2,0.3],“中国”的向量是[0.6,0.6,0.4],那么average后就是[0.5,0.5,0.5],然后这就类似一个特征为三的input。

这种方法的好处就是快捷,预处理的工作代价要小,随着数据量的增多,模型的效果要更加的好,这边给出一下业务数据对比:

experiment

date

intercepted_recall

3-grams

20180915

79.3%

3-grams

20180917

78.7%

3-grams+bayes+lr

20180915

83.4%

3-grams+bayes+lr

20180917

88.6%

gloVe+lr

20180915

93.1%

gloVe+lr

20180917

93.9%

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 向量化
  • 文本分类
    • tfidf+N-grams
      • tf-idf + n-grams + naive-bayes + lr
        • GolVe+lr
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档