## IDF weighting（Inverse Document Frequency）**

``````逆文档频率权重
Suppose a token t
IDF(t) = log(ND/NDt)
ND表示 the total number of documents;
NDt 表示出现t的文档数量 the number of documents that include t;``````

Document有效长度

Suppose query consists only one token.
Suppose d1 (simlarity 100%),cause d1 consists only one token that just matching the query.

Intuitively, measure Sim(q,d) should take the length of document and query into consideration.

## TF-IDF (Term Frequency-Inverse Document Frequency)

``````TF-IDF weight wtd of term t for document d is:

Wtd = Ftd*IDF(t);

IDF(t) = log(ND/NDt);

IDF(t)越大说明t只在少部分document中出现；
Ftd越大说明t在d中出现的次数越多。

Suppose t is just one term of query q；

t在document q中的权值 等于 t在q中出现的次数*log（总次数/t出现的次数）;``````

``````package com.lbh.tfidf;

import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @Autohor liubh
* @Email lbhbinhao@163.com
* @Date 20200119
*/
public class TfIdf {

/**
* tf-idf算法
* @param token
* @param documents
* Wtd = Ftd*IDF(t);
* IDF(t) = log(ND/NDt);
* @return
*/
public static Map tf_idf(String token, List<List<String>> documents){
//返回结果value 为token对应document的tf_idf值， key 为该token对应的documents index
HashMap<String, Double> result = new HashMap<>();
Integer ND  = documents.size();
Integer NDt = 0;
/**
* 每个document是由token组成的，和句子无关
*/
//记录包含该token的index
ArrayList<Integer> indexes = new ArrayList<>();
for(int i =0; i<documents.size(); i++){
for (String term:documents.get(i)){
if (term.equals(token)){
if (!indexes.contains(i)) {
NDt++;
System.out.println("the document index of all documents is:"+i);
}
continue;
}
}
}
double log_ND_NDt = 0;
if (NDt!=0) {
//double计算
log_ND_NDt = Math.log(ND*1.0/NDt);
}
else{
//模拟NDt无穷小
log_ND_NDt = 0.0001*0.0001*0.0001;
}
System.out.println("the size of documents:"+ND);
System.out.println("the size of token occurs:"+NDt);
for (int i = 0; i<indexes.size(); i++){
System.out.println("the loop of ："+(i+1)+ " times");
List<String> documentConsistsToken = documents.get(indexes.get(i));
Integer numbersOfTokenOfDocument = 0;
for (String word:documentConsistsToken){
if (word.equals(token)){
numbersOfTokenOfDocument++;
}
}
double Wtd = numbersOfTokenOfDocument*log_ND_NDt;
result.put(String.valueOf(indexes.get(i)),Wtd);
}
return result;
}

public static void main(String[] args) {
//        String text = "hello hello hello bye bye";
//        Pattern hello = Pattern.compile("bye");
//        Matcher matcher = hello.matcher(text);
//        int i=0;
//        while (matcher.find()){
//            i++;
//        }
//        System.out.println(i);

String text1 = "两个孤独的灵魂撞到了一起，都有着相同的遭遇而生出共鸣，彼此就像卖火柴的小女孩在冬夜里手中的那小小的火焰，彼此温暖着，但要说这是爱情么我不觉得是。如果继续写下去，玛蒂达会有新的生活，新的故事，这一段只是她人生中的一段回忆罢了，不过这段故事却会刻在他的气质里。就像是里昂给玛蒂达讲的他曾经的那段故事，做成电影并不一定比这段差，这是里昂人生中的一个片段。";
String text2 = "因为有恶警的存在，让我一度认为女孩家里人很无辜。这个人是线人，都会被这样无情的杀戮，太残暴了，尤其是那个弟弟，太舍不得了，这也是小女孩对警察恨之入骨的原因吧。\n" +
"\n" +
"于是她发誓一定要报仇，于是她找他求学。\n" +
"\n" +
"和他一起练习的时候，是他们最开心最安宁的时光了。\n" +
"\n" +
"小女孩更多的是感恩感激以及依赖之情，而里昂是从最开始的同情发展到最后的深沉的爱，甚至到了可以为她付出生命的地步。\n" +
"\n" +
"与其说小女孩因为他有了依靠，不如说他们两个孤独的人，成为了彼此的依靠。她，让他即使是一个杀手，也不太冷。";
String text3 = "爱情很美好，但会害死人。里昂爱的深沉，结局早就注定，就算没有因为爱情死去，也会在这样的生存环境下亡命天涯。玛蒂达不是聪明的小孩，诚如不懂事的年少的自己，一味感情用事，亲手害死自己的爱人。弟弟特别聪明，镇定，如果活着的机会给他，也许里昂的命运也会因此改写，是不一样的结局，两个原生家庭都破碎不堪的人就不该走到认识，于彼此是负担，即使有那么一刻是开心，但悲伤多于快乐。里昂跟托尼全程封闭式沟通，就像一个很有能力的职场精英，脚踏实地，满身才华，善良勤劳，简单纯粹，却没勇气跟雇主提价，也不会明确说出自己的需求，我需要钱，我收手不干，我要过自己的生活，只是在自己的专业领域无比卓越，却不知道怎样去获得自己想要的，完整表达自己的需求，并用智慧或者更多的心机获得，也高估人性，不懂得贪婪的人只会更贪婪。里昂的职业精神跟30岁的我那么接近，相似，突然就很难过，这世间，没有永恒，生命由无数个片段组成，在这个片段精彩，下个片段谢幕。我想，也是时候改变了，内在，外在你都拥有这么多，从此不妨大胆些";
String text4 = "冷面杀手大叔与萝莉的故事。我想，在走廊的初次遇见，就已经有某些情愫产生了。里昂是一个杀手，可最后的结尾却感谢玛蒂达让他有了根。里昂给了玛蒂达生的希望，给了玛蒂达活下去的庇护，给了玛蒂达胜似家人的陪伴。给她关心，给她爱护。替她铺好以后的路。在没有人比里昂对玛蒂达好了。我想里昂一直一直都是爱着玛蒂达的。但是他是一个孤独了多年的杀手，他一个人喝牛奶，一个人坐在黑暗中，他是顶级的杀手。因为他没有顾忌，没有牵绊。可是这样孤单地，冰冷地过一辈子也不过是虚度。所以，在某些方面来说，玛蒂达的出现其实是里昂生命的延续与扩展。";
String text5 = "里昂开门的那一瞬间就注定了他的结局，不过他开门之后度过了一辈子也难以忘怀的一段幸福时光，作为杀手你要想活的久，除了专业技能过硬，就是要有少的羁绊，因为这些羁绊后来可能都成为你的弱点，成为杀死自己的武器，不过人这一辈子，如果没有体会过什么是爱，就算度过了一生也是遗憾满满，哪怕最后是用生命换来的幸福，也值得人回味无穷，他们可以算作不伦恋了，两个人年龄差距非常大，但是在爱情面前，一切看起来都是那么美好，幸福，希望在评论里你们可以相爱到老，心心";

JiebaSegmenter jiebaSegmenter = new JiebaSegmenter();
List<SegToken> process1 = jiebaSegmenter.process(text1, JiebaSegmenter.SegMode.SEARCH);
ArrayList<String> document1 = new ArrayList<>();
for (SegToken word:process1){
}
List<SegToken> process2 = jiebaSegmenter.process(text2, JiebaSegmenter.SegMode.SEARCH);
ArrayList<String> document2 = new ArrayList<>();
for (SegToken word:process2){
}
List<SegToken> process3 = jiebaSegmenter.process(text3, JiebaSegmenter.SegMode.SEARCH);
ArrayList<String> document3 = new ArrayList<>();
for (SegToken word:process3){
}
List<SegToken> process4 = jiebaSegmenter.process(text4, JiebaSegmenter.SegMode.SEARCH);
ArrayList<String> document4 = new ArrayList<>();
for (SegToken word:process4){
}
List<SegToken> process5 = jiebaSegmenter.process(text5, JiebaSegmenter.SegMode.SEARCH);
ArrayList<String> document5 = new ArrayList<>();
for (SegToken word:process5){
}
ArrayList<List<String>> lists = new ArrayList<>();

Map result = tf_idf("杀手", lists);
System.err.println(result);
}
}``````

{1=0.5108256237659907, 3=2.043302495063963, 4=0.5108256237659907}