初学Hadoop之计算TF-IDF值
1.词频
TF(term frequency)词频,就是该分词在该文档中出现的频率,算法是:(该分词在该文档出现的次数)/(该文档分词的总数),这个值越大表示这个词越重要,即权重就越大。
例如:一篇文档分词后,总共有500个分词,而分词”Hello”出现的次数是20次,则TF值是: tf =20/500=0.04
考虑到文章有长短之分,为了便于不同文章的比较,进行"词频"标准化。
或者
2.逆文档频率
IDF(inversedocument frequency)逆向文件频率,一个文档库中,一个分词出现在的文档数越少越能和其它文档区别开来。算法是: log(总文档数/(出现该分词的文档数+1)) 。如果一个词越常见,那么分母就越大,逆文档频率就越小越接近0。分母之所以要加1,是为了避免分母为0(即所有文档都不包含该词)。
例如:一个文档库中总共有50篇文档,2篇文档中出现过“Hello”分词,则idf是: Idf = log(50/3) =1.2218487496
3.TF-IDF
TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。
3.1用途
自动提取关键词,计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。
信息检索时,对于每个文档,都可以分别计算一组搜索词("Hadoop"、"MapReduce")的TF-IDF,将它们相加,就可以得到整个文档的TF-IDF。这个值最高的文档就是与搜索词最相关的文档。
3.2优缺点
TF-IDF算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不 多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。(一种解决方法是,对全文的第一段和 每一段的第一句话,给予较大的权重。)
4.使用Hadoop计算TF-IDF
运行参数,第一个为文本存储路径,第二个为临时路径,第三个为结果输出路径
/home/hadoop/input /home/hadoop/temp /home/hadoop/output
package com.example.test; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class TFIDF {
// part1------------------------------------------------------------------------
public static class Mapper_Part1 extends
Mapper<LongWritable, Text, Text, Text> {
String File_name = ""; // 保存文件名,根据文件名区分所属文件
int all = 0; // 单词总数统计
static Text one = new Text("1");
String word;
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
InputSplit inputSplit = context.getInputSplit();
String str = ((FileSplit) inputSplit).getPath().toString();
File_name = str.substring(str.lastIndexOf("/") + 1); // 获取文件名
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word = File_name;
word += " ";
word += itr.nextToken(); // 将文件名加单词作为key es: test1 hello 1
all++;
context.write(new Text(word), one);
}
} public void cleanup(Context context) throws IOException,
InterruptedException {
// Map的最后,我们将单词的总数写入。下面需要用总单词数来计算。
String str = "";
str += all;
context.write(new Text(File_name + " " + "!"), new Text(str));
// 主要这里值使用的 "!"是特别构造的。 因为!的ascii比所有的字母都小。
}
} public static class Combiner_Part1 extends Reducer<Text, Text, Text, Text> {
float all = 0;
public void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
int index = key.toString().indexOf(" ");
// 因为!的ascii最小,所以在map阶段的排序后,!会出现在第一个
if (key.toString().substring(index + 1, index + 2).equals("!")) {
for (Text val : values) {
// 获取总的单词数。
all = Integer.parseInt(val.toString());
}
// 这个key-value被抛弃
return;
}
float sum = 0; // 统计某个单词出现的次数
for (Text val : values) {
sum += Integer.parseInt(val.toString());
}
// 跳出循环后,某个单词数出现的次数就统计完了,所有 TF(词频) = sum / all
float tmp = sum / all;
String value = "";
value += tmp; // 记录词频 // 将key中单词和文件名进行互换。es: test1 hello -> hello test1
String p[] = key.toString().split(" ");
String key_to = "";
key_to += p[1];
key_to += " ";
key_to += p[0];
context.write(new Text(key_to), new Text(value));
}
} public static class Reduce_Part1 extends Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
for (Text val : values) {
context.write(key, val);
}
}
} public static class MyPartitoner extends Partitioner<Text, Text> {
// 实现自定义的Partitioner
public int getPartition(Text key, Text value, int numPartitions) {
// 我们将一个文件中计算的结果作为一个文件保存
// es: test1 test2
String ip1 = key.toString();
ip1 = ip1.substring(0, ip1.indexOf(" "));
Text p1 = new Text(ip1);
return Math.abs((p1.hashCode() * 127) % numPartitions);
}
} // part2-----------------------------------------------------
public static class Mapper_Part2 extends
Mapper<LongWritable, Text, Text, Text> {
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String val = value.toString().replaceAll(" ", " "); // 将vlaue中的TAB分割符换成空格
// es: Bank
// test1
// 0.11764706 ->
// Bank test1
// 0.11764706
int index = val.indexOf(" ");
String s1 = val.substring(0, index); // 获取单词 作为key es: hello
String s2 = val.substring(index + 1); // 其余部分 作为value es: test1
// 0.11764706
s2 += " ";
s2 += "1"; // 统计单词在所有文章中出现的次数, “1” 表示出现一次。 es: test1 0.11764706 1
context.write(new Text(s1), new Text(s2));
}
} public static class Reduce_Part2 extends Reducer<Text, Text, Text, Text> {
int file_count; public void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
// 同一个单词会被分成同一个group
file_count = context.getNumReduceTasks(); // 获取总文件数
float sum = 0;
List<String> vals = new ArrayList<String>();
for (Text str : values) {
int index = str.toString().lastIndexOf(" ");
sum += Integer.parseInt(str.toString().substring(index + 1)); // 统计此单词在所有文件中出现的次数
vals.add(str.toString().substring(0, index)); // 保存
}
double tmp = Math.log10( file_count*1.0 /(sum*1.0)); // 单词在所有文件中出现的次数除以总文件数 = IDF
for (int j = 0; j < vals.size(); j++) {
String val = vals.get(j);
String end = val.substring(val.lastIndexOf(" "));
float f_end = Float.parseFloat(end); // 读取TF
val += " ";
val += f_end * tmp; // tf-idf值
context.write(key, new Text(val));
}
}
} public static void main(String[] args) throws Exception {
// part1----------------------------------------------------
Configuration conf1 = new Configuration();
// 设置文件个数,在计算DF(文件频率)时会使用
FileSystem hdfs = FileSystem.get(conf1);
FileStatus p[] = hdfs.listStatus(new Path(args[0])); // 获取输入文件夹内文件的个数,然后来设置NumReduceTasks
Job job1 = Job.getInstance(conf1, "My_tdif_part1");
job1.setJarByClass(TFIDF.class);
job1.setMapperClass(Mapper_Part1.class);
job1.setCombinerClass(Combiner_Part1.class); // combiner在本地执行,效率要高点。
job1.setReducerClass(Reduce_Part1.class);
job1.setMapOutputKeyClass(Text.class);
job1.setMapOutputValueClass(Text.class);
job1.setOutputKeyClass(Text.class);
job1.setOutputValueClass(Text.class);
job1.setNumReduceTasks(p.length);
job1.setPartitionerClass(MyPartitoner.class); // 使用自定义MyPartitoner FileInputFormat.addInputPath(job1, new Path(args[0]));
FileOutputFormat.setOutputPath(job1, new Path(args[1])); job1.waitForCompletion(true);
// part2----------------------------------------
Configuration conf2 = new Configuration(); Job job2 = Job.getInstance(conf2, "My_tdif_part2");
job2.setJarByClass(TFIDF.class);
job2.setMapOutputKeyClass(Text.class);
job2.setMapOutputValueClass(Text.class);
job2.setOutputKeyClass(Text.class);
job2.setOutputValueClass(Text.class);
job2.setMapperClass(Mapper_Part2.class);
job2.setReducerClass(Reduce_Part2.class);
job2.setNumReduceTasks(p.length); FileInputFormat.setInputPaths(job2, new Path(args[1]));
FileOutputFormat.setOutputPath(job2, new Path(args[2])); job2.waitForCompletion(true); // hdfs.delete(new Path(args[1]), true);
}
}
初学Hadoop之计算TF-IDF值的更多相关文章
- 使用solr的函数查询,并获取tf*idf值
1. 使用函数df(field,keyword) 和idf(field,keyword). http://118.85.207.11:11100/solr/mobile/select?q={!func ...
- 深度学习原理与框架-Tensorflow基本操作-mnist数据集的逻辑回归 1.tf.matmul(点乘操作) 2.tf.equal(对应位置是否相等) 3.tf.cast(将布尔类型转换为数值类型) 4.tf.argmax(返回最大值的索引) 5.tf.nn.softmax(计算softmax概率值) 6.tf.train.GradientDescentOptimizer(损失值梯度下降器)
1. tf.matmul(X, w) # 进行点乘操作 参数说明:X,w都表示输入的数据, 2.tf.equal(x, y) # 比较两个数据对应位置的数是否相等,返回值为True,或者False 参 ...
- tf–idf算法解释及其python代码实现(下)
tf–idf算法python代码实现 这是我写的一个tf-idf的简单实现的代码,我们知道tfidf=tf*idf,所以可以分别计算tf和idf值在相乘,首先我们创建一个简单的语料库,作为例子,只有四 ...
- tf–idf算法解释及其python代码实现(上)
tf–idf算法解释 tf–idf, 是term frequency–inverse document frequency的缩写,它通常用来衡量一个词对在一个语料库中对它所在的文档有多重要,常用在信息 ...
- 文本分类学习(三) 特征权重(TF/IDF)和特征提取
上一篇中,主要说的就是词袋模型.回顾一下,在进行文本分类之前,我们需要把待分类文本先用词袋模型进行文本表示.首先是将训练集中的所有单词经过去停用词之后组合成一个词袋,或者叫做字典,实际上一个维度很大的 ...
- 信息检索中的TF/IDF概念与算法的解释
https://blog.csdn.net/class_brick/article/details/79135909 概念 TF-IDF(term frequency–inverse document ...
- [python] 使用scikit-learn工具计算文本TF-IDF值
在文本聚类.文本分类或者比较两个文档相似程度过程中,可能会涉及到TF-IDF值的计算.这里主要讲述基于Python的机器学习模块和开源工具:scikit-learn. 希望文章对你有所帮 ...
- tf idf公式及sklearn中TfidfVectorizer
在文本挖掘预处理之向量化与Hash Trick中我们讲到在文本挖掘的预处理中,向量化之后一般都伴随着TF-IDF的处理,那么什么是TF-IDF,为什么一般我们要加这一步预处理呢?这里就对TF-IDF的 ...
- Elasticsearch由浅入深(十)搜索引擎:相关度评分 TF&IDF算法、doc value正排索引、解密query、fetch phrase原理、Bouncing Results问题、基于scoll技术滚动搜索大量数据
相关度评分 TF&IDF算法 Elasticsearch的相关度评分(relevance score)算法采用的是term frequency/inverse document frequen ...
随机推荐
- 6w6:第六周程序填空题3
描述 下面的程序输出结果是: A::Fun A::Do A::Fun C::Do 请填空: #include <iostream> using namespace std; class A ...
- A - 活动安排问题(贪心)
A - 活动安排问题 有若干个活动,第i个开始时间和结束时间是[Si,fi),同一个教室安排的活动之间不能交叠,求要安排所有活动,最少需要几个教室? Input第一行一个正整数n (n <= ...
- (转)使用vs调试的时候,如何知道程序阻塞在哪里?
遇到一个问题,加了两个断点当运行到断点A后,我释放掉了,理想状态应该是在断点B停住,但并没有,程序感觉就像是阻塞了一样请问,这种状况如何知道程序当前是在哪里阻塞着? 回复: 可以让调试器停住,然后在调 ...
- kali linux之端口扫描
端口对应网络服务及应用端程序,服务端程序的漏洞通过端口攻入 发现开放的端口,有更具体的攻击面 nmap hping3 scapy都可以 nmap隐蔽扫描 扫描抓包 nmap僵尸扫描 先发现僵尸机,僵尸 ...
- Linux man语法结构说明
一.man手册的内容结构(说明书页的格式): 标题含义: Name命令的名称和用途(摘要) Synopsis命令语法(摘要) Description完整描述 Environment命令使用的环境变量 ...
- 使用django进行发送 邮件
我们来看一下 django发送 邮件的整个流程 第一步:例先去 网易163注册账号并激活发邮件功能 把授权码进行 开启 来到我们的项目setting中进行 一个配置: # 邮箱的配置信息 EMAIL_ ...
- Python3之Memcache使用
简介 Memcached是一个高性能的分布式内存对象缓存系统,用于动态WEB应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态,数据库网站的速度.Memcached ...
- flex布局浅谈
flex布局浅谈和实例 阿基米德曾说给我一个支点我可以撬动地球,而拥有flex基本可以撬动所有的布局. 1.flex布局基本介绍及效果展示 工欲善其事必先利其器,来来来,一起看下基础知识先(呵~,老掉 ...
- alter table添加表约束
翻阅了一下网上关于alter table添加表约束的资料,学习下,然后供自己以后使用. 仅仅供自己使用... 总结alter table ### add constraint ## 使用方法 添加表约 ...
- SprimgMVC学习笔记(十)—— 拦截器
一. 什么是拦截器? Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录 ...