自然语言处理之文本相似度

1、文本相似度:

1) 语义相似、但字面不相似

2) 字面相似、但是语义不相似

2、方案:

1) 语义相似:依靠用户行为,最基本的方法:(1)基于共点击的行为(协同过滤),(2)借助回归算法

2) 字面相似:(1) LCS最大公共子序列 (2) 利用中文分词

3 字面相似的问题解决:
       余弦相似度 cosine
                    举例:A(1,2,3),B(2,3,4)
                    cosine(A,B) = 分子 / 分母
                    分子:A*B = 1*2+2*3+3*4 = 20

                    |A| = sqrt(1*1+2*2+3*3) = 3.74
                    |B| = sqrt(2*2+3*3+4*4) = 5.38
                    分母:|A|*|B| = 20.12

4 tfidf:

1) TF:词频
            
                    关键词:在当前文章出现较多,但在其他文章中出现较少
            
2) IDF:反文档频率
                                    
score = TF * IDF

5、自动摘要:

1) 确定关键词集合(两种方法(a)top-10 (b)阈值截断 > 0.8 )
2)哪些句子包含关键词,把这些句子取出来
3)  对关键词排序,对句子做等级划分
4)把等级高的句子取出来,就是摘要

6.实践:

1.idf实践:

一共508篇文章

(1)数据预处理:把所有文章的内容,全部收集到一个文件中

]# python convert.py input_tfidf_dir/ > idf_input.data

(2)计算IDF:通过mr批量计算IDF

         计算方法:文档总数/包含该词的文档数

代码:

convert.py:

import os

import sys

file_path_dir = sys.argv[1]

def read_file_handler(f):
    fd = open(f, 'r')
    return fd

file_name = 0
for fd in os.listdir(file_path_dir):
    file_path = file_path_dir + '/' + fd

    content_list = []

    file_fd = read_file_handler(file_path)
    for line in file_fd:
        content_list.append(line.strip())

    print '\t'.join([str(file_name), ' '.join(content_list)])

    file_name += 1

map.py:

import sys

for line in sys.stdin:
    ss = line.strip().split('\t')
    if len(ss) != 2:
        continue
    file_name, file_content = ss
    word_list = file_content.strip().split(' ')

    word_set = set(word_list)

    for word in word_set:
        print '\t'.join([word, '1'])

red.py:

import sys
import math

current_word = None
sum = 0

docs_cnt = 508

for line in sys.stdin:
    ss = line.strip().split('\t')
    if len(ss) != 2:
        continue
    word, val = ss
    if current_word == None:
        current_word = word
    if current_word != word:
        idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
        print '\t'.join([current_word, str(idf)])
        current_word = word
        sum = 0

    sum += int(val)

idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
print '\t'.join([current_word, str(idf)])

编写run.sh脚本运行MapReduce:

7.LCS(最长公共子序列)解决方案:

动态规划解决:

LCSpython实践:

1.数据:

2.python代码:

map.py:

# -*- coding: utf-8 -*-
#!/usr/bin/python

import sys

def cal_lcs_sim(first_str, second_str):
    len_vv = [[0] * 50] * 50

    first_str = unicode(first_str, "utf-8", errors='ignore')
    second_str = unicode(second_str, "utf-8", errors='ignore')

    len_1 = len(first_str.strip())
    len_2 = len(second_str.strip())

    for i in range(1, len_1 + 1):
        for j in range(1, len_2 + 1):
            if first_str[i - 1] == second_str[j - 1]:
                len_vv[i][j] = 1 + len_vv[i - 1][j - 1]
            else:
                len_vv[i][j] = max(len_vv[i - 1][j], len_vv[i][j - 1])

    return float(float(len_vv[len_1][len_2] * 2) / float(len_1 + len_2))


for line in sys.stdin:
    ss = line.strip().split('\t')
    if len(ss) != 2:
        continue
    first_str = ss[0].strip()
    second_str = ss[1].strip()

    sim_score = cal_lcs_sim(first_str, second_str)
    print '\t'.join([first_str, second_str, str(sim_score)])

执行脚本run.sh

执行:

结果:

 

shell终端做快速计算:
            ]# echo $[60000*2/16]
            ]# echo $((60000*2/16))

展开阅读全文

没有更多推荐了,返回首页