TFIDF的原理及实现

【算法原理】

TFIDF由TF和IDF相乘而来,TF是指某个单词在一个文档中出现次数归一化后的结果;IDF是一个单词普遍重要性的度量。它基本原理是单词的重要性随着它在文档中出现的次数而增加,随着它在所有文档中出现的频率而下降

one-hot矩阵是单词编码的一种方式,它先根据单词在所有文档中的出现顺序建立一个词汇表,然后每个文档对应one-hot矩阵的一行,每行长度为词汇表的大小。根据词汇表中每个单词是否出现在某一篇文档中,如果出现,对应的位置就为1,否则为0。

但one-hot矩阵只表示某个单词是否在文档中出现,并不能表示某个单词的出现次数,所以Bag-of-Words在one-hot基础上做出了改进,其中每一行对应一个文档,每个值对应词表的位置上该词语出现的次数。

但Bag-of-Words的统计方法更偏向于长文档,也就是说同一个词语在长文档里可能会比短文件有更高的词频,而不管该词语重要与否,所以TF在此基础上又做出改进,进将各词频归一化以消除文件长度的影响。所以得到TF的公式如下

t f i , d = n i , d ∑ k n k , d tf_{i,d}=\frac{n_{i,d}}{\sum_k{n_{k,d}}} tfi,d=knk,dni,d

上式中 n i , d n_{i,d} ni,d​是指单词 i i i在文档 d d d中出现的次数,而分母则是文档 d d d中所有单词出现的次数之和。

TF虽然能表示一个单词在一个文档中的重要性,但不能表示它和所有文档的关系,因为一个单词的重要性还会随着出现的文档数而下降,因此又引入一个指标IDF(反文档频率)它的公式如下:

i d f i = l o g ∣ D ∣ ∣ j : t i ∈ d j ∣ idf_i=log\frac{|D|}{|{j:t_i\in{d_j}}|} idfi=logj:tidjD​​

上式中 ∣ D ∣ |D| D​表示总的文档数,分母则表示单词 i i i​出现的文档总数,如果一个单词出现的次数越少,由于 ∣ D ∣ |D| D​是固定的,则 ∣ D ∣ ∣ j : t i ∈ d j ∣ \frac{|D|}{|{j:t_i\in{d_j}}|} j:tidjD​的值越大,则 i d f i idf_i idfi​​ 越大,表示该单词越重要,反之亦然。为了进一步改进,会在分母+1,主要为了防止分母出现0,如下式:

i d f i = l o g ∣ D ∣ ∣ j : t i ∈ d j ∣ + 1 idf_i=log\frac{|D|}{|{j:t_i\in{d_j}}|+1} idfi=logj:tidj+1D

至此,我们就可以将反文档频率和词频相乘,作为TFIDF矩阵的一个元素

i f i d f i , j = t f i , j × i d f i ifidf_{i,j}=tf_{i,j}\times idf_i ifidfi,j=tfi,j×idfi

【关键代码】

1.定义的全局变量

vector<vector<string>> words;  //存储所有的单词,words[i][j] 表示第i个文档的第j个单词。
unordered_map<string,int> dict; //hash,存储单词表,每个键值对表示<单词,出现顺序> dict[wordd[i][j]]表示第i个文档中第j个单词在单词表中的序号。 
vector<int> appear; //appear[i] 表示出现了单词i的文章数,
int index; //记录此时单词出现的次序

2.统计每个单词在文档中出现的次数以及出现的文档数

void get_data (vector<vector<double>>& TFIDF) {
    for (int i = 0; i < words.size(); i++) {//遍历每个单词
        for (int j = 0; j < words[i].size(); j++) {
            if (TFIDF[i][dict[words[i][j]]] == 0) appear[dict[words[i][j]]]++; // 如果words[i][j] 还没有在文档i中出现过,说明该单词在一篇新文章出现了。
            TFIDF[i][dict[words[i][j]]]++;   //文档i中单词j的出现次数加1;
        }
    }
}

3.根据统计结果计算每个tfidf值

void get_TFIDF (vector<vector<double>>& TFIDF) {
    for (int i = 0; i < words.size(); i++) {  //处理文档i
        for (int j = 0; j < dict.size(); j++) { //处理文档i中单词表中顺序为j的单词
            TFIDF[i][j] = TFIDF[i][j] * log((double)words.size() / (1.0 + (double)appear[j])) / (double) words[i].size();  //根据工式计算每个值
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值