一、词袋模型(BOW)
词袋模型是一种简单常用的模型,在该模型中,我们可以把文本看做是一系列词的集合,我们用袋子来把他们装起来就叫做词袋,这么说可能有些抽象,用一个例子来表示一下:
有一段文本:"it is a beautiful day today"
进行分词处理:it/is/a/beautiful/day/today
得到词袋:("it","is","a","beautiful","day","today")
但是我们得到的词袋要交给计算机处理,计算机并不能很好的识别英文,只能识别数字,那么我们给每一个词添加一个索引去解决这个问题:
词袋索:(0,1,2,3,4,5)
对于需要考虑词频的词袋模型我们可以定义成用一个数字来表示索引一个数字来表示词频的形式:[(0,2),(1,2),(2,2)......]
上例是词袋模型的一种表示方法, 下面举另外一个例子来表示一下:
给出两个文本:
1:Bob likes to play basketball, Jim likes too.
2:Bob also likes to play football games.
我们可以构造出一个词典:
{1:”Bob”, 2. “like”, 3. “to”, 4. “play”, 5. “basketball”, 6. “also”, 7. “football”, 8. “games”, 9. “Jim”, 10. “too”}。
上面的词典中包含了10个单词,对于每个单词都有一个唯一的索引,那么对于两个文本我们有如下的词袋表示方法:
1:[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
2:[1, 1, 1, 1 ,0, 1, 1, 1, 0, 0]
词袋模型适用的数据类型:离散,高维,稀疏
词袋模型存在的问题:
1、维度灾难,如果一个例子词典中包含10000个单词,那么每个文本需要用10000维的向量表示。
2、无法保留词序信息
3、存在语义鸿沟的问题
代码示例
from sklearn.feature_extraction.text import CountVectorizer
# list of text documents
text = ["The quick brown fox jumped over the lazy dog."]
# create the transform
vectorizer = CountVectorizer()
# tokenize and build vocab
vectorizer.fit(text)
# summarize
print(vectorizer.vocabulary_)
# encode document
vector = vectorizer.transform(text)
# summarize encoded vector
print(vector.shape)
print(type(vector))
print(vector.toarray())
二、one-hot(独热码)
one-hot是表示一项属性的特征向量,向量中只有一个特征是不为0的,其他的特征都为0(简单的来说就是将一个bit的位置填1,其他位置都填0),比如机器学习中对于离散型的分类数据,需要对其进行数字化,此时便可以使用独热码来表示,举例表示一下:
对于一个特征是离散值的情况:
性别:{男,女,其他}
可以看到上面的性别特征有三个不同的分类值,也就意味着我们需要三个bit的值来表示这些类别,此时可以用独热码表示为:
男:{100},女:{010},其他:{001}
对于多个特征时:
性别:{男,女,其他}
年级:{一年级,二年级,三年级,四年级}
那么对于一年级的男生编码既可以为:{1001000}(前面的100表示男生,后面的1000表示一年级)
from sklearn import preprocessing
ont_hot = preprocessing.OneHotEncoder()
data = [[0, 1, 2], [0, 0, 1], [1, 0, 0], [1, 1, 3]]
ont_hot.fit(data)
print(ont_hot.transform([[1, 0, 3]]).toarray())
三、word2vec
word2vec技术是一种为了利用神经网络从大量无标注的文本中提取有用信息而产生的向量。
上文中我们提到了one-hot编码,但是独热码中只有一个bit的数值为1其余都为0,对于需要编码很多类别的情况容易产生维度灾难,那么我们能不能把维度变低呢,下面我们就来说一下word2vec。
word2vec本质上是一种简单的神经网络,它分为两种训练模型(CBOW和Skip-gram):
word2vec模型的主要构成如下:
该模型的输入是one-hot编码,Hidden Layer是线性单元(没有激活函数),Output的使用的是softmax回归(输出输入词的邻近词的概率分布),维度和input相同,模型训练后输入层和隐藏层之间权重即为我们要获取的词向量。
CBOW模型是根据中心词W(t)周围的词来预测中心词。
Skip-gram模型是根据中心词W(t)来预测周围的词。
示例代码:
process_wiki.py
from __future__ import print_function
import logging
import os.path
import six
import sys
from gensim.corpora import WikiCorpus
if __name__ == '__main__':
program = os.path.basename(sys.argv[0])
logger = logging.getLogger(program)
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s')
logging.root.setLevel(level=logging.INFO)
logger.info("running %s" % ' '.join(sys.argv))
# check and process input arguments
if len(sys.argv) != 3:
print("Using: python process_wiki.py enwiki.xxx.xml.bz2 wiki.en.text")
sys.exit(1)
inp, outp = sys.argv[1:3]
space = " "
i = 0
output = open(outp, 'w')
wiki = WikiCorpus(inp, lemmatize=False, dictionary={})
for text in wiki.get_texts():
if six.PY3:
output.write(bytes(' '.join(text), 'utf-8').decode('utf-8') + '\n')
# ###another method###
# output.write(
# space.join(map(lambda x:x.decode("utf-8"), text)) + '\n')
else:
output.write(space.join(text) + "\n")
i = i + 1
if i % 10000 == 0:
logger.info("Saved " + str(i) + " articles")
output.close()
logger.info("Finished Saved " + str(i) + " articles")
train_word2vec_model.py
from __future__ import print_function
import logging
import os
import sys
import multiprocessing
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
if __name__ == '__main__':
program = os.path.basename(sys.argv[0])
logger = logging.getLogger(program)
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s')
logging.root.setLevel(level=logging.INFO)
logger.info("running %s" % ' '.join(sys.argv))
# check and process input arguments
if len(sys.argv) < 4:
print("Useing: python train_word2vec_model.py input_text "
"output_gensim_model output_word_vector")
sys.exit(1)
inp, outp1, outp2 = sys.argv[1:4]
model = Word2Vec(LineSentence(inp), size=200, window=5, min_count=5,
workers=multiprocessing.cpu_count())
model.save(outp1)
model.wv.save_word2vec_format(outp2, binary=False)
model.py
import gensim
model = gensim.models.Word2Vec.load("wiki.en.text.model")
print(model.most_similar("man"))
数据:enwiki-latest-pages-articles.xml.bz2(自行百度下载,大概16G)