• sklearn之特征提取(文本特征)


    1、引言

    关于文本的提取有很多方法,本文主要探索下sklearn官方的文本特征提取功能。

    2、文本特征提取

    文本分析是机器学习算法的主要应用领域。 然而,原始数据,符号文字序列不能直接传递给算法,因为它们大多数要求具有固定长度的数字矩阵特征向量,而不是具有可变长度的原始文本文档。

    sklearn提供三种方法:

    令牌化, 对每个可能的词令牌分成字符串并赋予整数形的id,例如通过使用空格和标点符号作为令牌分隔符。

    统计,每个词令牌在文档中的出现次数。

    标准化,在大多数的文档 / 样本中,可以减少重要的次令牌的出现次数的权重。

    总的来说,方法是把文本文档集合转化成特征向量,比如每一行是一个文档,每一列是词id。

    由于词的稀疏性,通常使用scipy.sparse 包中的稀疏实现。

    3、使用方法

    类CountVectorizer介绍

    首先类 CountVectorizer 在单个类中实现了 tokenization (词语切分)和 occurrence counting (出现频数统计):

    >>> from sklearn.feature_extraction.text import CountVectorizer
    >>> vectorizer = CountVectorizer()
    >>> corpus = [
    ...     'This is the first document.',
    ...     'This is the second second document.',
    ...     'And the third one.',
    ...     'Is this the first document?',
    ... ]
    >>> X = vectorizer.fit_transform(corpus)
    
    #对每一列进行index
    >>> vectorizer.get_feature_names() == (
    ...     ['and', 'document', 'first', 'is', 'one',
    ...      'second', 'the', 'third', 'this'])
    True
    
    >>> X.toarray()           
    array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
           [0, 1, 0, 1, 0, 2, 1, 0, 1],
           [1, 0, 0, 0, 1, 0, 1, 1, 0],
           [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)
    
    #还可以设置一个或两个词来进行分割,设置两个词的原因是部分语句要连读才有区分度
    >>> bigram_vectorizer = CountVectorizer(ngram_range=(1, 2),
    ...                                     token_pattern=r'w+', min_df=1)
    >>> analyze = bigram_vectorizer.build_analyzer()
    >>> analyze('Bi-grams are cool!') == (
    ...     ['bi', 'grams', 'are', 'cool', 'bi grams', 'grams are', 'are cool'])
    True

    TF-idf项加权

    在一个大的文本语料库中,一些单词将出现很多次(例如 “the”, “a”, “is” 是英文),因此对文档的实际内容没有什么有意义的信息。 如果我们将直接计数数据直接提供给分类器,那么这些频繁词组会掩盖住那些我们关注但很少出现的词。

    为了重新计算特征权重,并将其转化为适合分类器使用的浮点值,因此使用 tf-idf 变换是非常常见的。

    Tf表示 术语频率,而 tf-idf 表示术语频率乘以转制文档频率:

     	ext{tf-idf(t,d)}=	ext{tf(t,d)} 	imes 	ext{idf(t)}.

    术语频率,一个术语在给定文档中出现的次数乘以 idf 组件, 计算为

    	ext{idf}(t) = log{frac{1 + n_d}{1+	ext{df}(d,t)}} + 1,

    其中 n_d 是文档的总数,	ext{df}(d,t) 是包含术语 t 的文档数。 然后,所得到的 tf-idf 向量通过欧几里得范数归一化:

    v_{norm} = frac{v}{||v||_2} = frac{v}{sqrt{v{_1}^2 + v{_2}^2 + dots + v{_n}^2}}.

    它源于一个词权重的信息检索方式(作为搜索引擎结果的评级函数),同时也在文档分类和聚类中表现良好。

    以下部分包含进一步说明和示例,说明如何精确计算 tf-idfs 以及如何在 scikit-learn 中计算 tf-idfs, TfidfTransformer 并 TfidfVectorizer 与定义 idf 的标准教科书符号略有不同

    	ext{idf}(t) = log{frac{n_d}{1+	ext{df}(d,t)}}.

    在 TfidfTransformer 和 TfidfVectorizer 中 smooth_idf=False,将 “1” 计数添加到 idf 而不是 idf 的分母:

    	ext{idf}(t) = log{frac{n_d}{	ext{df}(d,t)}} + 1

    >>> from sklearn.feature_extraction.text import TfidfTransformer
    >>> transformer = TfidfTransformer(smooth_idf=False)
    
    >>> counts = [[3, 0, 1],
    ...           [2, 0, 0],
    ...           [3, 0, 0],
    ...           [4, 0, 0],
    ...           [3, 2, 0],
    ...           [3, 0, 2]]
    ...
    >>> tfidf = transformer.fit_transform(counts)
    >>> tfidf.toarray()                        
    array([[ 0.81940995,  0.        ,  0.57320793],
           [ 1.        ,  0.        ,  0.        ],
           [ 1.        ,  0.        ,  0.        ],
           [ 1.        ,  0.        ,  0.        ],
           [ 0.47330339,  0.88089948,  0.        ],
           [ 0.58149261,  0.        ,  0.81355169]])

    每行都被正则化,使其适应欧几里得标准:

    v_{norm} = frac{v}{||v||_2} = frac{v}{sqrt{v{_1}^2 + v{_2}^2 + dots + v{_n}^2}}

    例如,我们可以计算`计数`数组中第一个文档中第一个项的 tf-idf ,如下所示:

    n_{d, {	ext{term1}}} = 6

    	ext{df}(d, t)_{	ext{term1}} = 6

    	ext{idf}(d, t)_{	ext{term1}} = log frac{n_d}{	ext{df}(d, t)} + 1 = log(1)+1 = 1

    	ext{tf-idf}_{	ext{term1}} = 	ext{tf} 	imes 	ext{idf} = 3 	imes 1 = 3

    现在,如果我们对文档中剩下的2个术语重复这个计算,我们得到:

    	ext{tf-idf}_{	ext{term2}} = 0 	imes log(6/1)+1 = 0

    	ext{tf-idf}_{	ext{term3}} = 1 	imes log(6/2)+1 approx 2.0986

    和原始 tf-idfs 的向量:

    	ext{tf-idf}_raw = [3, 0, 2.0986].

    然后,应用欧几里德(L2)规范,我们获得文档1的以下 tf-idfs:

    frac{[3, 0, 2.0986]}{sqrt{ig(3^2 + 0^2 + 2.0986^2ig)}} = [ 0.819,  0,  0.573].

    通过 拟合 方法调用计算的每个特征的权重存储在模型属性中:

    >>> transformer.idf_                       
    array([ 1. ...,  2.25...,  1.84...])

    虽然tf-idf标准化通常非常有用,但是可能有一种情况是二元变量显示会提供更好的特征。 这可以使用类 CountVectorizer 的 二进制 参数来实现。 特别地,一些估计器,诸如 伯努利朴素贝叶斯 显式的使用离散的布尔随机变量。 而且,非常短的文本很可能影响 tf-idf 值,而二进制出现信息更稳定。

    通常情况下,调整特征提取参数的最佳方法是使用基于网格搜索的交叉验证,例如通过将特征提取器与分类器进行流水线化。

    词语表示的限制

    直接看例子

    >>> ngram_vectorizer = CountVectorizer(analyzer='char_wb', ngram_range=(2, 2))
    >>> counts = ngram_vectorizer.fit_transform(['words', 'wprds'])
    >>> ngram_vectorizer.get_feature_names() == (
    ...     [' w', 'ds', 'or', 'pr', 'rd', 's ', 'wo', 'wp'])
    True
    >>> counts.toarray().astype(int)
    array([[1, 1, 1, 0, 1, 1, 1, 0],
           [1, 1, 0, 1, 1, 1, 0, 1]])
    
    
    >>> ngram_vectorizer = CountVectorizer(analyzer='char_wb', ngram_range=(5, 5))
    >>> ngram_vectorizer.fit_transform(['jumpy fox'])
    ...                                
    <1x4 sparse matrix of type '<... 'numpy.int64'>'
       with 4 stored elements in Compressed Sparse ... format>
    >>> ngram_vectorizer.get_feature_names() == (
    ...     [' fox ', ' jump', 'jumpy', 'umpy '])
    True
    
    >>> ngram_vectorizer = CountVectorizer(analyzer='char', ngram_range=(5, 5))
    >>> ngram_vectorizer.fit_transform(['jumpy fox'])
    ...                                
    <1x5 sparse matrix of type '<... 'numpy.int64'>'
        with 5 stored elements in Compressed Sparse ... format>
    >>> ngram_vectorizer.get_feature_names() == (
    ...     ['jumpy', 'mpy f', 'py fo', 'umpy ', 'y fox'])
    True

    对比以上几种例子,我们可以知道:

    对于使用白色空格进行单词分离的语言,对于语言边界感知变体 char_wb 尤其有趣,因为在这种情况下,它会产生比原始 char 变体显着更少的噪音特征。 对于这样的语言,它可以增加使用这些特征训练的分类器的预测精度和收敛速度,同时保持关于拼写错误和词导出的稳健性。

    虽然可以通过提取 n-gram 而不是单独的单词来保存一些本地定位信息,但是包含 n-gram 的单词和袋子可以破坏文档的大部分内部结构,因此破坏了该内部结构的大部分含义。

    为了处理自然语言理解的更广泛的任务,因此应考虑到句子和段落的地方结构。因此,许多这样的模型将被称为 “结构化输出” 问题,这些问题目前不在 scikit-learn 的范围之内。

  • 相关阅读:
    div在父集高度未知的情况下垂直居中的方法
    固比固布局 圣杯布局 css实现传统手机app布局
    img标签的onerror事件
    vue中的swiper element ui
    前后端分离跨域 关于前后端分离开发环境下的跨域访问问题(angular proxy=>nginx )
    自己开发的网页在跳转至微信公众号文章后,点击微信的返回,无法返回原网页
    关于audio元素在实际项目中遇到的问题总结
    移动端HTML5<video>视频播放优化实践
    数据类型转换
    穿越宇宙的邀请函——镜像图片技巧
  • 原文地址:https://www.cnblogs.com/hotsnow/p/9512413.html
Copyright © 2020-2023  润新知