精华内容
下载资源
问答
  • word2vec获取词向量,查找相似

    千次阅读 2019-07-14 20:58:45
    word2vec获取词向量,查找相似词 首先安装gensim, 训练或者下载别人训练好的word2vec模型 # coding=utf-8 from gensim.models import Word2Vec from gensim.models import KeyedVectors #model = Word2Vec.load('...

    word2vec获取词向量,查找相似词

    首先安装gensim, 训练或者下载别人训练好的word2vec模型

    # coding=utf-8
    from gensim.models import Word2Vec
    from gensim.models import KeyedVectors
     
    #model = Word2Vec.load('./model/wiki.zh.text.model')   #用模型
    model = KeyedVectors.load_word2vec_format('./model/wiki.zh.text.vector')    # 用转换成txt的词向量文件
    testwords = ['孩子', '数学', '学术', '白痴', '篮球']
    for i in range(5):
        res = model.most_similar(testwords[i])
        print(testwords[i])
        print(res)
    

    结果如下图
    在这里插入图片描述

    展开全文
  • 查找相似的英文句子

    千次阅读 2018-03-01 19:01:34
    问题描述:已有文件sentence.dat是由很多行英文句子构成,请你对这个文件进行处理,构造相应的数据结构,开发出一个快速查找相似句子的系统(相似度计算方法见附注),该系统能实现的功能为:1 在控制台(console...

    问题描述:

    已有文件sentence.dat是由很多行英文句子构成,请你对这个文件进行处理,构造相应的数据结构,开发出一个快速查找最相似句子的系统(相似度计算方法见附注),该系统能实现的功能为:


    1 在控制台(console)中可以随时输入一个英文句子,单词长度小于等于8,运算后立刻在console中打印出在sentence.dat中与输入的英文句子最相似的前十个英文句子,和对应的相似度。

    2 每执行依次相似句子查询后,在控制台打印出本次执行的总时长,并要求从每次从console获得输入到执行完毕,总时长小于100毫秒

    附注:两个英文句子AB的相似性计算公式为:


    算法1:主要思想是利用循环迭代思想,对文件中每个句子采用set求其与输入句子的交集,并集个数,进而求得两个句子的相似度。并以键值对的形式,以相似度为key,以句子为value保存入字典。循环结束后,对字典按照key倒序排序,输出前10个键值对。

    运行结果如下图,运行时间在350ms左右。。


    from __future__ import division
    import time
    
    file = ‘/***/f.dat’
    
    def find1(file, content):
        flist = []
        with open(file, 'r') as f:
                for l in f:
            	    flist.append(l.replace('\n', ''))
    
        time1 = time.time()
        dictres = dict()
        n = 0
    
        set1 = set(content.replace('\n', '').split(' '))
        if len(set1) > 8:
            print '请输入单词个数小于等于8的句子'
            exit()
    
        for l in flist:
            set2 = set(l.split(' '))
            n1 = len(set1 & set2)
            n2 = len(set1 | set2)
            sim = round(n1 / n2, 4)
            dictres[sim] = l
    
        for key in sorted(dictres.keys(), reverse=True):
            print '%s : %s' % (key, dictres[key])
            n += 1
            if n >= 10:
                break
    
        time2 = time.time()
        print time2 - time1
    
    
    if __name__ == '__main__':
        content = raw_input()
        find1(file, content)

    算法2:使用gensim基于lsa算法进行相似度计算,运行时间最好的在109ms


    #! /usr/bin/env python2.7
    # coding=utf-8
    
    from __future__ import division
    
    import pickle
    
    from gensim import corpora, models, similarities
    import time
    
    datapath = "/***/data/f.dat"
    
    
    def loaddata(path):
        corp = list()
        with open(path, 'r') as fh:
            for l in fh:
                corp.append(l.split())
        return corp
    
    
    def simi(corp):
        dictionary = corpora.Dictionary(corp)
        dictionary.save('dictionary.dict')
        corpus = [dictionary.doc2bow(text) for text in corp]
        tfidf = models.TfidfModel(corpus)
        corpus_tfidf = tfidf[corpus]
        lsi = models.LsiModel(corpus_tfidf, id2word=dictionary)
        lsi.save('model.lsi')
        index = similarities.MatrixSimilarity(lsi[corpus])
        index.save('sim.index')
    
    
    if __name__ == '__main__':
    
        corp = loaddata(datapath)
        # simi(corp)
        dictionary = corpora.Dictionary.load('dictionary.dict')
        lsi = models.LsiModel.load('model.lsi')
        index = similarities.MatrixSimilarity.load('sim.index')
    
        query = raw_input()
        if len(query.split()) > 8:
            print '请输入单词长度小于8的句子'
            exit()
        time1 = time.time()
        vec_bow = dictionary.doc2bow(query.split())
        vec_lsi = lsi[vec_bow]
        sims = index[vec_lsi]
        sims = sorted(enumerate(sims), key=lambda item: -item[1])
        time2 = time.time()
        print time2 - time1
        print '与它话题相似度前十的有:'
        for i in range(10):
            print ' '.join(corp[sims[i][0]])
            print sims[i][1]


    算法改进3:

    在算法2的基础上,改进了排序算法。使排序时间从nlogn,缩短到10logn,运行时间缩短至50-60ms。算法如下:

    #! /usr/bin/env python2.7
    # coding=utf-8
    
    from __future__ import division
    
    from gensim import corpora, models, similarities
    import time
    datapath = "/***/data/f.dat"
    
    
    class Myheap:
        lst = []
    
        def __init__(self, lst):
            self.lst = lst
    
        def get_top_ten(self):
            if len(self.lst) <= 10:
                self.lst.sort(key=lambda doc: doc[1], reverse=True)
                return
            else:
                for start in xrange(9, -1, -1):
                    self.sift_down(start, 9)
                for index in xrange(10, len(self.lst) - 1, 1):
                    if self.lst[index][1] > self.lst[0][1]:
                        self.lst[0] = self.lst[index]
                        self.sift_down(0, 9)
            return sorted(self.lst[:10], key=lambda x: x[1], reverse=True)
    
        def sift_down(self, start, end):
            root = start
            while True:
                child = 2 * root + 1
                if child > end:
                    break
                if child + 1 <= end and self.lst[child][1] > self.lst[child + 1][1]:
                    child += 1
                if self.lst[root][1] > self.lst[child][1]:
                    self.lst[root], self.lst[child] = self.lst[child], self.lst[root]
                    root = child
                else:
                    break
    
    
    def loaddata(path):
        corp = []
        with open(path, 'r') as fh:
            for l in fh:
                corp.append(l.split())
        return corp
    
    
    def simi(corp):
        dictionary = corpora.Dictionary(corp)
        dictionary.save('dictionary.dict')
        corpus = [dictionary.doc2bow(text) for text in corp]
        tfidf = models.TfidfModel(corpus)
        corpus_tfidf = tfidf[corpus]
        lsi = models.LsiModel(corpus_tfidf, id2word=dictionary)
        lsi.save('model.lsi')
        index = similarities.MatrixSimilarity(lsi[corpus])
        index.save('sim.index')
    
    
    if __name__ == '__main__':
    
        corp = loaddata(datapath)
        # simi(corp)
        dictionary = corpora.Dictionary.load('dictionary.dict')
        lsi = models.LsiModel.load('model.lsi')
        index = similarities.MatrixSimilarity.load('sim.index')
        print '模型加载完毕'
        while True:
            query = raw_input('请输入').split()
            # if len(query) > 8:
            #     print '请输入单词长度小于8的句子'
            #     exit()
            time1 = time.time()
            query_bow = dictionary.doc2bow(query)
            query_lsi = lsi[query_bow]
            sims = index[query_lsi]
            # sims = sorted(enumerate(sims), key=lambda item: -item[1])
            simList = zip(xrange(len(sims)), sims)
            # heap sort
            heap = Myheap(simList)
            result = heap.get_top_ten()
            time2 = time.time()
            print 'Cost %f seconds' % (time2 - time1)
            print '与它话题相似度前十的句子排行及其相似度如下:'
            for line, sim in result:
                print ' '.join(corp[line])
                print sim

    算法4:同时王子豪的例子,在此先膜拜大神。。。

    使用的是稀疏矩阵保存倒排索引,即把词-文档 矩阵保存成稀疏矩阵的方式。后面计算相似度也是使用相应的矩阵运算求解。速度保持在50-70ms

    #! /usr/bin/env python2.7
    # coding=utf-8
    
    from __future__ import division
    
    import time
    import numpy as np
    from sklearn.feature_extraction.text import CountVectorizer
    
    datapath = "/***/data/f.dat"
    
    
    TOP_K = 10
    
    
    class Myheap:
        lst = []
    
        def __init__(self, lst):
            self.lst = lst
    
        def get_top_ten(self):
            if len(self.lst) <= 10:
                self.lst.sort(key=lambda doc: doc[1], reverse=True)
                return
            else:
                for start in xrange(9, -1, -1):
                    self.sift_down(start, 9)
                for index in xrange(10, len(self.lst) - 1, 1):
                    if self.lst[index][1] > self.lst[0][1]:
                        self.lst[0] = self.lst[index]
                        self.sift_down(0, 9)
            return sorted(self.lst[:10], key=lambda x: x[1], reverse=True)
    
        def sift_down(self, start, end):
            root = start
            while True:
                child = 2 * root + 1
                if child > end:
                    break
                if child + 1 <= end and self.lst[child][1] > self.lst[child + 1][1]:
                    child += 1
                if self.lst[root][1] > self.lst[child][1]:
                    self.lst[root], self.lst[child] = self.lst[child], self.lst[root]
                    root = child
                else:
                    break
    
    
    class Finder(object):
        def __init__(self):
            self.loadData()
    
        def loadData(self):
            # load data and vectorize
            self.sentences = []
            with open(datapath, 'r') as f:
                for line in f.readlines():
                    self.sentences.append(line.strip())
            self.cv = CountVectorizer(binary=True)
            self.term_doc = self.cv.fit_transform(self.sentences).transpose().tocsr()  # term-doc(51472, 100000)
            self.doc_len = self.term_doc.sum(axis=0)  # doc_len (1, 100000)
    
        def find(self, query):
            q_vector = self.cv.transform([query])
    
            # add up docs which contain terms in query
            # matches (100000, )
            matches = np.zeros(self.term_doc.shape[1])
            # 去听用词了?'a之类的' 7/8 = 0.875
            for term in q_vector.nonzero()[1]:
                matches += self.term_doc[term]
    
            if not matches.max():
                print "Can't find similar sentences, please try another.."
                return
    
            simVector = matches / (self.doc_len + len(query.split()) - matches)  # 矩阵之间的运算,simVector (1, 100000)
            # tansform to list [(line_num, similarity), ]
            sl = simVector[0, :].tolist()[0]
            simList = zip(xrange(len(sl)), sl)
    
            # heap sort
            heap = Myheap(simList)
            self.result = heap.get_top_ten()
    
            self.show()
    
        def show(self):
            just = 80
            print 'Find top10 sentences:'.ljust(just), 'Similarity'
            print '---------------------'.ljust(just), '----------'
            for line, sim in self.result:
                print self.sentences[line].ljust(just), sim
            print '---------------------'.ljust(just), '----------'
    
    
    if __name__ == '__main__':
        finder = Finder()
        while 1:
            query = raw_input('please input your sentence:')
            start = time.time()
            finder.find(query)
            print 'Cost %.04f seconds.' % (time.time() - start)
    


    展开全文
  • 相似文档查找算法之 simHash

    千次阅读 2017-04-27 17:02:31
    转自:介绍一个基于simhash作海量文章排重的库:simhashpy 摘要: 海量文章排重的具体...通过simhash能将一篇文章映射成64bit,再比较两篇文章的64bit的海明距离,就能知道文章的相似程序。若两篇文章的海明距离

    转自:介绍一个基于simhash作海量文章排重的库:simhashpy


    摘要: 海量文章排重的具体实践方法,主要是介绍在工程当中如何使用。

    基于simhash的海量文章排重的实践

    简单介绍

    simhash是一种能计算文档相似度的hash算法。通过simhash能将一篇文章映射成64bit,再比较两篇文章的64bit的海明距离,就能知道文章的相似程序。若两篇文章的海明距离<=3,可认为这两篇文章很相近,可认为它们是重复的文章。

    这篇博客有详细的介绍

    simhash-py

    要更准确的对文章进行排重,需要找到好的simhash算法。目前我知道的有python-hashes,simhash-py。两个库通过简单的修改,再加上中文分词库,可以比较好的对中文文章计算hash。simhash-py可使用我fork的版本以支持中文文章的simhash (通过里面的hash_token或hash_tokenpy两个函数实现对切词之后的中文文章进行simhash计算)。

    simhash算法

    simhash算法最简单实现的库应该是python-hashes库了。使用过程当中发现,对于排重的使用目的来说,这个库的simhash算法有缺点是:只考虑到文章存在哪些词,没有考虑到词的顺序。不过相应的优点是,可以实现海量文章相似度计算。文章相似度计算忽略词的顺序之后效果更好。

    simhash-py内部实现了simhash算法。它里面的simhash使用了cyclic hash算法,这个算法考虑到N(可以在3~5)个词之间的顺序。考虑到词的顺序的hash算法在排重过程当中会更准确,不过这个我也没有特别好的测试:)

    simhash加快搜索

    若看过本文推荐的simhash的原理讲解那篇文章,发现可以通过“shard”方式加快simhash值的搜索,从而能快速的知道是否存在重复的文章。而simhash-py库通过C++的Judy库实现了这一点。

    simhash集群处理

    既然可以通过“shard”方式,那么很容易把这个思路拓展到集群上。所以相应的,simhashpy的作者实现了simhash-cluster。

    过程当中有疑问可加我开源项目交流QQ群:27498_3126 欢迎对数据处理有兴趣的同学多多交流。


    转自:相似文档查找算法之 simHash 简介及其 java 实现

    传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上相当于伪随机数产生算法。产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别极大。从这个意义 上来 说,要设计一个 hash 算法,对相似的内容产生的签名也相近,是更为艰难的任务,因为它的签名值除了提供原始内容是否相等的信息外,还能额外提供不相等的 原始内容的差异程度的信息。
    而 Google 的 simhash 算法产生的签名,可以满足上述要求。出人意料,这个算法并不深奥,其思想是非常清澈美妙的。

    1、Simhash 算法简介

    simhash算法的输入是一个向量,输出是一个 f 位的签名值。为了陈述方便,假设输入的是一个文档的特征集合,每个特征有一定的权重。比如特征可以是文档中的词,其权重可以是这个词出现的次数。 simhash 算法如下: 
    1,将一个 f 维的向量 V 初始化为 0 ; f 位的二进制数 S 初始化为 0 ; 
    2,对每一个特征:用传统的 hash 算法对该特征产生一个 f 位的签名 b 。对 i=1 到 f : 
    如果b 的第 i 位为 1 ,则 V 的第 i 个元素加上该特征的权重; 
    否则,V 的第 i 个元素减去该特征的权重。  
    3,如果 V 的第 i 个元素大于 0 ,则 S 的第 i 位为 1 ,否则为 0 ; 
    4,输出 S 作为签名。

    2、算法几何意义和原理

    这个算法的几何意义非常明了。它首先将每一个特征映射为f维空间的一个向量,这个映射规则具体是怎样并不重要,只要对很多不同的特征来说,它们对所对应的向量是均匀随机分布的,并且对相同的特征来说对应的向量是唯一的就行。比如一个特征的4位hash签名的二进制表示为1010,那么这个特征对应的 4维向量就是(1, -1, 1, -1)T,即hash签名的某一位为1,映射到的向量的对应位就为1,否则为-1。然后,将一个文档中所包含的各个特征对应的向量加权求和,加权的系数等于该特征的权重。得到的和向量即表征了这个文档,我们可以用向量之间的夹角来衡量对应文档之间的相似度。最后,为了得到一个f位的签名,需要进一步将其压缩,如果和向量的某一维大于0,则最终签名的对应位为1,否则为0。这样的压缩相当于只留下了和向量所在的象限这个信息,而64位的签名可以表示多达264个象限,因此只保存所在象限的信息也足够表征一个文档了。 


    明确了算法了几何意义,使这个算法直观上看来是合理的。但是,为何最终得到的签名相近的程度,可以衡量原始文档的相似程度呢?这需要一个清晰的思路和证明。在simhash的发明人Charikar的论文中[2]并没有给出具体的simhash算法和证明,以下列出我自己得出的证明思路。

    Simhash是由随机超平面hash算法演变而来的,随机超平面hash算法非常简单,对于一个n维向量v,要得到一个f位的签名(f<<n),算法如下: 
    1,随机产生f个n维的向量r1,…rf; 
    2,对每一个向量ri,如果v与ri的点积大于0,则最终签名的第i位为1,否则为0. 


    这个算法相当于随机产生了f个n维超平面,每个超平面将向量v所在的空间一分为二,v在这个超平面上方则得到一个1,否则得到一个0,然后将得到的 f个0或1组合起来成为一个f维的签名。如果两个向量u, v的夹角为θ,则一个随机超平面将它们分开的概率为θ/π,因此u, v的签名的对应位不同的概率等于θ/π。所以,我们可以用两个向量的签名的不同的对应位的数量,即汉明距离,来衡量这两个向量的差异程度。

    Simhash算法与随机超平面hash是怎么联系起来的呢?在simhash算法中,并没有直接产生用于分割空间的随机向量,而是间接产生的:第 k个特征的hash签名的第i位拿出来,如果为0,则改为-1,如果为1则不变,作为第i个随机向量的第k维。由于hash签名是f位的,因此这样能产生 f个随机向量,对应f个随机超平面。下面举个例子: 
    假设用5个特征w1,…,w5来表示所有文档,现要得到任意文档的一个3维签名。假设这5个特征对应的3维向量分别为: 
    h(w1) = (1, -1, 1)T 
    h(w2) = (-1, 1, 1)T 
    h(w3) = (1, -1, -1)T 
    h(w4) = (-1, -1, 1)T 
    h(w5) = (1, 1, -1)T 


    按simhash算法,要得到一个文档向量d=(w1=1, w2=2, w3=0, w4=3, w5=0) T的签名,

    先要计算向量m = 1*h(w1) + 2*h(w2) + 0*h(w3) + 3*h(w4) + 0*h(w5) = (-4, -2, 6) T, 
    然后根据simhash算法的步骤3,得到最终的签名s=001。 


    上面的计算步骤其实相当于,先得到3个5维的向量,第1个向量由h(w1),…,h(w5)的第1维组成:

    r1=(1,-1,1,-1,1) T; 
    第2个5维向量由h(w1),…,h(w5)的第2维组成: 
    r2=(-1,1,-1,-1,1) T; 
    同理,第3个5维向量为: 
    r3=(1,1,-1,1,-1) T. 
    按随机超平面算法的步骤2,分别求向量d与r1,r2,r3的点积: 
    d T r1=-4 < 0,所以s1=0; 
    d T r2=-2 < 0,所以s2=0; 
    d T r3=6 > 0,所以s3=1. 
    故最终的签名s=001,与simhash算法产生的结果是一致的。 


    从上面的计算过程可以看出,simhash算法其实与随机超平面hash算法是相同的,simhash算法得到的两个签名的汉明距离,可以用来衡量原始向量的夹角。这其实是一种降维技术,将高维的向量用较低维度的签名来表征。衡量两个内容相似度,需要计算汉明距离,这对给定签名查找相似内容的应用来说带来了一些计算上的困难;我想,是否存在更为理想的simhash算法,原始内容的差异度,可以直接由签名值的代数差来表示呢?

    3、比较相似度

    海明距离: 两个码字的对应比特取值不同的比特数称为这两个码字的海明距离。一个有效编码集中, 任意两个码字的海明距离的最小值称为该编码集的海明距离。举例如下: 10101 和 00110 从第一位开始依次有第一位、第四、第五位不同,则海明距离为 3. 


    异或: 只有在两个比较的位不同时其结果是1 ,否则结果为 0 

    对每篇文档根据SimHash 算出签名后,再计算两个签名的海明距离(两个二进制异或后 1 的个数)即可。根据经验值,对 64 位的 SimHash ,海明距离在 3 以内的可以认为相似度比较高。 
    假设对64 位的 SimHash ,我们要找海明距离在 3 以内的所有签名。我们可以把 64 位的二进制签名均分成 4块,每块 16 位。根据鸽巢原理(也成抽屉原理,见组合数学),如果两个签名的海明距离在 3 以内,它们必有一块完全相同。 
    我们把上面分成的4 块中的每一个块分别作为前 16 位来进行查找。 建立倒排索引。



    如果库中有2^34 个(大概 10 亿)签名,那么匹配上每个块的结果最多有 2^(34-16)=262144 个候选结果 (假设数据是均匀分布, 16 位的数据,产生的像限为 2^16 个,则平均每个像限分布的文档数则 2^34/2^16 = 2^(34-16)) ,四个块返回的总结果数为 4* 262144 (大概 100 万)。原本需要比较 10 亿次,经过索引,大概就只需要处理 100 万次了。由此可见,确实大大减少了计算量。 

    4、示例代码:

    /**
     * Function: simHash 判断文本相似度,该示例程支持中文<br/>
     * date: 2013-8-6 上午1:11:48 <br/>
     * @author june
     * @version 0.1
     */
    import java.io.IOException;
    import java.io.StringReader;
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    import org.wltea.analyzer.IKSegmentation;
    import org.wltea.analyzer.Lexeme;
    
    public class SimHash {
    
    	private String tokens;
    
    	private BigInteger intSimHash;
    
    	private String strSimHash;
    
    	private int hashbits = 64;
    
    	public SimHash(String tokens) throws IOException {
    		this.tokens = tokens;
    		this.intSimHash = this.simHash();
    	}
    
    	public SimHash(String tokens, int hashbits) throws IOException {
    		this.tokens = tokens;
    		this.hashbits = hashbits;
    		this.intSimHash = this.simHash();
    	}
    
    	HashMap<String, Integer> wordMap = new HashMap<String, Integer>();
    
    	public BigInteger simHash() throws IOException {
    		// 定义特征向量/数组
    		int[] v = new int[this.hashbits];
    		// 英文分词
    		// StringTokenizer stringTokens = new StringTokenizer(this.tokens);
    		// while (stringTokens.hasMoreTokens()) {
    		// String temp = stringTokens.nextToken();
    		// }
    		// 1、中文分词,分词器采用 IKAnalyzer3.2.8 ,仅供演示使用,新版 API 已变化。
    		StringReader reader = new StringReader(this.tokens);
    		// 当为true时,分词器进行最大词长切分
    		IKSegmentation ik = new IKSegmentation(reader, true);
    		Lexeme lexeme = null;
    		String word = null;
    		String temp = null;
    		while ((lexeme = ik.next()) != null) {
    			word = lexeme.getLexemeText();
    			// 注意停用词会被干掉
    			// System.out.println(word);
    			// 2、将每一个分词hash为一组固定长度的数列.比如 64bit 的一个整数.
    			BigInteger t = this.hash(word);
    			for (int i = 0; i < this.hashbits; i++) {
    				BigInteger bitmask = new BigInteger("1").shiftLeft(i);
    				// 3、建立一个长度为64的整数数组(假设要生成64位的数字指纹,也可以是其它数字),
    				// 对每一个分词hash后的数列进行判断,如果是1000...1,那么数组的第一位和末尾一位加1,
    				// 中间的62位减一,也就是说,逢1加1,逢0减1.一直到把所有的分词hash数列全部判断完毕.
    				if (t.and(bitmask).signum() != 0) {
    					// 这里是计算整个文档的所有特征的向量和
    					// 这里实际使用中需要 +- 权重,比如词频,而不是简单的 +1/-1,
    					v[i] += 1;
    				} else {
    					v[i] -= 1;
    				}
    			}
    		}
    
    		BigInteger fingerprint = new BigInteger("0");
    		StringBuffer simHashBuffer = new StringBuffer();
    		for (int i = 0; i < this.hashbits; i++) {
    			// 4、最后对数组进行判断,大于0的记为1,小于等于0的记为0,得到一个 64bit 的数字指纹/签名.
    			if (v[i] >= 0) {
    				fingerprint = fingerprint.add(new BigInteger("1").shiftLeft(i));
    				simHashBuffer.append("1");
    			} else {
    				simHashBuffer.append("0");
    			}
    		}
    		this.strSimHash = simHashBuffer.toString();
    		System.out.println(this.strSimHash + " length " + this.strSimHash.length());
    		return fingerprint;
    	}
    
    	private BigInteger hash(String source) {
    		if (source == null || source.length() == 0) {
    			return new BigInteger("0");
    		} else {
    			char[] sourceArray = source.toCharArray();
    			BigInteger x = BigInteger.valueOf(((long) sourceArray[0]) << 7);
    			BigInteger m = new BigInteger("1000003");
    			BigInteger mask = new BigInteger("2").pow(this.hashbits).subtract(new BigInteger("1"));
    			for (char item : sourceArray) {
    				BigInteger temp = BigInteger.valueOf((long) item);
    				x = x.multiply(m).xor(temp).and(mask);
    			}
    			x = x.xor(new BigInteger(String.valueOf(source.length())));
    			if (x.equals(new BigInteger("-1"))) {
    				x = new BigInteger("-2");
    			}
    			return x;
    		}
    	}
    
    	public int hammingDistance(SimHash other) {
    
    		BigInteger x = this.intSimHash.xor(other.intSimHash);
    		int tot = 0;
    
    		// 统计x中二进制位数为1的个数
    		// 我们想想,一个二进制数减去1,那么,从最后那个1(包括那个1)后面的数字全都反了,
    		// 对吧,然后,n&(n-1)就相当于把后面的数字清0,
    		// 我们看n能做多少次这样的操作就OK了。
    
    		while (x.signum() != 0) {
    			tot += 1;
    			x = x.and(x.subtract(new BigInteger("1")));
    		}
    		return tot;
    	}
    
    	public int getDistance(String str1, String str2) {
    		int distance;
    		if (str1.length() != str2.length()) {
    			distance = -1;
    		} else {
    			distance = 0;
    			for (int i = 0; i < str1.length(); i++) {
    				if (str1.charAt(i) != str2.charAt(i)) {
    					distance++;
    				}
    			}
    		}
    		return distance;
    	}
    
    	public List subByDistance(SimHash simHash, int distance) {
    		// 分成几组来检查
    		int numEach = this.hashbits / (distance + 1);
    		List characters = new ArrayList();
    
    		StringBuffer buffer = new StringBuffer();
    
    		int k = 0;
    		for (int i = 0; i < this.intSimHash.bitLength(); i++) {
    			// 当且仅当设置了指定的位时,返回 true
    			boolean sr = simHash.intSimHash.testBit(i);
    
    			if (sr) {
    				buffer.append("1");
    			} else {
    				buffer.append("0");
    			}
    
    			if ((i + 1) % numEach == 0) {
    				// 将二进制转为BigInteger
    				BigInteger eachValue = new BigInteger(buffer.toString(), 2);
    				System.out.println("----" + eachValue);
    				buffer.delete(0, buffer.length());
    				characters.add(eachValue);
    			}
    		}
    
    		return characters;
    	}
    
    	public static void main(String[] args) throws IOException {
    		String s = "传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值," 
    				+ "原理上相当于伪随机数产生算法。产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的;"
    				+ "如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节," 
    				+ "所产生的签名也很可能差别极大。从这个意义 上来 说,要设计一个 hash 算法,"
    				+ "对相似的内容产生的签名也相近,是更为艰难的任务,因为它的签名值除了提供原始内容是否相等的信息外," 
    				+ "还能额外提供不相等的 原始内容的差异程度的信息。";
    		SimHash hash1 = new SimHash(s, 64);
    		System.out.println(hash1.intSimHash + "  " + hash1.intSimHash.bitLength());
    		// 计算 海明距离 在 3 以内的各块签名的 hash 值
    		hash1.subByDistance(hash1, 3);
    
    		// 删除首句话,并加入两个干扰串
    		s = "原理上相当于伪随机数产生算法。产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的;"
    				+ "如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节," 
    				+ "所产生的签名也很可能差别极大。从这个意义 上来 说,要设计一个 hash 算法,"
    				+ "对相似的内容产生的签名也相近,是更为艰难的任务,因为它的签名值除了提供原始内容是否相等的信息外," 
    				+ "干扰1还能额外提供不相等的 原始内容的差异程度的信息。";
    		SimHash hash2 = new SimHash(s, 64);
    		System.out.println(hash2.intSimHash + "  " + hash2.intSimHash.bitCount());
    		hash1.subByDistance(hash2, 3);
    
    		// 首句前添加一句话,并加入四个干扰串
    		s = "imhash算法的输入是一个向量,输出是一个 f 位的签名值。为了陈述方便," 
    				+ "假设输入的是一个文档的特征集合,每个特征有一定的权重。"
    				+ "传统干扰4的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值," 
    				+ "原理上这次差异有多大呢3相当于伪随机数产生算法。产生的两个签名,如果相等,"
    				+ "说明原始内容在一定概 率 下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,"
    				+ "因为即使原始内容只相差一个字节,所产生的签名也很可能差别极大。从这个意义 上来 说,"
    				+ "要设计一个 hash 算法,对相似的内容产生的签名也相近,是更为艰难的任务,因为它的签名值除了提供原始"
    				+ "内容是否相等的信息外,干扰1还能额外提供不相等的 原始再来干扰2内容的差异程度的信息。";
    		SimHash hash3 = new SimHash(s, 64);
    		System.out.println(hash3.intSimHash + "  " + hash3.intSimHash.bitCount());
    		hash1.subByDistance(hash3, 3);
    
    		System.out.println("============================");
    
    		int dis = hash1.getDistance(hash1.strSimHash, hash2.strSimHash);
    		System.out.println(hash1.hammingDistance(hash2) + " " + dis);
    		// 根据鸽巢原理(也成抽屉原理,见组合数学),如果两个签名的海明距离在 3 以内,它们必有一块签名subByDistance()完全相同。
    		int dis2 = hash1.getDistance(hash1.strSimHash, hash3.strSimHash);
    		System.out.println(hash1.hammingDistance(hash3) + " " + dis2);
    	}
    }

    5、适用场景:

    simHash在短文本的可行性:

    测试相似文本的相似度与汉明距离
    测试文本:20个城市名作为词串:北京,上海,香港,深圳,广州,台北,南京,大连,苏州,青岛,无锡,佛山,重庆,宁波,杭州,成都,武汉,澳门,天津,沈阳

    相似度矩阵:

    simHash码:

    勘误:0.667, Hm:13 是对比的msg 1与2。
    可见:相似度在0.8左右的Hamming距离为7,只有相似度高到0.9412,Hamming距离才近到4,

    此时,反观Google对此算法的应用场景:网页近重复、镜像网站、内容复制、嵌入广告、计数改变、少量修改。
    以上原因对于长文本来说造成的相似度都会比较高,而对于短文本来说,如何处理海量数据的相似度文本更为合适的?

    测试短文本(长度在8个中文字符~45个中文字符之间)相似性的误判率如下图所示:



    REF:

    1、simHash 简介以及java实现

    http://blog.sina.com.cn/s/blog_4f27dbd501013ysm.html

    2、对simhash算法的一些思考

    http://2588084.blog.51cto.com/2578084/558873

    3、Simhash算法原理和网页查重应用

    http://blog.sina.com.cn/s/blog_72995dcc010145ti.html

    4、其它

    http://www.cnblogs.com/zhengyun_ustc/archive/2012/06/12/sim.html

    http://tech.uc.cn/?p=1086  利用Simhash快速查找相似文档

    http://jacoxu.com/?p=369  simHash是否适合短文本的相似文本匹配

    https://github.com/sing1ee/simhash-java

    http://blog.jobbole.com/46839/    海量数据相似度计算之simhash和海明距离

    求二进制数中1的个数

    http://segmentfault.com/q/1010000000269106

    海量数据相似度计算之simhash短文本查找(提升查找效率)

    http://blog.jobbole.com/47748/



    展开全文
  • 在一个文本词库里查找相似单词,就是输入一个单词,在词库里找与这个单词相似的单词,由相似度大到小,用最小编辑距离实现C++ #include #include <iostream> #include <string> #include <string.h> #include ...
  • word2vec找文本相似词小试牛刀

    千次阅读 2015-10-20 11:48:36
    word2vec作为google的一个开源工具,比较强大,效果也比较好,便试试。 一、工具 下载:http://word2vec.googlecode.com/svn/trunk/(翻墙) 也可以从CSDN下载:http://download.csdn.net/detail/hortond/8095703 ...

    preface: 找出语料中跟某个词类似的词。

    word2vec作为google的一个开源工具,比较强大,效果也比较好,便试试。


    一、工具

    下载:http://word2vec.googlecode.com/svn/trunk/(翻墙)

    也可以从CSDN下载:http://download.csdn.net/detail/hortond/8095703

    官方教程:https://code.google.com/p/word2vec/(翻墙)

    类似博客:

    利用中文数据跑word2vec:http://www.tuicool.com/articles/RB7fqaB

    利用word2vec对关键词进行聚类:http://blog.csdn.net/zhaoxinfan/article/details/11069485

    豆瓣word2vec的学习思路:http://www.douban.com/note/298095260/(有原理说明)

    另外python gensim包自带word2vec这个神器。

    Figure 1-1: gensim word2vec

    参考博客:

    http://rare-technologies.com/word2vec-tutorial/

    http://ju.outofmemory.cn/entry/80023

    http://www.52nlp.cn/中英文维基百科语料上的word2vec实验


    二、语料

    采用之前爬取的新浪娱乐的文本。


    三、分词

    分词,采用python jieba分词,数据存在data文件夹下,新浪娱乐每篇文章一个txt文件。共计85317个文件夹。

    #!/usr/bin/env python
    # coding=utf-8
    import jieba
    import os
    import codecs
    num = 0
    
    for i in os.walk("data"):
        for j in i[2]:
    #        print j
            try:
                fw = codecs.open("pickle_jiebatest.txt","a")
                f = codecs.open("data/"+j,encoding="utf-8",errors="strict")
                for k in f.readlines():
                    line = k.strip()
                    word_list = jieba.cut(line)
                    new_s  = " ".join(word_list)
                    fw.write(new_s+"\n")
                fw.close()
            except:
    #            print j,num
                pass
            
            num+=1
            if num%1000==0:
                print "===========================================处理个数:",num


    Figure 1-2: 分好词的语料


    四、word2vec训练

    一句命令即可,进行训练,具体的参数待学习,改输入文件输出文件即可,输出一个模型文件

    ./word2vec -train shifeng/pickle_jieba.txt -output shifeng/vectors_word.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1  

    Figure 1-3: 对文件进行训练

    找出相似的词:

    ./distance shifeng/vectors_word.bin

    Figure 1-4: 进行测试


    将结果输出到文件中,利用管道符更加方便快捷

    Figure 1-5: 多个文件输出


    五、其他

    由于word2vec计算的是余弦值,距离范围为0-1之间,值越大代表这两个词关联度越高,所以越排在上面的词与输入的词越紧密。至于聚类,只需要另一个命令即可:
    <span style="font-size:18px;">./word2vec -train resultbig.txt -output classes.txt -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -classes 500  </span>
    按类别排序
    <span style="font-size:18px;">sort classes.txt -k 2 -n > classes.sorted.txt </span>



    展开全文
  • 海量数据相似查找系列2 -- Annoy算法

    千次阅读 2017-09-28 20:21:38
    上面一章说了下高维稀疏数据如何通过learning to hash的方法来进行相似查找,这种主要想说下另外一种情况,稠密向量如何进行快速相似查找呢?还是以文本为例吧。之前提到过文本的paragraph2vector的向量表示,以及词...
  • System.out.println(p.imgChk(targetImage, compareImage + "ohter_word.jpg", 10)); System.out.println(p.imgChk(targetImage, compareImage + "similar_pic.jpg", 10)); System.out.println(p.imgChk...
  • 传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,...如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别极大。从这个意义 ...
  • 这一节重点针对高维稀疏数据情况,说如何通过哈希技术进行快速进行相似查找。 试想个案例,就拿推荐系统中item-user矩阵说事。如果你有item数量是百万级别,user是千万级别,这个矩阵是十分稀疏的。你如何计算每一个...
  • 首先,建立自己的语料库 def ylk(x): seg = jieba.cut(x, cut_all=False) with open('D://listTwo.txt', 'a',encoding='utf-8')as f: for word in seg: ...from gensim.models.word2vec import LineSentence, Wo
  • c#对word操作的查找替换功能

    千次阅读 2009-10-19 13:07:00
    如果为 True,则在从右向左的语言的文档中,查找内容应与区分双向控制字符的文本相匹配。由于选择或安装的语言支持不同(例如,英语(美国)),此参数可能不可用。 说明 如果 MatchWildcards 为 True,...
  • word内容关键字搜索

    千次阅读 2013-06-03 15:57:35
    我的电脑里大约有几千个Word文档,分类比较多,有点乱,再加上从根目录开始,有多层子目录,文档名字大多相似,很多时候记不住文档的名字了,只是记得内容的个别词汇,于是我进入那个文件夹,开始用系统自带的关键字...
  • Word中的特殊符号的区别, 替换表示方法.
  • 图解Word2vec

    千次阅读 多人点赞 2019-04-08 08:58:57
    这是另一个示例列表(通过垂直扫描列来查找具有相似颜色的列): 有几个要点需要指出: 1.所有这些不同的单词都有一条直的红色列。 它们在这个维度上是相似的(虽然我们不知道每个维度是什么) 2.你可以看到...
  • word技巧

    千次阅读 2018-03-01 21:40:22
    word 高效经典教程(整理版)目录一分钟驾驭word 高效经典教程(整理版)... 6A、基础知识... 61、度量单位... 62、WORD中文字字号与磅的对应关系... 63、字体文件格式... 7B、文本编辑... 71、快速移动文档... 72、...
  • 查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算,例如编译程序中符号表的查找。本文简单概括性的介绍了常见的七种查找算法,说是七种,其实二分查找、插值查找以及斐波那契查找...
  • zotero word 调整样式 上标

    千次阅读 2018-06-11 17:19:22
    说明:教程比较简单,只讲步骤,不讲原因,介意绕道。 假定:你已经装好zotero,word中也添加好zotero插件。 解决:引用上标问题。 方法一:(不提倡) 简单粗暴,直接右键字体,调成上标。...2. 查找相似样...
  • 机器学习算法实现解析——word2vec源码解析

    万次阅读 多人点赞 2017-03-16 16:32:44
    在阅读本文之前,建议首先阅读“简单易学的机器学习算法——word2vec的算法原理”,掌握如下的几个概念: 什么是统计语言模型 神经概率语言模型的网络结构 CBOW模型和Skip-gram模型的网络结构 Hierarchical Softmax...
  • Embedding和Word2vec的理解

    千次阅读 2020-10-28 00:05:46
    文章目录 前言 介绍 背景知识 CBOW和Skip-gram CBOW Skip-gram Skipgram with Negative Sampling (SGNS) Word2vec训练流程 最后 前言 说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,...
  • NLP系列(10)_词向量之图解Word2vec

    万次阅读 多人点赞 2019-04-08 09:58:35
    审校:龙心尘 作者:Jay Alammar 编译:张秋玥、毅航、高延 ...https://jalammar.github.io/illustrated-word2vec/ 嵌入(embedding)是机器学习中最迷人的想法之一。 如果你曾经使用Siri、Google...
  • Word2Vec解释

    万次阅读 多人点赞 2018-04-17 15:46:51
    Word2Vec解释 一、Word2Vec梗概 字面意思:即Word to Vector,由词到向量的方法。 专业解释:Word2Vec使用一层神经网络将one-hot(独热编码)形式的词向量映射到分布式形式的词向量。使用了Hierarchical ...
  • 词向量:对word2vec的理解

    千次阅读 2017-12-11 16:07:21
    这里的词向量就是上面在huffman树种的叶子节点初始化的向量,一般习惯把所有词向量构建成一张look-up table,把每一个词转化为对应table中的索引,在使用的时候直接查找,能够提高效率。 (6)投影层处理 投影层将...
  • word2vec可以通过词,查找对应的词向量,同样也可以通过词向量找到相似的词。 链接:...
  • Word2Vec详解

    千次阅读 2018-04-13 10:54:50
    Word2Vec详解 这几天集中学习了Word2Vec,实现并不复杂,但是真正对一些细节有些了解还查阅了一些资料,今天在这里统一自己整理总结一下。 简介 首先说为什么会有Word2Vec,之前对文字的编码通常使用的是one-...
  • word2vec算法

    千次阅读 2019-07-01 16:30:54
    word2vec1 算法的基本思想2 举例说明2.1 构造训练数据2.2 数字化表示单词对2.3 定义网络结构2.4 隐藏层2.4 输出层3 直觉的启示4 下篇预告 本文是一篇翻译的文章,原文链接是:...
  • 文章目录索引`Word Embeddings`评分的余弦相似度局限性通过抽象属性搜索 Elasticsearch做文本检索是基于文本之间的相似性的。在Elasticsearch 5.0中,Elasticsearch将默认算法由TF / IDF切换为Okapi BM25,该算法...
  • TensorFlow v2.0实现Word2Vec算法

    千次阅读 2019-10-27 14:18:32
    使用TensorFlow v2.0实现Word2Vec算法计算单词的向量表示,这个例子是使用一小部分维基百科文章来训练的。 更多信息请查看论文: Mikolov, Tomas et al. "Efficient Estimation of Word Representations in Vector ...
  • Word2vec代码实现

    千次阅读 多人点赞 2019-10-31 19:07:33
    Word2vec纯python代码实现 1. 什么是 Word2vec? 在聊 Word2vec 之前,先聊聊 NLP (自然语言处理)。NLP 里面,最细粒度的是 词语,词语组成句子,句子再组成段落、篇章、文档。所以处理 NLP 的问题,首先就要拿...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,782
精华内容 11,112
关键字:

word查找相似内容