当前位置:   article > 正文

word2vec预训练词向量+通俗理解word2vec+CountVectorizer+TfidfVectorizer+tf-idf公式及sklearn中TfidfVectorizer_sklearn中word2vec文本特征提取并分类预测

sklearn中word2vec文本特征提取并分类预测

文分类实(一) word2vec预训练词向量

  • 文本分类这个系列有十篇左右
    • 基于word2vec预训练的文本分类
    • 基于最新的预训练模型(ELMo,BERT等)的文本分类。
  • 总共有以下
      word2vec预训练词向量
      textCNN 模型
      charCNN 模型
      Bi-LSTM 模型
      Bi-LSTM + Attention 模型
      RCNN 模型
      Adversarial LSTM 模型
      Transformer 模型
      ELMo 预训练模型
      BERT 预训练模型
  • 代码均在
  • 添加链接描述
    提取码:t5vd

2 数据集

  • IMDB电影影评,
  • 三个数据文件,
  • /data/rawData下
  • unlabeledTrainData.tsv,
  • labeledTrainData.tsv,
  • testData.tsv。
  • 文本分类时需要有标签的数据(labeledTrainData),
  • 但是在训练word2vec词向量模型(无监督学习)时可以将无标签的数据一起用上。

3 数据预处理

  • 属英文文本
  • 本序列主要是文本分类的模型介绍
  • 数据预处理比较简单
  • 只去除各种标点符号,HTML标签,小写化
import pandas as pd
from bs4 import BeautifulSoup

with open("textClassifier/data/rawData/unlabeledTrainData.tsv", "r",encoding='UTF-8') as f:
    unlabeledTrain = [line.strip().split("\t") for line in f.readlines() if len(line.strip().split("\t")) == 2]
    #print (type(unlabeledTrain))
    #print (len(unlabeledTrain))
    #print (type(unlabeledTrain[0]))
    print (unlabeledTrain[1])
    
with open("textClassifier/data/rawData/labeledTrainData.tsv", "r",encoding='UTF-8') as f:
    labeledTrain = [line.strip().split("\t") for line in f.readlines() if len(line.strip().split("\t")) == 3]
    #print (type(labeledTrain))
    #print (len(labeledTrain))
    #print (labeledTrain[0])
    #print (labeledTrain[1])


unlabel = pd.DataFrame(unlabeledTrain[1: ], columns=unlabeledTrain[0])
label = pd.DataFrame(labeledTrain[1: ], columns=labeledTrain[0])

#print (unlabel)



def cleanReview(subject):
    beau = BeautifulSoup(subject)
    newSubject = beau.get_text()
    newSubject = newSubject.replace("\\", "").replace("\'", "").replace('/', '').replace('"', '').replace(',', '').replace('.', '').replace('?', '').replace('(', '').replace(')', '')
    newSubject = newSubject.strip().split(" ")
    newSubject = [word.lower() for word in newSubject]
    newSubject = " ".join(newSubject)
    
    return newSubject
    
unlabel["review"] = unlabel["review"].apply(cleanReview)
label["review"] = label["review"].apply(cleanReview)
print (unlabel.iloc[0][1])



newDf = pd.concat([unlabel["review"], label["review"]], axis=0) 
# 保存成txt文件
newDf.to_csv("wordEmbdiing.txt", index=False)








  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 用pandas直接处理数据,建议用apply方法,处理速度快,

  • 数据处理完之后将有标签和无标签的数据合并,并保存成txt

  • 这下只有一列啦!全是review!

4 预训练word2vec模型

class gensim.models.word2vec.Word2Vec(sentences=None, corpus_file=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=0.001, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, ns_exponent=0.75, cbow_mean=1, hashfxn=<built-in function hash>, iter=5, null_word=0, trim_rule=None, sorted_vocab=1, batch_words=10000, compute_loss=False, callbacks=(), max_final_vocab=None)
  • 1
  • sentences:要分析的语料,可是一个列表,或从文件中遍历读出(word2vec.LineSentence(filename) )

  • size:词向量维度,默认100。一般与我们的语料的大小相关,不大的语料,比如小于100M,则使用默认值一般就可以。

    • 超大的语料,建议增大维度。
  • window:即词向量上下文最大距离,越大,则和某一词较远的词也会产生上下文关系。默认5

  • 小语料则这个值可以设的更小。

  • 对一般的语料这个值推荐在[5;10]

  • sg:0, 则是CBOW;是1则是Skip-Gram;默认是0

  • hs:即我们的word2vec两个解法的选择了。如果是0, 则是Negative Sampling;是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。

  • negative:即使用Negative Sampling时负采样的个数,默认5。

    • 推荐[3,10]。算法原理篇中标记为neg。
  • 7 cbow_mean:仅用于CBOW在做投影的时候,为0,则算法中的xw为上下文的词向量之和,为1则为上下文的词向量的平均值。在我们的原理篇中,是按照词向量的平均值来描述的。个人比较喜欢用平均值来表示xw,默认值也是1,不推荐修改默认值。

  • 8 min_count:需要计算词向量的最小词频。

    • 这个值可以去掉一些很生僻的低频词,默认5。
    • 小语料可调低这个值。
    1. iter:随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大
    1. alpha:在随机梯度下降法中迭代的初始步长。算法原理篇中标记为η,默认0.025。
    1. min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步。
  • 训练模型的代码

import logging
import gensim
from gensim.models import word2vec

# 设置输出日志
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# 直接用gemsim提供的API去读取txt文件,读取文件的API有LineSentence 和 Text8Corpus, PathLineSentences等。
sentences = word2vec.LineSentence("/data4T/share/jiangxinyang848/textClassifier/data/preProcess/wordEmbdiing.txt")

# 训练模型,词向量的长度设置为200, 迭代次数为8,采用skip-gram模型,模型保存为bin格式
model = gensim.models.Word2Vec(sentences, size=200, sg=1, iter=8)  
model.wv.save_word2vec_format("./word2Vec" + ".bin", binary=True) 

# 加载bin格式的模型
wordVec = gensim.models.KeyedVectors.load_word2vec_format("word2Vec.bin", binary=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

canci

通俗理解word2vec

独热编码

  • 优点:

    • 解决分类器不好处理离散数据,
    • 也起到了扩充特征的作用。
  • 缺点:

    • 文本特征表示上有些缺点就非常突出了。
    • 它是一个词袋模型,
    • 不考虑词与词之间顺序
    • 它假设词与词相互独立
    • 它得到的特征是离散稀疏的。

  • 如果将世界所有城市名称作为语料库的话,那这个向量会过于稀疏,会造成维度灾难。

杭州 [0,0,0,0,0,0,0,1,0,……,0,0,0,0,0,0,0]
上海 [0,0,0,0,1,0,0,0,0,……,0,0,0,0,0,0,0]
宁波 [0,0,0,1,0,0,0,0,0,……,0,0,0,0,0,0,0]
北京 [0,0,0,0,0,0,0,0,0,……,1,0,0,0,0,0,0]

  • 杭州、上海、宁波、北京各对应一个向量,向量中只有一个值为1,其余都为0。

  • 能不能把词向量的维度变小

  • Dristributed representation可解决One hot representation的问题,
  • 通过训练,将每个词都映射到一个较短的词向量。
  • 所有的这些词向量就构成向量空间,
    • 可用普通的统计学来研究词与词之间关系。
    • 这个较短的词向量维度是多大呢?这个一般需要我们在训练时自己来指定。

  • 将词汇表里的词用"Royalty",“Masculinity”, "Femininity"和"Age"4维度表示,
  • King这个词对应的词向量可能是(0.99,0.99,0.05,0.7)
  • 并不能对词向量的每个维度做一个很好的解释。

在这里插入图片描述

  • 将king这个词从一个可能非常稀疏的向量坐在的空间,映射到现在这个四维向量所在的空间,

  • 必须满足

  • 这个映射是单设(不懂的概念自行搜索);

  • 映射之后的向量不会丢失之前的那种向量所含的信息。

  • 这个过程称word embedding,

    • 将高维词向量嵌入到一个低维空间

  • 经过一系列降维,
  • 有了用Dristributed representation表示的较短的词向量,
  • 就可以较容易的分析词之间的关系了,
  • 将词的维度降维到2维,有一个有趣的研究表明,用下图的词向量表示我们的词时,我们可以发现:
  • 原因是,最后的词向量的训练过程中引入了词的上下文。

  • You shall know a word by the company it keeps.

  • 举栗

  • 想到得到"learning"的词向量,训练过程中考虑了它的上下文

  • 就可以使"learning"带有语义信息

  • 通过这种操作,我们可以得到近义词,甚至cat和它的复数cats的向量极其相近。

  • 下面开始正片

word2vec

  • 就是简单化的神经网络

  • 输入One-Hot Vector
  • Hidden Layer没有激活函数,也就是线性的单元。
  • Output Layer维度跟Input Layer的维度一样,用Softmax回归
  • 训练好后,并不用这个训练好的模型处理新的任务,真正需要的是这个模型通过训练数据所学得的参数
    • 如隐层权重矩阵

  • 如何定义数据的输入和输出呢?
  • 分CBOW(Continuous Bag-of-Words 与Skip-Gram
  • CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,输出就是这特定的一个词的词向量
  • Skip-Gram输入是特定的一个词的词向量
    • 输出特定词对应的上下文词向量
    • CBOW对小数据库合适
    • Skip-Gram在大型语料中更好

(Continuous Bag-of-Words)

  • 1 输入层:上下文单词的onehot. {单词向量空间为V,上下文单词个数C}

字典有V个单词

  • 2 所有onehot分别乘以共享输入权重矩阵W. {VN矩阵,N为自己设定,初始化权重矩阵W}

N是嵌入的维度

  • 3 所得的向量相加求平均作为隐层向量, 为1N
  • 4 乘以输出权重矩阵W’ {NV}
  • 5 得到向量 {1V} 激活函数处理得到V-dim概率分布
    • {是onehot嘛,其中的每一维斗代表着一个单词}
  • 6 概率最大的index所指示的单词为预测出的中间与true label的onehot比较
    • 误差越小越好(根据误差更新权重矩阵)

  • 需定义loss function(一般交叉熵),
  • 用梯度下降算法更新W和W’。
  • 训练后,
  • 输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),
  • 这个矩阵(所有单词的word embedding)也叫look up table(这个look up table就是矩阵W自身),
  • 任何一个单词的onehot乘以这个矩阵都将得到自己的词向量。
  • 有了look up table就可以免去训练过程直接查表得到单词的词向量了。

  • 窗口大小是2,
  • 选取coffe前面两个单词和后面两个单词,作为input

  • 设我们此时得到的概率分布已经达到了设定的迭代次数,
  • 那么训练出来的look up table应该为矩阵W。
  • 任何一个单词的one-hot表示乘以这个矩阵都将得到自己的word embedding

canci

sklearn: TfidfVectorizer 中文处理及参数

  • TfidfVectorizer把原始文本转化为tf-id矩阵,从
  • 为后续的文本相似度计算,
  • 主题模型(如LSI),文本搜索排序等一系列应用奠定基础。
#coding=utf-8
from sklearn.feature_extraction.text import TfidfVectorizer
document = ["I have a pen.",
            "I have an apple."]
tfidf_model = TfidfVectorizer().fit(document)
sparse_result = tfidf_model.transform(document)     # 得到tf-idf矩阵,稀疏矩阵表示法
print(sparse_result)

print(sparse_result.todense())                     # 转化为更直观的一般矩阵

print(tfidf_model.vocabulary_)                      # 词语与列的对应关系
  (0, 3)        0.8148024746671689
  (0, 2)        0.5797386715376657
  (1, 2)        0.4494364165239821
  (1, 1)        0.6316672017376245
  (1, 0)        0.6316672017376245
[[0.         0.         0.57973867 0.81480247]
 [0.6316672  0.6316672  0.44943642 0.        ]]
{'have': 2, 'pen': 3, 'an': 0, 'apple': 1}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 你看每句话都被用4维向量表示了!
    • 这4个维度分别是哪4个单词呢?
    • 第0个事an
    • 第一个是apple
    • 第二个是have
    • 第三个是pen

  • 本大王的疑问
    • 上面为啥两句话have的权重不一样呢?
    • 因为被它奶奶的l2归一化了啊

  • 我试试不归一化
from sklearn.feature_extraction.text import TfidfVectorizer
document = ["I have a pen.",
            "I have an apple."]
tfidf_model = TfidfVectorizer(norm=None).fit(document)
sparse_result = tfidf_model.transform(document)     # 得到tf-idf矩阵,稀疏矩阵表示法
print(sparse_result)

print(sparse_result.todense())                     # 转化为更直观的一般矩阵

print(tfidf_model.vocabulary_)  

  (0, 3)        1.4054651081081644
  (0, 2)        1.0
  (1, 2)        1.0
  (1, 1)        1.4054651081081644
  (1, 0)        1.4054651081081644
[[0.         0.         1.         1.40546511]
 [1.40546511 1.40546511 1.         0.        ]]
{'have': 2, 'pen': 3, 'an': 0, 'apple': 1}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

canci

TfidfVectorizer参数analyzer ="char"就可以实现对任意东西检测啦!!

TfidfVectorizer参数解析

  • vectorizer = CountVectorizer()
    • 计算TF的玩意
  • transformer = TfidfTransformer()
    • 计算TF-IDF的玩意
  • tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
    • vectorizer.fit_transform(corpus)将文本输入,得词频矩阵
    • 将这个矩阵作为输入,用transformer.fit_transform(词频矩阵)得到TF-IDF矩阵
  • CountVectorizer()和TfidfVectorizer()都有一个成员
    • vocabulary_
    • 是词典索引,对应TF-IDF权重矩阵的列
    • 不过一个是私有成员,一个是外部输入,原则上应该保持一致。
vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf = True, max_df = 0.5)
  • 1

  • input:string{‘filename’, ‘file’, ‘content’}
    • 如果是’filename’,序列作为参数传递给拟合器,预计为文件名列表,这需要读取原始内容进行分析
    • 如果是’file’,序列项目必须有一个”read“的方法(类似文件的对象),被调用作为获取内存中的字节数 否则,输入预计为序列串,或字节数据项都预计可直接进行分析。
  • encoding:string, ‘utf-8’by default 如果给出要解析的字节或文件,此编码将用于解码decode_error: {‘strict’, ‘ignore’, ‘replace’} 如果一个给出的字节序列包含的字符不是给定的编码,指示应该如何去做。默认情况下,它是’strict’,这意味着的UnicodeDecodeError将提高,其他值是’ignore’和’replace’
  • strip_accents: {‘ascii’, ‘unicode’, None} 在预处理步骤中去除编码规则(accents),”ASCII码“是一种快速的方法,仅适用于有一个直接的ASCII字符映射,"unicode"是一个稍慢一些的方法,None(默认)什么都不做
  • analyzer:string,{‘word’, ‘char’} or callable
    • 定义特征为词(word)或n-gram字符,
    • 如果传递给它的调用被用于抽取未处理输入源文件的特征序列
  • preprocessor:callable or None(default) 当保留令牌和”n-gram“生成步骤时,覆盖预处理(字符串变换)的阶段
  • tokenizer:callable or None(default) 当保留预处理和n-gram生成步骤时,覆盖字符串令牌步骤ngram_range: tuple(min_n, max_n) 要提取的n-gram的n-values的下限和上限范围,在min_n <= n <= max_n区间的n的全部值
  • stop_words:string {‘english’}, list, or None(default)
    • english,用于英语内建的停用词列表
    • 如果未list,该列表被假定为包含停用词,列表中的所有词都将从令牌中删除
    • None,不用停用词。max_df可被设为[0.7, 1.0),基于内部预料词频来自动检测和过滤停用词
  • lowercase:boolean, default True 在令牌标记前转换所有的字符为小写
  • token_pattern:string
    • 正则表达式显示”token“的构成,
    • 仅当analyzer == ‘word’时才被使用。
    • 两个或多个字母数字字符的正则表达式(标点符号完全被忽略,始终被视为一个标记分隔符)。
  • max_df: float in range [0.0, 1.0] or int, optional, 1.0 by default
    • 构建词汇表时,忽略高于给出阈值的文档频率的词条,语料指定的停用词。
    • 浮点值,该参数代表文档的比例,整型绝对计数值,如果词汇表不为None,此参数被忽略。
  • min_df:float in range [0.0, 1.0] or int, optional, 1.0 by default当构建词汇表时,严格忽略低于给出阈值的文档频率的词条,语料指定的停用词。如果是浮点值,该参数代表文档的比例,整型绝对计数值,如果词汇表不为None,此参数被忽略。
  • max_features: optional,None by default
    • 如果不None,构建一个词汇表,仅考虑max_features–按语料词频排序,如果词汇表不为None,这个参数被忽略vocabulary:Mapping or iterable, optional 也是一个映射(Map)(例如,字典),其中键是词条而值是在特征矩阵中索引,或词条中的迭代器。如果没有给出,词汇表被确定来自输入文件。在映射中索引不能有重复,并且不能在0到最大索引值之间有间断。
    • binary:boolean, False by default
      • True,则所有非零计数被设置为1,这对于离散概率模型是有用的,建立二元事件模型,而不是整型计数
    • dtype:type, optional
      • fit_transform()或transform()返回矩阵的类型
  • norm:‘l1’, ‘l2’, or None,optional
    • 用于标准化词条向量。
    • None为不归一化
  • use_idf
    • boolean, optional
    • 启动inverse-document-frequency重新计算权重
  • smooth_idf:boolean,optional
    • 加1到文档频率平滑idf,防止除零,
    • 加入一个额外的文档
  • sublinear_tf:boolean, optional
    • 应用线性缩放TF,
    • 例如,用1+log(tf)覆盖tf

lianjie

CountVectorizer

  • CountVectorizer
  • 对每一个训练文本,只考虑每种词汇在该训练文本中出现的次数
  • 将文本中的词语转为词频矩阵
  • fit_transform
    • 计算各个词语出现的次数

参数详解

CountVectorizer(input='content', encoding='utf-8',  decode_error='strict', strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, stop_words=None, 
token_pattern='(?u)\b\w\w+\b', ngram_range=(1, 1), analyzer='word', max_df=1.0, min_df=1, max_features=None, vocabulary=None, binary=False, dtype=<class 'numpy.int64'>)
  • 1
  • 2
  • 参数很多,分三个处理步骤:

    • preprocessing、tokenizing、n-grams generation.
  • 设置参数:ngram_range,

    • max_df,
    • min_df,
    • max_features
  • input

    • 一般默认,可设为"filename’或’file’
  • encodeing

    • 默认的utf-8,分析器将会以utf-8解码raw document
  • decode_error

    • 默认strict,遇到不能解码的字符将报UnicodeDecodeError错,
    • 为ignore将会忽略解码错误,
    • 还可设为replace,作用尚不明确
  • strip_accents

    • 默认None,
    • 可设为ascii或unicode,将用ascii或unicode编码在预处理步骤去除raw document中的重音符号
  • analyzer

    • 一般默认,可设为string类型,如’word’, ‘char’, ‘char_wb’,还可设置为callable类型,比如函数是一个callable类型

我写的从广告提取的例子

  • 就是每个句子都用一句话里出现的词频作为向量
    • 就是词的个数哈!!

from sklearn.feature_extraction.text import CountVectorizer

texts=["1 12 3","2 3 4","5 5", '6'] 

cv = CountVectorizer(analyzer='word',token_pattern="[0-9]+")#创建词袋数据结构
cv_fit=cv.fit_transform(texts)
print(cv_fit.toarray()) #.toarray() 是将结果转化为稀疏矩阵矩阵的表示方式;

print(cv.get_feature_names())   
print(cv.vocabulary_)              # {‘dog’:2,'cat':1,'fish':3,'bird':0} 字典形式呈现,key:词,value:词频
print(cv_fit)
print(cv_fit.toarray()) #.toarray() 是将结果转化为稀疏矩阵矩阵的表示方式;
print(cv_fit.toarray().sum(axis=0))  #每个词在所有文档中的词频

[[1 1 0 1 0 0 0]
 [0 0 1 1 1 0 0]
 [0 0 0 0 0 2 0]
 [0 0 0 0 0 0 1]]
['1', '12', '2', '3', '4', '5', '6']
{'1': 0, '12': 1, '3': 3, '2': 2, '4': 4, '5': 5, '6': 6}
  (0, 0)        1
  (0, 1)        1
  (0, 3)        1
  (1, 3)        1
  (1, 2)        1
  (1, 4)        1
  (2, 5)        2
  (3, 6)        1
[[1 1 0 1 0 0 0]
 [0 0 1 1 1 0 0]
 [0 0 0 0 0 2 0]
 [0 0 0 0 0 0 1]]
[1 1 1 2 1 2 1]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

入门示例


from sklearn.feature_extraction.text import CountVectorizer

texts=["dog cat fish","dog cat cat","fish bird", 'bird'] 

cv = CountVectorizer()#创建词袋数据结构
cv_fit=cv.fit_transform(texts)
#上述代码等价于下面两行
#cv.fit(texts)
#cv_fit=cv.transform(texts)

print(cv.get_feature_names())    
print(cv.vocabulary_	)              

print(cv_fit)


print(cv_fit.toarray()) 

print(cv_fit.toarray().sum(axis=0))  

['bird', 'cat', 'dog', 'fish']
{'dog': 2, 'cat': 1, 'fish': 3, 'bird': 0}
  (0, 2)        1
  (0, 1)        1
  (0, 3)        1
  (1, 2)        1
  (1, 1)        2
  (2, 3)        1
  (2, 0)        1
  (3, 0)        1
[[0 1 1 1]
 [0 2 1 0]
 [1 0 0 1]
 [1 0 0 0]]
[2 3 2 2]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

参考链接

TfidfVectorizer

  • (term frequency-inverse document frequency)
  • 处理文本时如何将文字转化为向量?
  • TF-IDF呀!
  • 字词的重要性与其在文本中出现的频率成正比(TF),
    • 与其在语料库中出现的频率成反比(IDF)

TF

  • TF(w)=(词w在文档中出现的次数)/(文档的总词数)
  • 文档指的是这个文章,不是整个文章的集合!

IDF

  • IDF:逆向文件频率。
  • 有些词在文本中频繁出现,但并不重要,也即信息量小,
  • 如is,of,that,这些单词在语料库中出现的频率也非常大,
  • 我们就可以利用这点,降低其权重
  • IDF(w)=log_e(语料库的总文档数)/(语料库中词w出现的文档数)

在这里插入图片描述

  • TF-IDF=TF*IDF

如何使用?

  • 文本处理中,将一段话变成向量,以组成矩阵来输入到模型中处理
  • 但是我们需要自己找语料库训练TF-IDF吗?
from sklearn.feature_extraction.text import TfidfVectorizer

cv=TfidfVectorizer(binary=False,decode_error='ignore',stop_words='english')
vec=cv.fit_transform(['hello world','this is a panda.'])#传入句子组成的list
arr=vec.toarray()

print(arr)
[[0.70710678 0.         0.70710678]
 [0.         1.         0.        ]]



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 一行代表一个句子样本,这样的矩阵就可放入模型中训练
  • 与TfidfVectorizer类似的还有CountVectorizer
  • 与此相关的概念还有词袋,词集

  • stop_words设为None
from sklearn.feature_extraction.text import TfidfVectorizer

cv=TfidfVectorizer(binary=False,decode_error='ignore',stop_words=None)
vec=cv.fit_transform(['hello world','this is a panda.'])#传入句子组成的list
arr=vec.toarray()
print (arr)
print (cv.get_feature_names())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
runfile('C:/Users/ZTZ/Desktop/temp.py', wdir='C:/Users/ZTZ/Desktop')
[[0.70710678 0.         0.         0.         0.70710678]
 [0.         0.57735027 0.57735027 0.57735027 0.        ]]
['hello', 'is', 'panda', 'this', 'world']
  • 1
  • 2
  • 3
  • 4

参考文献

tf-idf公式及sklearn中TfidfVectorizer

  • 在文本挖掘预处理之向量化与Hash Trick中
  • 文本挖掘的预处理中,向量化之后一般都伴随TF-IDF处理

1 文本向量化特征的不足

  • 将文本分词并向量化后,得到词汇表中每个词在各个文本中形成的词向量,
  • 在文本挖掘预处理之向量化与Hash Trick这篇文章中,
  • 下面4个短文本做词频统计
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
    不考虑停用词,得到的词向量如下:
[[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0]
 [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0]
 [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 直接将统计词频后的19维特征做为文本分类的输入
  • 第一个文本,发现"come","China"和“Travel”各1次,“to“出现两次
  • ”to“是一个非常普遍的词,几乎所有的文本都会用到,
  • 虽然它的词频为2,但重要性却比词频为1的"China"和“Travel”要低的多
  • 向量化特征仅用词频表示就无法反应这一点。
  • 需进一步的预处理来反应文本的这个特征,就是TF-IDF。

2. TF-IDF概述

  • TF也就是我们前面说到的词频,我们之前做的向量化也就是做了文本中各个词的出现频率统计,并作为文本特征
  • “逆文本频率”如何理解
  • 文本都会出现的"to"其词频虽然高,但重要性却应该比词频低的"China"和“Travel”要低。
  • IDF就是来帮助我们来反应这个词的重要性的,进而修正仅仅用词频表示的词特征值。
  • IDF反应一个词在所有文本中出现的频率,
    • 如果一个词在很多的文本中出现,那么它的IDF值应低,
    • 比如上文中的“to”
    • 而反过来如果一个词在比较少的文本中出现,那么它的IDF值应该高。
    • 一些专业的名词如“Machine Learning”。
    • 这样的词IDF值应该高。
    • 一个极端的情况,如果一个词在所有的文本中都出现,那么它的IDF值应为0

3 用scikit-learn进行TF-IDF预处理

  • scikit-learn中,两种方法进行TF-IDF的预处理。

  • 用CountVectorizer类向量化之后再调用TfidfTransformer类预处理。

  • 直接用TfidfVectorizer完成向量化与TF-IDF预处理。

  • 第一种方法,CountVectorizer+TfidfTransformer的组合

  • 各个文本各个词的TF-IDF值



from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer  

corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 

vectorizer=CountVectorizer()

transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))  

print (vectorizer.vocabulary_)

print (tfidf)

runfile('C:/Users/ZTZ/untitled0.py', wdir='C:/Users/ZTZ')
{'come': 4, 'to': 15, 'china': 3, 'travel': 16, 'this': 14, 
 'is': 6, 'car': 2, 'polupar': 9, 'in': 5, 'love': 7, 
 'tea': 12, 'and': 0, 'apple': 1, 'the': 13, 'work': 17, 
 'write': 18, 'some': 11, 'papers': 8, 'science': 10}
  (0, 16)       0.4424621378947393
  (0, 15)       0.697684463383976
  (0, 4)        0.4424621378947393
  (0, 3)        0.348842231691988
  (1, 14)       0.45338639737285463
  (1, 9)        0.45338639737285463
  (1, 6)        0.3574550433419527
  (1, 5)        0.3574550433419527
  (1, 3)        0.3574550433419527
  (1, 2)        0.45338639737285463
  (2, 12)       0.5
  (2, 7)        0.5
  (2, 1)        0.5
  (2, 0)        0.5
  (3, 18)       0.3565798233381452
  (3, 17)       0.3565798233381452
  (3, 15)       0.2811316284405006
  (3, 13)       0.3565798233381452
  (3, 11)       0.3565798233381452
  (3, 10)       0.3565798233381452
  (3, 8)        0.3565798233381452
  (3, 6)        0.2811316284405006
  (3, 5)        0.2811316284405006

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • TfidfVectorizer一步到位

from sklearn.feature_extraction.text import TfidfVectorizer


corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science "] 



tfidf2 = TfidfVectorizer()
re = tfidf2.fit_transform(corpus)
print (type(re))
print (re.toarray())
print (tfidf2.get_feature_names())

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

<class 'scipy.sparse.csr.csr_matrix'>
[[0.         0.         0.         0.34884223 0.44246214 0.
  0.         0.         0.         0.         0.         0.
  0.         0.         0.         0.69768446 0.44246214 0.
  0.        ]
 [0.         0.         0.4533864  0.35745504 0.         0.35745504
  0.35745504 0.         0.         0.4533864  0.         0.
  0.         0.         0.4533864  0.         0.         0.
  0.        ]
 [0.5        0.5        0.         0.         0.         0.
  0.         0.5        0.         0.         0.         0.
  0.5        0.         0.         0.         0.         0.
  0.        ]
 [0.         0.         0.         0.         0.         0.28113163
  0.28113163 0.         0.35657982 0.         0.35657982 0.35657982
  0.         0.35657982 0.         0.28113163 0.         0.35657982
  0.35657982]]
['and', 'apple', 'car', 'china', 'come', 'in', 'is', 'love', 'papers', 'polupar', 'science', 'some', 'tea', 'the', 'this', 'to', 'travel', 'work', 'write']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 第二种方法简洁,推荐使用,一步到位完成向量化,TF-IDF与标准化。

4. TF-IDF小结

  • TF-IDF是常用的文本挖掘预处理基本步骤,
    • 如果预处理中用了Hash Trick,一般就无法用TF-IDF,
    • Hash Trick后我们已经无法得到哈希后的各特征的IDF的值
  • 用IF-IDF并标准化后,就可用各个文本的词特征向量作为文本的特征,进行分类或者聚类
  • 不光可用于文本挖掘,信息检索等很多领域都有用。
  • 好好理解

联结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/353460
推荐阅读
相关标签
  

闽ICP备14008679号