TF-IDF模型简介
整理了网上的一些资料
TF-IDF是一种用于资讯检索与文本挖掘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TF-IDF实际上是:TF * IDF,TF词频(Term Frequency),IDF逆向文件频率(Inverse Document Frequency)。TF表示词条在文档d中出现的频率。IDF的主要思想是:如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。如果某一类文档C中包含词条t的文档数为m,而其它类包含t的文档总数为k,显然所有包含t的文档数n=m+k,当m大的时候,n也大,按照IDF公式得到的IDF的值会小,就说明该词条t类别区分能力不强。但是实际上,如果一个词条在一个类的文档中频繁出现,则说明该词条能够很好代表这个类的文本的特征,这样的词条应该给它们赋予较高的权重,并选来作为该类文本的特征词以区别于其它类文档。这就是IDF的不足之处。 在一份给定的文件里,词频(term frequency,TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数的归一化,以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词数,而不管该词语重要与否。)对于在某一特定文件里的词语来说,它的重要性可表示为:
以上式子中是该词在文件
中的出现次数,而分母则是在文件
中所有字词的出现次数之和。
逆向文件频率(inverse document frequency,IDF)是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到:
其中:
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
注:以上摘自维基百科
C++实现:来源于互联网
#include<map>
#include<set>
#include<string>
#include<iostream>
#include<fstream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
char Comment[]=",.!\"?;:()";
int TextNum=0; //文章数
map<string,float> IDFTable;
map<string,int> WordTable;
struct Words{
string wd;
float freq;
float weight;
};
vector<Words> WordList;
bool cmp(Words &w1,Words &w2)
{
return w1.weight>w2.weight;
}
//判断是不是纯数字
bool IsNumber(string s)
{
for(int i=0;i<s.length();i++){
if(s[i]<'0'||s[i]>'9')
return false;
}
return true;
}
//判空
bool Isblank(string s)
{
for(int i=0;i<s.length();i++){
if(s[i]!=' '&&s[i]!='\t')
return false;
}
return true;
}
//把大写改成小写
string &Lower(string &cs)
{
for(int i=0;i<cs.length();i++)
{
if(cs[i]>'A'&&cs[i]<'Z')
cs[i]+=('a'-'A');
}
return cs;
}
void ReadFile(string fname,set<string> &wds)
{
ifstream fin(fname.c_str());
string word;
wds.clear();
while(!fin.eof())
{
fin>>word;
for(int i=0;Comment[i]!=0;i++)
{
int pos;
//去掉词中最后一个特殊符号
while((pos=word.find(Comment[i]))!=-1)
word.replace(pos,1,"");
}
//如果不是纯数字和空字符串,则加入到set集合中
if(!IsNumber(word)&&!Isblank(word))
wds.insert(Lower(word));
}
fin.close();
}
//计算IDF值
void IDF()
{
TextNum=0;
string files[5]={"first.txt",
"second.txt",
"thrid.txt",
"fourth.txt",
"fifth.txt"
}; //用作训练集
set<string> wds;
for(int i=0;i<5;i++)
{
ReadFile(files[i],wds);
set<string>::iterator it;
for(it=wds.begin();it!=wds.end();++i)
{
map<string,float>::iterator iter;
string word=*it;
if((iter=IDFTable.find(word))!=IDFTable.end())
iter->second+=1;
else
IDFTable[word]=1;
}
TextNum++;
}
for(map<string,float>::iterator iter=IDFTable.begin();
iter!=IDFTable.end();++iter)
iter->second=log((float)TextNum/(iter->second+1.0));
}
int TF()
{
ifstream fin("Test.txt"); //测试的数据
string word;
int textwords=0;
while(!fin.eof())
{
fin>>word;
for(int i=0;Comment[i]!=0;i++)
{
int pos;
while((pos=word.find(Comment[i]))!=-1)
word.replace(pos,1,"");
}
if(!IsNumber(word)&&!Isblank(word))
{
textwords++;
map<string,int>::iterator it;
word=Lower(word);
if((it=WordTable.find(word))!=WordTable.end())
it->second++;
else
WordTable[word]=1;
}
}
fin.close();
for(map<string,int>::iterator it=WordTable.begin();
it!=WordTable.end();++it)
{
Words wd;
wd.wd=it->first;
wd.freq=(float)(it->second)/textwords;
float idf=0;
map<string,float>::iterator iter;
if((iter=IDFTable.find(wd.wd))!=IDFTable.end())
idf=iter->second;
else
idf=log((float)TextNum);
wd.weight=wd.freq*idf;
WordList.push_back(wd);
}
return textwords;
}
void Sort()
{
sort(WordList.begin(),WordList.end(),cmp);
}
int main()
{
IDF();
int txtwd=TF();
Sort();
int topnum=10;
cout<<"Total Words: "<<txtwd<<" Top "<<topnum<<":\n";
cout<<"Wrod\t\tweight\n";
for(int i=0;i<topnum;i++)
cout<<WordList[i].wd<<"\t\t"<<WordList[i].weight<<endl;
}