`
zhaohuafei
  • 浏览: 27217 次
文章分类
社区版块
存档分类
最新评论

TF-IDF笔记

 
阅读更多
信息检索的历史发展过程中,出现了很多的模型,模型就是实际问题的抽象。如布尔模型、向量模型。
布尔模型以集合的布尔运算为基础,查询效率高,但只能适用简单搜索问题,同时还要求用户要按照要求拼凑查询串,只能用于特定领域。
向量模型把查询串和文档都是为词所构成的多维向量,查询与文档的相关性用向量间的夹角来表示。向量计算不适用于大规模数据。
TF-IDF(Term Frequency Inverse Doucument Frequency)模型,中文意思是:词频-逆文档频率。
TF-IDF核心思想是“给定的查询串q和文档d的匹配度问题”,这个在搜索引擎中使用广泛。
TF(Term Frequency),即词频,一个词q在文中出现的次数(tf = len(q)/len(all)),一般来说,一个词在一篇文章中出现的次数越多,则这篇文章的意思就越有可能与这个词相关,但是有些词,如“的”、“是”,在文中出现的次数一般都很高,但都没有实际的意义。所以,词频可以衡量一个词与文的相关性,但不能只用它。
IDF(Inverse Doucument Frequency),逆文档频率,即文档总数n与词q所出现文件数n1的比值的对数log(n/n1)。其思想是:词q如果在某篇文章中出现,而在其他文章中很少出现,则q具有很好的区分性,能大致代表出现较多的那篇文章。
最后TF-IDF的值就是:tf*idf,用来表示查询串与文档d的匹配度。这个匹配度,可以从概率的角度来理解,即用户通过查询串q,期望获得文档d的概率。在结果展示中,按从大到小的顺序排列即可,当然,实际中可能还有更多的问题要考虑。

下面是我用Java的实现:
package cn.zhf.cluster;

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

import org.junit.Test;
/**
 * tf-idf实现类
 * 如果是中文,其中input中的txt文件需要先用空格分好词
 * 此类只是简单实现,还有很多问题
 * @author zhaohuafei
 *
 */
public class TFIDF {
    public static final String FILE = "E:/input2/input2.txt";// 单个文件地址
    public static final String FILES = "E:/input2/";// 文档所在目录

    /**
     * Term Frequency - Inverse Document Frequency 给定串在给定文件列表中某一文件的 逆文档频率
     * 
     * @param term
     * @param file
     * @param files
     * @return
     */
    public double tfidf(String term, File file, File[] files) {
        int tf = tf(term, file);
        double idf = idf(term, files);
        return tf * idf;
    }

    /**
     * Term Frequency of a term(word) in a file
     * 
     * @param term
     * @param file
     * @return
     */
    public int tf(String term, File file) {
        if (tfmap(file).get(term) == null)
            return 0;
        return tfmap(file).get(term);
    }

    /**
     * Inverse Document Frequency the number of documents that a term appears
     * 
     * @param term
     * @list the documents that this term appears
     * @return
     */
    public double idf(String term, File[] files) {
        List<Map<String, String>> list = idfmap(files);
        int count = 0;// term出现的文件数
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> map = list.get(i);
            for (Map.Entry<String, String> m : map.entrySet()) {
                if (m.getValue().equals(term))
                    count++;
            }
        }
        return Math.log(files.length / count);
    }

    /**
     * All Term Frequency Map in a file
     * 
     * @param file
     * @return
     */
    public Map<String, Integer> tfmap(File file) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        List<String> list = segment(file);
        for (String term : list)
            map.put(term, !map.containsKey(term) ? 1 : map.get(term) + 1);
        return map;
    }

    /**
     * All Inverse Document Frequency as a map
     * 
     * @param files
     * @return map<filename,term>
     */
    public List<Map<String, String>> idfmap(File[] files) {
        Map<String, Integer> maptf = new HashMap<String, Integer>();
        List<Map<String, String>> list = new LinkedList<Map<String, String>>();
        for (int i = 0; i < files.length; i++) {
            maptf = tfmap(files[i]);
            for (Map.Entry<String, Integer> m : maptf.entrySet()) {
                String key = m.getKey();
                Map<String, String> map = new HashMap<String, String>();
                map.put(files[i].getName(), key);
                list.add(map);
            }
        }
        return list;
    }

    /**检索方法
     * 返回(文档名,tfidf值)
     * 
     * @param query
     * 查询串
     * @return <文档名,tfidf值>,按tfidf值排序
     */
    public Map<String, Double> search(String query, File[] files) {
        Map<String, Double> map = new HashMap<String, Double>();
        for (int i = 0; i < files.length; i++) {
            int tf = tf(query, files[i]);
            if (tf == 0)
                continue;
            double idf = idf(query, files);
            double tfidf = tf * idf;
            map.put(files[i].getName(), tfidf);
        }
        map = sortMapByValueAsc(map);
        return map;
    }

    /**
     * map按值排序 asc
     * 
     * @param map
     * @return
     */
    public static <K, V extends Comparable<? super V>> Map<K, V> sortMapByValueAsc(
            Map<K, V> map) {
        List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(
                map.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
            @Override
            public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
                return (o2.getValue()).compareTo(o1.getValue());
            }
        });
        Map<K, V> ret = new LinkedHashMap<K, V>();
        for (Map.Entry<K, V> m : list) {
            ret.put(m.getKey(), m.getValue());
        }
        return ret;
    }

    /**
     * 简单的分词,假设句子都是以空格隔开的 TODO
     * 
     * @param file
     * @return
     */
    public List<String> segment(File file) {
        List<String> list = new ArrayList<String>();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file), "gbk"));
            String tmp = null, str = null;
            while ((str = br.readLine()) != null) {
                tmp += str;
            }
            String[] s = tmp.split("\\s");
            for (int i = 0; i < s.length; i++)
                list.add(s[i].trim());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    // 以下均为测试
    @Test
    public void test3() {
        int tf = tf("的", new File(FILE));
        System.out.println("TF = " + tf);
        Map<String, Double> map = search("的", new File(FILES).listFiles());
        for (Map.Entry<String, Double> m : map.entrySet()) {
            System.out.println(m.getKey() + "-->" + m.getValue());
        }
    }

    public void test2() {
        File file = new File(FILES);
        File[] files = file.listFiles();
        List<Map<String, String>> list = idfmap(files);
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> map = list.get(i);
            for (Map.Entry<String, String> m : map.entrySet()) {
                System.out.println(m.getKey() + "-->" + m.getValue());
            }
        }
        double tfidf = tfidf("的", new File(FILE), new File(FILES).listFiles());
        System.out.println("count = " + tfidf);
    }

    public void test1() {
        File file = new File(FILE);
        List<String> list = segment(file);
        for (String str : list)
            System.out.println(str);
    }

    public void test() {
        File file = new File(FILES);
        File[] files = file.listFiles();
        for (int i = 0; i < files.length; i++) {
            Map<String, Integer> map = tfmap(files[i]);
            for (Map.Entry<String, Integer> m : map.entrySet()) {
                System.out.println(m.getKey() + "-->" + m.getValue());
            }
        }
    }

}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics