– 余弦值接近1,夹角趋于0,表明两个向量越相似
计算词频:如果一个词语出现一次就计分为1,0次计分为0,2次计分为2.
• 进一步调整假设:如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能反映了这篇文章的特性,正是我们所需要的关键词
词频(TF):计算方式有两种,都有自己的意义所在没有标准作出选择,看场景选择合适的方式,用abTest来做测试。
• 每篇文章各取出若干个关键词(比如20个),合并成一个集合,计算每篇文章对于这个集合中的词的词频(为了避免文章长度的差异,可以使用相对词频);
-正排表:doc1:t1,t2,t3,... doc2:t1,t2,t3;通过关键词得到相似文章:doc1:doc,doc,doc... 近似值,解决问题就好=平衡计算代价和准确性
• 生成两篇文章各自的词频向量;• 计算两个向量的余弦相似度,值越大就表示越相似。
• 下一步,对于每个簇,都计算它的重要性分值。
• 例如:其中的簇一共有7个词,其中4个是关键词。因此,它的重要性分值等于 ( 4 x 4 ) / 7 =2.3• 简化:不再区分"簇",只考虑句子包含的关键词。下面就是一个例子(采用伪码表示),只考虑关键词首先出现的句子
选择关键词首先出现的句子:多个关键词可能会选择同一个句子,此时setSummarySentences.add(firstMatchingSentence)里面需要做去重处理
– 这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。(一种解决方法是,对全文的第一段和每一段的第一句话,给予较大的权重。)
通过10000篇已知的文章和分词工具怎样得到一个相对比较好用的停用词名单?
--TF-IDF值越小的-->set
通过以上停用词名单去对另外5000篇文章去做过滤,则上一篇又需要怎样得到停用词名单?
--通过IDF去得到停用词再来处理这5000篇文章
数据准备
508篇文章
随机一篇文章的示例:每一句的词语都通过空格分开
将所有数据整理到一个文件,每一行均代表某一篇文章的某些信息
doc1:t1,t2,
doc2:t1,t2,
doc3:t1,t2,
convert.py
#!/usr/bin/python
import os
import sys
import gzip
#得到文件的目录,然后便利
test_dir = sys.argv[1]
def get_file_handler(f):
file_in = open(f, 'r')
return file_in
index = 0
for fd in os.listdir(test_dir): #便利目录,得到每一篇文章
txt_list = []
#得到一篇文章放进数组,因为每一篇文章数据较小所以可以直接放进内存
file_fd = get_file_handler(test_dir + '/' + fd)
for line in file_fd:
txt_list.append(line.strip())
#索引代表的是某一篇文章 文章索引+内容通过 \t分割
print '\t'.join([str(index), ' '.join(txt_list)])
index += 1
执行脚本:python convert.py ../input_tf_idf_dir/ > test_file.data 然后查看输出的文件内容
对输出数据做IDF:
#!/usr/bin/python
import sys
for line in sys.stdin:
ss = line.strip().split('\t', 1)
doc_index = ss[0].strip()
doc_context = ss[1].strip() #分割得到文章内容
word_list = doc_context.split(' ')
word_set = set()
for word in word_list:
word_set.add(word) #通过word_set做去重,因为我们是做IDF,所以需要去重,为什么?
for word in word_set:
print '\t'.join([word, "1"])
语料库文档总数:508
所以通过reduce可以到最终的IDF
#!/usr/bin/python
import sys
import math
current_word = None
count_pool = []
sum = 0
docs_cnt = 508 #这个通过公司的具体量级来定,这里是508
for line in sys.stdin:
ss = line.strip().split(' ') #这里的标准输入得用空格分割
if len(ss) != 2:
continue
word, val = ss
if current_word == None:
current_word = word
if current_word != word:
for count in count_pool:
sum += count
idf_score = math.log(float(docs_cnt) / (float(sum) + 1)) #得到IDF分数
print "%s\t%s" % (current_word, idf_score) #输出每一个单词的IDF
current_word = word
count_pool = []
sum = 0
count_pool.append(int(val))
for count in count_pool:
sum += count
idf_score = math.log(float(docs_cnt) / (float(sum) + 1))
print "%s\t%s" % (current_word, idf_score)
//cat test.data | python map.py | sort -k1 | python red.py >1.data #排序会引入乱码,需要指定分隔符
cat test.data | python map.py > 1.data #没有排序不会乱码
cat 1.data | awk -F'\t' '{print $1,$2}' | sort -k1 > 2.data
//cat 2.data | python red.py | grep --color '32' #调试时用,逐条查看包含32的乱码
cat 2.data | python red.py > 3.data
运行的脚本文件run.sh
HADOOP_CMD="/usr/local/src/hadoop-2.6.1/bin/hadoop"
STREAM_JAR_PATH="/usr/local/src/hadoop-2.6.1/share/hadoop/tools/lib/hadoop-streaming-2.6.1.jar"
INPUT_FILE_PATH_1="/tfidf_input.data"
OUTPUT_PATH="/tfidf_output"
$HADOOP_CMD fs -rmr -skipTrash $OUTPUT_PATH
# Step 1.
$HADOOP_CMD jar $STREAM_JAR_PATH \
-input $INPUT_FILE_PATH_1 \
-output $OUTPUT_PATH \
-mapper "python map.py" \
-reducer "python red.py" \
-file ./map.py \
-file ./red.py
在输出文件1.data中,我们可以去找分数最低的几个词语,是否在其他文章中经常出现,所以相关性较低
--10条有9条同样的类型,10张图片有9张是一样的,用户选择性较差,只能点击同样的类型--又进入同样的推荐-->死循环 --去重、过滤、随机处理
如果xm =yn(最后一个字符相同),则:xm 与yn 的最长公共子序列Z k 的最后一个字符必定为xm (= yn)
•