北太天元学习43-文本分析之词频-逆文档频率
我们搜集了很多文档,把这些文档作为一个集合来研究。 我们确定了一批单词(这些单词可以是把这些文档的所有的不同的单词都找出来,然后剔除到一些意义不大的单词之后得到的), 然后就得到了 文档-单词 矩阵, 每一行表示一个文档(每一行的文档两两不同),每一列表示一个单词(每一列的单词两两不同), 文档i中单词j中出现的次数 是矩阵的(i,j) 元, 例如
单词1 单词2 单词3
文档1 0 2 3
文档2 1 0 1
这个文档-单词矩阵表示 单词1 在文档1 中出现了0 次, 在文档2 中出现了1次, 那么我们可以看到,在我们搜索的搜有文档中,文档1中单词1出现了0次,单词2出现了2次,单词3出现了3次, 其中在文档1中单词1出现的次数占比是 0/5, 单词2出现的次数占比是 2/5, 单词3总出现的次数占比是 3/5, 我们我们就定义 文档1中单词1 , 2, 3 的词频是 0/5, 2/5, 3/5 。 类似的,我们可以得到文档2 单词 1 2 3 的词频, 这样我们就得到了词频矩阵
词频(term frequency)矩阵(有时候就简称为词频了)
单词1 单词2 单词3
文档1 0/5 2/5 3/5
文档2 1 /2 0/2 1/2
matrix_tf = [ 0/5 2/5 3/5;
1 /2 0/2 1/2 ];
北太天元命令行窗口输入matrix_tf

单词3 在文档1 中的词频是3/5,比单词2在文档1中的词频2/5高,我们应该觉得单词3更能体现文档3的特色,因此单词应该对文章1的重要性更大,但是我们又观察到单词3在文档2中的词频是 1/2, 而单词2在文档2的词频是0/2, 那么我们又会猜测 单词3可能是个常用单词,在很多文档中都会出现,因此它对一个文章的重要性不是那么大,而单词2仅仅在文档1中出现,它对文档1的重要性可能应该更大。于是我们就引入了逆文档频率(inverse document freqency):
单词3 的 逆文档频率可以定义成:
idf_3 = log( 文档总数 / 包含单词3的文档数 )
针对我们上面这个例子,文档总数是2,包含单词3的文档总数也是2, 因此,
idf_3 = log( 2/ 2 ) = 0
类似的,我们可以得到单词1 的逆文档频率是
idf_1 = log( 2/ 1 )
类似的,我们可以得到单词2的逆文档频率是
idf_2 = log(2/1)
逆文档频率矩阵是一个 1x3 的矩阵
matrix_idf = [ log(2/1), log(2/1), log(2/2) ]
这里的 diag(matrix_idf) 是从1x3的向量构造一个3x3的对角阵, 看北太天元的执行结果

最后,我们得到的 tf-idf 矩阵是
matrix_tf_idf = matrix_tf * diag( matrix_idf )

matrix_tf 乘以一个对角矩阵,相当于每一列乘以对角矩阵相应的对角元, 本来 matrix_tf 的第3列的元素都很大,但是乘以第个单词的逆文档频率0之后,在 tf-idf 矩阵中第三个单词的重要性一下子下降到0 了。
下面是完整的计算tf-idf矩阵的北太天元代码,包括函数 tfidf 和两个子函数 tf, idf
新建一个文件 tfidf.m 把下面的代码copy 到tfidf.m 中,一个调用的例子可以是
X = [ 0 0 1 2 1; 1 0 1 0 1; 2 1 0 0 0; 0 1 1 0 0; 0 1 0 2 3; 0 1 0 0 1 ]
Y = tfidf(X)
得到如下图的运行结果

%北太天元计算 tf-idf
% tf-idf(term frequency–inverse document frequency)
% tf-idf是一种统计方法,用以评估一个单词对于一个文挡集或一个语料库中的其中
%一份文档的重要程度。单词的重要性随着它在一个文档中出现的次数成正比增加,
% 但同时会随着它在语料库中出现的频率成反比下降(如果这个单词在所有的
% 文档中都出现,那么它就不重要,例如the 这个冠词。)。
% tf是词频(Term Frequency),
%idf是逆文档频率(Inverse Document Frequency)。
%
% 函数 计算TF-IDF
%
% Y = tfidf( X );
%
% 输入:
% X - 文档-单词矩阵(每一行表示一个文档,每一列表示一个单词)
% X(i,j) 表示文档i中单词j出现的次数
%
% 输出:
% Y - tf-idf 文档-单词矩阵(每一行表示一个文档,每一列表示
% 一个单词, Y(i,j) 表示文档i 中单词j 的 tf-idf
% 例如: 我么通过处理6个文档,只考虑5个单词,然后得到文档-单词矩阵如下:
% X = [ 0 0 1 2 1; 1 0 1 0 1; 2 1 0 0 0; 0 1 1 0 0; 0 1 0 2 3; 0 1 0 0 1 ]
% Y = tfidf(X)
function Y = tfidf( X )
% 获得词频
X = tf(X);
% 获得逆文档频率
I = idf(X);
% 词频(tf) 乘以 这个单词的逆文档频率(idf)
Y = X* diag( I );
end
function X = tf(X)
% 子函数-计算词频
% 对于每一个文档
for i=1:size(X, 1)
%对于第i个文档,所有单词出现的次数组成的向量
x = X(i, :);
% 在文档i中单词次数都加起来
sumX = sum( x );
% 计算单词i出现的频率
if sumX ~= 0
X(i, :) = x / sumX;
else
% 避免0作除数
X(i, :) = 0;
end
end
end
function I = idf(X)
% 子函数 计算 逆文档频率
% m - 文档个数
% n - 单词个数
[m, n]=size(X);
% 预先为逆文档频率分配分配存储
I = zeros(1,n);
% 对于每一个单词
for j=1:n
%统计出现单词j的文档的个数
nz = nnz( X(:, j) ); % nnz 得到的是矩阵的非零元的个数
% 如果nz不是0,那么计算一个权重作为逆文档评率
if nz
I(j) = log( m / nz );
end
end
end