赞
踩
继续做早鸟,首先这一期的任务提纲:
感觉在word2vec 特别是现在的contextual word embedding之后,利用tf-idf直接向量化文本几乎已经弃用了,但是tf-idf作为权重,用来进行句子或者篇章中词向量的加权,也依然在被使用。
第一次接触tf-idf是很早以前,读吴军先生的《数学之类》[5]的时候,当时就被一系列文本向量化的表示和操作所吸引。回到主题,tf-idf实际上是两个指标,即tf Term Frequency,词频,idf Inverse Document Frequency 逆文本频率 。
TF-IDF的主要思想是:如果某个词在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词具有很好的类别区分能力,适合用来分类。
形式化的表达为:
t
f
i
,
j
=
n
i
,
j
∑
k
n
k
,
j
tf_{i,j} = \frac{n_{i,j}}{\sum_k n_{k,j}}
tfi,j=∑knk,jni,j,
i
d
f
i
=
∣
D
∣
∣
j
:
t
i
∈
D
j
∣
idf_i = \frac{|D|}{|{j:t_i \in D_j}|}
idfi=∣j:ti∈Dj∣∣D∣,
t
f
tf
tf-
i
d
f
i
=
t
f
i
,
j
∗
i
d
f
i
idf _i= tf_{i,j} * idf_i
idfi=tfi,j∗idfi。其中i 表示词
i
i
i ,
j
j
j 表示所属文章
D
j
D_j
Dj,
∣
x
∣
|x|
∣x∣ 表示集合
x
x
x中元素的个数。
直接上代码
# -*- coding: utf-8 -*- # @Time : 2019/4/12 11:43 # @Author : Lei Wang # @Site : # @File : tfidf.py # @Software: PyCharm import pkuseg from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_extraction.text import TfidfTransformer text = [] with open(r'..\cnews\cnews.train.txt', 'r', encoding = 'utf-8') as fsource: text_line= fsource.readline() seg = pkuseg.pkuseg() seg_list = seg.cut(text_line) text.extend(seg_list) with open(r'..\stoplist_baidu.txt', 'r', encoding = 'utf-8') as fstop: content = fstop.read() stop_words = content.split('\n') count_vectorizer = CountVectorizer(stop_words=stop_words) tfidf_transformer = TfidfTransformer() tfidf = tfidf_transformer.fit_transform(count_vectorizer.fit_transform(text)) print (tfidf) print('-------------给个小一点的例子--------------') corpus = [ 'This is the first document.', 'This is the second second document.', 'And the third one.', 'Is this the first document?', ] s_count_vectorizer = CountVectorizer() s_tfidf_transformer = TfidfTransformer() s_tfidf = s_tfidf_transformer.fit_transform(s_count_vectorizer.fit_transform(corpus)) print (s_tfidf)
结果截图:
谈起互信息这个话题,还是依着《数学之美》[5]思路,先从信息和熵的定义开始说。信息是用来消除不确定性的。换句话说,知道的信息越多,不确定性就越低。对于一个变量 X X X,如果我们知道,我们知道它的分布 P ( X ) P(X) P(X), 则可以定义它的信息熵为: H ( X ) = − ∑ x ∈ X P ( x ) l o g P ( x ) H(X) = - \sum_{x \in X} P(x) logP(x) H(X)=−∑x∈XP(x)logP(x)。 这里继续给出条件熵的概念,类比于条件概率分布, H ( X ∣ Y ) = − ∑ x ∈ X , y ∈ Y P ( x , y ) l o g P ( x ∣ y ) H(X|Y)=-\sum_{x \in X,y \in Y} P(x,y)logP(x|y) H(X∣Y)=−∑x∈X,y∈YP(x,y)logP(x∣y)那么问题来了,互信息呢? 互信息其实是用来度量两个事件的相关性,其定义如下:
I ( X ; Y ) = − ∑ x ∈ X , y ∈ Y P ( x , y ) P ( x ) P ( y ) = H ( X ) − H ( X ∣ Y ) I(X;Y) = -\sum_{x \in X,y \in Y} \frac{P(x,y)}{P(x)P(y)} = H(X) - H(X|Y) I(X;Y)=−∑x∈X,y∈YP(x)P(y)P(x,y)=H(X)−H(X∣Y)
关于互信息,其实我当年做过一个很有意思的推导,就是想推导多元的互信息熵。我当时只是推导了三元,基本结论是
I
(
X
;
Y
;
Z
)
=
I
(
X
;
Y
)
−
I
(
X
;
Y
∣
Z
)
=
I
(
X
;
Y
)
−
∑
l
o
g
P
(
x
y
z
)
P
(
z
)
P
(
x
z
)
P
(
y
z
)
I(X;Y;Z) = I(X;Y) - I(X;Y|Z) = I(X;Y) - \sum log\frac{P(xyz)P(z)}{P(xz)P(yz)}
I(X;Y;Z)=I(X;Y)−I(X;Y∣Z)=I(X;Y)−∑logP(xz)P(yz)P(xyz)P(z)
正确性有待各位有心的观众检验,多元互信息的表达我参考文献[6]。
关于互信息,数学之美上还有一个关于tf-idf的信息学解释,有兴趣可以去看书的108-109页的相关内容,写的非常清晰易懂,这里就不再赘述了。
既然写到这里,那就顺便写一下深度学习中最常用的相对熵和交叉熵。相对熵,也就是KL散度的定义,他是用来衡量两个取值为正的函数f(X)和g(X)的相似性,即
K
L
(
f
(
X
)
∣
∣
g
(
X
)
)
=
∑
x
∈
X
f
(
x
)
l
o
g
f
(
x
)
g
(
x
)
KL(f(X)||g(X))=\sum_{x \in X} f(x) log\frac{f(x)}{g(x)}
KL(f(X)∣∣g(X))=∑x∈Xf(x)logg(x)f(x), 而交叉熵则是
H
(
f
(
x
)
,
g
(
x
)
)
=
−
∑
x
∈
X
f
(
x
)
l
o
g
g
(
x
)
=
H
(
f
(
x
)
)
+
K
L
(
f
(
x
)
∣
∣
g
(
x
)
)
H(f(x),g(x))=-\sum_{x \in X} f(x) logg(x) = H(f(x)) +KL(f(x)||g(x))
H(f(x),g(x))=−∑x∈Xf(x)logg(x)=H(f(x))+KL(f(x)∣∣g(x))。当然这两个熵也都有对应的连续变量形式的表达。可以看出:
特征选择指的是删除了原始特征里和结果预测关系不大的特征,而不像降维会去做特征的计算组合构成了新的特征。 这里参考了文献[7]
常用的方法有:过滤法,包裹法和嵌入法
方法:评价单个特征和结果之间的相关程度,排序留下Top相关的部分。
评价方式:Pearson相关系数、互信息
缺点:没有考虑到特征之间的关联作用,可能把有用的关联特征踢掉。因此工业界使用的比较少
python包:SelectKBest指定过滤个数、SelectPercentile指定过滤的百分比
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
iris = load_iris()
X, y = iris.data, iris.target
X.shape
(150, 4)
X_new = SelectKBest(chi2, k = 2).fit_transform(X, y)
X_new.shape
(150, 2)
方法:把特征选择看做一个特征子集搜索问题,筛选各种特征子集,用模型评估效果(递归特征删除算法,RFE)。
应用在LR上过程:用全量特征跑一个模型;删掉5~10%的弱特征,观察准确率/AUC的变化;逐步进行,直至准确率/AUC出现大的下滑停止。
python:RFE
from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_boston
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
lr = LinearRegression()
rfe = RFE(lr, n_features_to_select = 1)
rfe.fit(X, Y)
print("Features sorted by their rank:")
print(sorted(zip(map(lambda x: round(x, 4), rfe.ranking_),names)))
Features sorted by their rank:
[(1, ‘NOX’), (2, ‘RM’), (3, ‘CHAS’), (4, ‘PTRATIO’), (5, ‘DIS’), (6, ‘LSTAT’), (7, ‘RAD’), (8, ‘CRIM’), (9, ‘INDUS’), (10, ‘ZN’), (11, ‘TAX’), (12, ‘B’), (13, ‘AGE’)]
方法:根据模型来分析特征重要性,最常见的方式为正则化方式来做特征选择
举例:举个例子,最早在电商用LR做CRT预估,在3-5亿维系数的特征上用L1正则化的LR模型。剩余2-3千万的feature,意味着其他的feature的重要程度不够。
python:feature_selection.SelectFromModel选出权重不为0的特征
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
iris = load_iris()
X, y = iris.data, iris.target
X.shape
(150, 4)
lsvc = LinearSVC(C = 0.01, penalty = "l1", dual = False).fit(X, y)
model = SelectFromModel(lsvc, prefit = True)
X_new = model.transform(X)
X_new.shape
(150, 3)
回到主题,如何利用互信息进行特征筛选, 还是利用sklearn的库,因为这个需要标签,所以用了IMDB,代码如下
# -*- coding: utf-8 -*- # @Time : 2019/4/13 12:11 # @Author : Lei Wang # @Site : # @File : feature_selection.py # @Software: PyCharm from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import mutual_info_classif #选择K个最好的特征,返回选择特征后的数据 #arr = SelectKBest(mutual_info_classif, k=2).fit_transform(tfidf, target[:99]) from nltk.corpus import stopwords import collections import pandas as pd import numpy as np import os import codecs pos_list=[] with open('../Sentiment_IMDB/aclImdb/train/pos_all.txt','r',encoding='utf8')as f: line=f.readlines() pos_list.extend(line) neg_list=[] with open('../Sentiment_IMDB/aclImdb/train/neg_all.txt','r',encoding='utf8')as f: line=f.readlines() neg_list.extend(line) #创建标签 label=[1 for i in range(12500)] label.extend([0 for i in range(12499)]) #评论内容整合 content=pos_list.extend(neg_list) content=pos_list stop_words=set(stopwords.words('english')) count_vectorizer = CountVectorizer(stop_words=stop_words) tfidf_transformer = TfidfTransformer() tfidf = tfidf_transformer.fit_transform(count_vectorizer.fit_transform(content)) print (tfidf.shape) arr = SelectKBest(mutual_info_classif, k=2).fit_transform(tfidf[:24999], label) print(arr)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。