TF-IDF(转)

From:http://www.cnblogs.com/ywl925/archive/2013/08/26/3275878.html

TF-IDF

前言

前段时间,又具体看了自己以前整理的TF-IDF,这里把它发布在博客上,知识就是需要不断的重复的,否则就感觉生疏了。

TF-IDF理解

TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与资讯探勘的常用加权技术, TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是: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的不足之处.

TF公式:

\mathrm{tf_{i,j}} = \frac{n_{i,j}}{\sum_k n_{k,j}}

以上式子中 n_{i,j} 是该词在文件d_{j}中的出现次数,而分母则是在文件d_{j}中所有字词的出现次数之和。

IDF公式:

\mathrm{idf_{i}} = \log \frac{|D|}{|\{j: t_{i} \in d_{j}\}|}

|D|:语料库中的文件总数
|\{ j: t_{i} \in d_{j}\}| :包含词语 t_{i} 的文件数目(即 n_{i,j} \neq 0的文件数目)如果该词语不在语料库中,就会导致被除数为零,因此一般情况下使用1 + |\{j : t_{i} \in d_{j}\}|
然后
\mathrm{tf{}idf_{i,j}} = \mathrm{tf_{i,j}} \times \mathrm{idf_{i}}
TF-IDF案例

案例:假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频就是3/100=0.03。一个计算文件频率 (DF) 的方法是测定有多少份文件出现过“母牛”一词,然后除以文件集里包含的文件总数。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是 lg(10,000,000 / 1,000)=4。最后的TF-IDF的分数为0.03 * 4=0.12。

TF-IDF实现(Java)

这里采用了外部插件IKAnalyzer-2012.jar,用其进行分词,插件和测试文件可以从这里下载:点击

具体代码如下:

复制代码
package tfidf;

import java.io.*;
import java.util.*;

import org.wltea.analyzer.lucene.IKAnalyzer;

public class ReadFiles {

/**
* @param args
*/
private static ArrayList<String> FileList = new ArrayList<String>(); // the list of file

//get list of file for the directory, including sub-directory of it
public static List<String> readDirs(String filepath) throws FileNotFoundException, IOException
{
try
{
File file = new File(filepath);
if(!file.isDirectory())
{
System.out.println("输入的[]");
System.out.println("filepath:" + file.getAbsolutePath());
}
else
{
String[] flist = file.list();
for(int i = 0; i < flist.length; i++)
{
File newfile = new File(filepath + "\\" + flist[i]);
if(!newfile.isDirectory())
{
FileList.add(newfile.getAbsolutePath());
}
else if(newfile.isDirectory()) //if file is a directory, call ReadDirs
{
readDirs(filepath + "\\" + flist[i]);
}
}
}
}catch(FileNotFoundException e)
{
System.out.println(e.getMessage());
}
return FileList;
}

//read file
public static String readFile(String file) throws FileNotFoundException, IOException
{
StringBuffer strSb = new StringBuffer(); //String is constant, StringBuffer can be changed.
InputStreamReader inStrR = new InputStreamReader(new FileInputStream(file), "gbk"); //byte streams to character streams
BufferedReader br = new BufferedReader(inStrR);
String line = br.readLine();
while(line != null){
strSb.append(line).append("\r\n");
line = br.readLine();
}

return strSb.toString();
}

//word segmentation
public static ArrayList<String> cutWords(String file) throws IOException{

ArrayList<String> words = new ArrayList<String>();
String text = ReadFiles.readFile(file);
IKAnalyzer analyzer = new IKAnalyzer();
words = analyzer.split(text);

return words;
}

//term frequency in a file, times for each word
public static HashMap<String, Integer> normalTF(ArrayList<String> cutwords){
HashMap<String, Integer> resTF = new HashMap<String, Integer>();

for(String word : cutwords){
if(resTF.get(word) == null){
resTF.put(word, 1);
System.out.println(word);
}
else{
resTF.put(word, resTF.get(word) + 1);
System.out.println(word.toString());
}
}
return resTF;
}

//term frequency in a file, frequency of each word
public static HashMap<String, Float> tf(ArrayList<String> cutwords){
HashMap<String, Float> resTF = new HashMap<String, Float>();

int wordLen = cutwords.size();
HashMap<String, Integer> intTF = ReadFiles.normalTF(cutwords);

Iterator iter = intTF.entrySet().iterator(); //iterator for that get from TF
while(iter.hasNext()){
Map.Entry entry = (Map.Entry)iter.next();
resTF.put(entry.getKey().toString(), Float.parseFloat(entry.getValue().toString()) / wordLen);
System.out.println(entry.getKey().toString() + " = "+ Float.parseFloat(entry.getValue().toString()) / wordLen);
}
return resTF;
}

//tf times for file
public static HashMap<String, HashMap<String, Integer>> normalTFAllFiles(String dirc) throws IOException{
HashMap<String, HashMap<String, Integer>> allNormalTF = new HashMap<String, HashMap<String,Integer>>();

List<String> filelist = ReadFiles.readDirs(dirc);
for(String file : filelist){
HashMap<String, Integer> dict = new HashMap<String, Integer>();
ArrayList<String> cutwords = ReadFiles.cutWords(file); //get cut word for one file

dict = ReadFiles.normalTF(cutwords);
allNormalTF.put(file, dict);
}
return allNormalTF;
}

//tf for all file
public static HashMap<String,HashMap<String, Float>> tfAllFiles(String dirc) throws IOException{
HashMap<String, HashMap<String, Float>> allTF = new HashMap<String, HashMap<String, Float>>();
List<String> filelist = ReadFiles.readDirs(dirc);

for(String file : filelist){
HashMap<String, Float> dict = new HashMap<String, Float>();
ArrayList<String> cutwords = ReadFiles.cutWords(file); //get cut words for one file

dict = ReadFiles.tf(cutwords);
allTF.put(file, dict);
}
return allTF;
}
public static HashMap<String, Float> idf(HashMap<String,HashMap<String, Float>> all_tf){
HashMap<String, Float> resIdf = new HashMap<String, Float>();
HashMap<String, Integer> dict = new HashMap<String, Integer>();
int docNum = FileList.size();

for(int i = 0; i < docNum; i++){
HashMap<String, Float> temp = all_tf.get(FileList.get(i));
Iterator iter = temp.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry = (Map.Entry)iter.next();
String word = entry.getKey().toString();
if(dict.get(word) == null){
dict.put(word, 1);
}else {
dict.put(word, dict.get(word) + 1);
}
}
}
System.out.println("IDF for every word is:");
Iterator iter_dict = dict.entrySet().iterator();
while(iter_dict.hasNext()){
Map.Entry entry = (Map.Entry)iter_dict.next();
float value = (float)Math.log(docNum / Float.parseFloat(entry.getValue().toString()));
resIdf.put(entry.getKey().toString(), value);
System.out.println(entry.getKey().toString() + " = " + value);
}
return resIdf;
}
public static void tf_idf(HashMap<String,HashMap<String, Float>> all_tf,HashMap<String, Float> idfs){
HashMap<String, HashMap<String, Float>> resTfIdf = new HashMap<String, HashMap<String, Float>>();

int docNum = FileList.size();
for(int i = 0; i < docNum; i++){
String filepath = FileList.get(i);
HashMap<String, Float> tfidf = new HashMap<String, Float>();
HashMap<String, Float> temp = all_tf.get(filepath);
Iterator iter = temp.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry = (Map.Entry)iter.next();
String word = entry.getKey().toString();
Float value = (float)Float.parseFloat(entry.getValue().toString()) * idfs.get(word);
tfidf.put(word, value);
}
resTfIdf.put(filepath, tfidf);
}
System.out.println("TF-IDF for Every file is :");
DisTfIdf(resTfIdf);
}
public static void DisTfIdf(HashMap<String, HashMap<String, Float>> tfidf){
Iterator iter1 = tfidf.entrySet().iterator();
while(iter1.hasNext()){
Map.Entry entrys = (Map.Entry)iter1.next();
System.out.println("FileName: " + entrys.getKey().toString());
System.out.print("{");
HashMap<String, Float> temp = (HashMap<String, Float>) entrys.getValue();
Iterator iter2 = temp.entrySet().iterator();
while(iter2.hasNext()){
Map.Entry entry = (Map.Entry)iter2.next();
System.out.print(entry.getKey().toString() + " = " + entry.getValue().toString() + ", ");
}
System.out.println("}");
}

}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String file = "D:/testfiles";

HashMap<String,HashMap<String, Float>> all_tf = tfAllFiles(file);
System.out.println();
HashMap<String, Float> idfs = idf(all_tf);
System.out.println();
tf_idf(all_tf, idfs);

}

}
<think>好的,我现在需要回答用户关于C-TF-IDFTF-IDF之间区别的问题。首先,我得回忆一下这两个概念的基本定义和应用场景。 TF-IDF是信息检索中常用的加权技术,用于评估一个词在文档中的重要程度。TF代表词频,即某个词在文档中出现的次数,而IDF是逆文档频率,衡量该词在所有文档中的普遍重要性。两者的乘积就是TF-IDF值,值越大表示词对文档越重要。用户提供的引用中提到了TFIDF的计算方法,以及ATF-IDF的变体,这对我理解基础概念有帮助,但需要更多关于C-TF-IDF的信息。 接下来,C-TF-IDF,全称Class-based TF-IDF,是专门为文本分类任务设计的改进版本。它调整了传统的TF-IDF计算方式,考虑了类别级别的信息。根据我的知识,C-TF-IDF在计算时会将同一类别的文档视为一个整体,计算词在该类别中的频率,然后结合跨类别的IDF值。这有助于突出在某个类别内频繁出现但在其他类别中少见的词汇,提升分类效果。 然后,我需要对比两者的区别。首先,应用场景不同:TF-IDF适用于信息检索和一般的文档关键词提取,而C-TF-IDF更适合监督学习的文本分类任务。其次,计算方式上,TF-IDFTF基于单个文档,IDF基于整个文档集合;C-TF-IDFTF则是基于类别内所有文档的总词频,IDF可能跨类别计算。此外,C-TF-IDF通过调整权重,能更好地区分类别特征词,减少常见词的影响。 在用法方面,用户需要明确他们的任务类型。如果是无监督的聚类或检索,TF-IDF更合适;如果是监督分类,特别是需要区分不同类别关键词的情况,C-TF-IDF可能效果更好。不过,实际应用中可能需要根据数据特点进行调整,比如结合其他特征或使用不同的变体。 最后,我需要验证这些信息是否正确。用户提供的引用中提到了ATF-IDF,但未直接涉及C-TF-IDF,所以需要确保我的理解没有偏差。可能需要查阅相关资料确认C-TF-IDF的具体公式和应用案例。例如,C-TF-IDF是否确实将类别作为计算单元,以及它的数学表达式如何。假设正确,我可以总结出两者的主要区别和适用场景,并生成相关问题供用户进一步探索。</think>### C-TF-IDF vs TF-IDF 概念与区别解析 #### 1. **核心概念** - **TF-IDF** 通过词频(Term Frequency)和逆文档频率(Inverse Document Frequency)的乘积衡量词的重要性: $$TF(t, d) = \frac{\text{词 t 在文档 d 中出现的次数}}{\text{文档 d 的总词数}}$$ $$IDF(t) = \log\left(\frac{\text{总文档数}}{\text{包含词 t 的文档数}}\right)$$ $$TF\text{-}IDF(t, d) = TF(t, d) \times IDF(t)$$ 特点:适用于单文档级别的关键词提取,如搜索引擎排序[^1]。 - **C-TF-IDF (Class-based TF-IDF)** 专为文本分类设计,将计算粒度从文档提升到类别: $$TF_c(t, c) = \frac{\text{词 t 在类别 c 所有文档中的总出现次数}}{\text{类别 c 所有文档的总词数}}$$ $$IDF_c(t) = \log\left(\frac{\text{总类别数}}{\text{包含词 t 的类别数}}\right)$$ $$C\text{-}TF\text{-}IDF(t, c) = TF_c(t, c) \times IDF_c(t)$$ 特点:突出类别特有词汇,适用于监督学习任务(如新闻分类)[^2]。 #### 2. **关键区别** | **维度** | **TF-IDF** | **C-TF-IDF** | |----------------|------------------------------|-------------------------------| | 计算粒度 | 单个文档 | 整个类别 | | 应用场景 | 信息检索、关键词提取 | 文本分类、监督学习 | | 核心目标 | 衡量词对单文档的重要性 | 区分词对类别的代表性 | | 抗噪能力 | 易受高频通用词干扰 | 抑制跨类别高频词的影响 | #### 3. **典型用法** - **TF-IDF** ```python from sklearn.feature_extraction.text import TfidfVectorizer corpus = ["文档1文本", "文档2文本"] vectorizer = TfidfVectorizer() X = vectorizer.fit_transform(corpus) ``` 适用场景:搜索引擎结果排序、文档相似度计算。 - **C-TF-IDF** ```python # 假设已通过标签获取类别分组 from sklearn.preprocessing import normalize def c_tf_idf(tf_per_class, count_per_class, total_classes): idf = np.log(total_classes / (1 + np.sum(tf_per_class > 0, axis=1))) tf_idf = tf_per_class * idf[:, None] return normalize(tf_idf, norm='l2', axis=0) ``` 适用场景:新闻主题分类、情感分析中的特征工程。 #### 4. **选择依据** - 选择 **TF-IDF**:需处理无标签数据或关注文档级别的关键词。 - 选择 **C-TF-IDF**:拥有类别标签且需强化类别区分度(如短文本分类)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值