自然语言处理--特征选择

互信息与点互信息

点互信息

在机器学习领域,经常会用到点互信息PMI这个指标来衡量两个事物之间的相关性(比如两个词)。原理如下:
在这里插入图片描述
若x与y不相关,则p(x,y)=p(x)p(y)。二者相关性越大,则p(x,y)就相比于p(x)p(y)越大。中间那个等式较好理解:在y出现的情况下x出现的概率除以x本身出现的概率,自然就表示x跟y的相关程度。
举个自然语言处理中的例子来说,我们想衡量like这个词的极性(正向情感还是负向情感)。我们可以预先挑选一些正向情感的词,比如good。然后我们算like跟good的PMI。

互信息

点互信息PMI其实就是从信息论里面的互信息这个概念里面衍生出来的。
互信息是信息论里的概念:
在这里插入图片描述
其衡量的是两个随机变量之间的相关性,即一个随机变量中包含的关于另一个随机变量的信息量。所谓的随机变量,即随机试验结果的量的表示,可以简单理解为按照一个概率分布进行取值的变量,比如随机抽查的一个人的身高就是一个随机变量。
可以看出,互信息其实就是对X和Y的所有可能的取值情况的点互信息PMI的加权和。因此,点互信息这个名字还是很形象的。

sklearn编程实现

from sklearn import metrics as mr
mr.mutual_info_score(label,x)

label、x为list或array。
计算x和label的互信息

TF-IDF及TF-IDF值的计算

TF-IDF定义

TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。
前面的TF也就是我们前面说到的词频,向量化就是做了文本中各个词的出现频率统计,并作为文本特征,这个很好理解。后面的这个IDF,即“逆文本频率”。几乎所有文本都会出现的"to"其词频虽然高,但是重要性却应该比词频低的"China"和“Travel”要低。IDF就是来帮助反应这个词的重要性的,进而修正仅仅用词频表示的词特征值。
概括来讲, IDF反应了一个词在所有文本中出现的频率,如果一个词在很多的文本中出现,那么它的IDF值应该低,比如上文中的“to”。而反过来如果一个词在比较少的文本中出现,那么它的IDF值应该高。比如一些专业的名词如“Machine Learning”。这样的词IDF值应该高。一个极端的情况,如果一个词在所有的文本中都出现,那么它的IDF值应该为0。
上面是从定性上说明的IDF的作用,那么如何对一个词的IDF进行定量分析呢?这里直接给出一个词x的IDF的基本公式如下:
在这里插入图片描述
其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词x的文本总数。
上面的IDF公式已经可以使用了,但是在一些特殊的情况会有一些小问题,比如某一个生僻词在语料库中没有,这样分母为0, IDF没有意义了。所以常用的IDF需要做一些平滑,使语料库中没有出现的词也可以得到一个合适的IDF值。平滑的方法有很多种,最常见的IDF平滑后的公式之一为:
在这里插入图片描述
这样就可以计算某一个词的TF-IDF值了:
在这里插入图片描述
其中TF(x)指词x在当前文本中的词频。

计算TF-IDF

语料库:

# 语料库
corpus = [
    'this is the first document',
    'this is the second second document',
    'and the third one',
    'is this the first document'
]

使用gensim提取文本的tfidf特征

# 把语料库做一个分词的处理
word_list = []
for i in range(len(corpus)):
    word_list.append(corpus[i].split(' '))
print(word_list)
>>[['this', 'is', 'the', 'first', 'document'], ['this', 'is', 'the', 'second', 'second', 'document'], ['and', 'the', 'third', 'one'], ['is', 'this', 'the', 'first', 'document']]
# 得到每个词的id值及词频
from gensim import corpora
# 赋给语料库中每个词(不重复的词)一个整数id
dictionary = corpora.Dictionary(word_list)
new_corpus = [dictionary.doc2bow(text) for text in word_list]
print(new_corpus)
# 元组中第一个元素是词语在词典中对应的id,第二个元素是词语在文档中出现的次数
>>[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)], [(0, 1), (2, 1), (3, 1), (4, 1), (5, 2)], [(3, 1), (6, 1), (7, 1), (8, 1)], [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]]
print(dictionary.token2id)
# 通过下面的方法可以看到语料库中每个词对应的id
>>{'document': 0, 'first': 1, 'is': 2, 'the': 3, 'this': 4, 'second': 5, 'and': 6, 'one': 7, 'third': 8}
# 训练模型并保存
from gensim import models
tfidf = models.TfidfModel(new_corpus)
tfidf.save("my_model.tfidf")
# 载入模型
tfidf = models.TfidfModel.load("my_model.tfidf")
# 使用这个训练好的模型得到单词的tfidf值
tfidf_vec = []
for i in range(len(corpus)):
    string = corpus[i]
    string_bow = dictionary.doc2bow(string.lower().split())
    string_tfidf = tfidf[string_bow]
    tfidf_vec.append(string_tfidf)
print(tfidf_vec)
>>[[(0, 0.33699829595119235), (1, 0.8119707171924228), (2, 0.33699829595119235), (4, 0.33699829595119235)], [(0, 0.10212329019650272), (2, 0.10212329019650272), (4, 0.10212329019650272), (5, 0.9842319344536239)], [(6, 0.5773502691896258), (7, 0.5773502691896258), (8, 0.5773502691896258)], [(0, 0.33699829595119235), (1, 0.8119707171924228), (2, 0.33699829595119235), (4, 0.33699829595119235)]]

小测试现出gensim计算的原形

string = "the i first second name"
string_bow = dictionary.doc2bow(string.lower().split())
string_tfidf = tfidf[string_bow]
print(string_tfidf)
>>[(1, 0.4472135954999579), (5, 0.8944271909999159)]

gensim训练出来的tf-idf值左边是词的id,右边是词的tfidf值 gensim有自动去除停用词的功能,比如the gensim会自动去除单个字母,比如i gensim会去除没有被训练到的词,比如name 所以通过gensim并不能计算每个单词的tfidf值。

使用sklearn提取文本tfidf特征

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vec = TfidfVectorizer()
tfidf_matrix = tfidf_vec.fit_transform(corpus)

# 得到语料库所有不重复的词
print("语料库中所有不重复的词:'\n'", tfidf_vec.get_feature_names())

# 得到每个单词对应的id值
print("每个单词对应的id值:'\n'", tfidf_vec.vocabulary_)

# 得到每个句子所对应的向量
# 向量里数字的顺序是按照词语的id顺序来的
print("每个句子所对应的向量:'\n'", tfidf_matrix.toarray())
>>语料库中所有不重复的词:'
' ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
每个单词对应的id值:'
' {'this': 8, 'is': 3, 'the': 6, 'first': 2, 'document': 1, 'second': 5, 'and': 0, 'third': 7, 'one': 4}
每个句子所对应的向量:'
' [[0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]
 [0.         0.27230147 0.         0.27230147 0.         0.85322574
  0.22262429 0.         0.27230147]
 [0.55280532 0.         0.         0.         0.55280532 0.
  0.28847675 0.55280532 0.        ]
 [0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]]

python提取文本的tfidf特征

# 对语料进行分词
word_list = []
for i in range(len(corpus)):
    word_list.append(corpus[i].split(' '))
print(word_list)
>>[['this', 'is', 'the', 'first', 'document'], ['this', 'is', 'the', 'second', 'second', 'document'], ['and', 'the', 'third', 'one'], ['is', 'this', 'the', 'first', 'document']]
# 统计词频
from collections import Counter
countlist = []
for i in range(len(word_list)):
    count = Counter(word_list[i])
    countlist.append(count)
countlist
>>[Counter({'document': 1, 'first': 1, 'is': 1, 'the': 1, 'this': 1}),
 Counter({'document': 1, 'is': 1, 'second': 2, 'the': 1, 'this': 1}),
 Counter({'and': 1, 'one': 1, 'the': 1, 'third': 1}),
 Counter({'document': 1, 'first': 1, 'is': 1, 'the': 1, 'this': 1})]

定义计算tfidf公式的函数

# word可以通过count得到,count可以通过countlist得到

# count[word]可以得到每个单词的词频, sum(count.values())得到整个句子的单词总数
def tf(word, count):
    return count[word] / sum(count.values())

# 统计的是含有该单词的句子数
def n_containing(word, count_list):
    return sum(1 for count in count_list if word in count)
 
# len(count_list)是指句子的总数,n_containing(word, count_list)是指含有该单词的句子的总数,加1是为了防止分母为0
def idf(word, count_list):
    return math.log(len(count_list) / (1 + n_containing(word, count_list)))

# 将tf和idf相乘
def tfidf(word, count, count_list):
    return tf(word, count) * idf(word, count_list)
# 计算每个单词的tfidf值
import math
for i, count in enumerate(countlist):
    print("Top words in document {}".format(i + 1))
    scores = {word: tfidf(word, count, countlist) for word in count}
    sorted_words = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    for word, score in sorted_words[:]:
        print("\tWord: {}, TF-IDF: {}".format(word, round(score, 5)))
>>
Top words in document 1
	Word: first, TF-IDF: 0.05754
	Word: this, TF-IDF: 0.0
	Word: is, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.04463
Top words in document 2
	Word: second, TF-IDF: 0.23105
	Word: this, TF-IDF: 0.0
	Word: is, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.03719
Top words in document 3
	Word: and, TF-IDF: 0.17329
	Word: third, TF-IDF: 0.17329
	Word: one, TF-IDF: 0.17329
	Word: the, TF-IDF: -0.05579
Top words in document 4
	Word: first, TF-IDF: 0.05754
	Word: is, TF-IDF: 0.0
	Word: this, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.04463

参考资料

互信息与点互信息
使用不同方法计算TF-IDF值
TF-IDF

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值