python使用局部敏感性哈希算法,在海量数据中查询相似序列

2023-11-01


局部敏感性哈希是指:相似的哈希具有相似的原始序列

整体思路:

  1. 首先将数据装在不同的桶里(通过桶之间的Jaccard系数计算原始数据hash)
  2. 得到hash生成的规则
  3. 用这个规则来转换新的数据
  4. 将新数据生成的hash与原有的所有hash进行比较,选择最相似的

注:最后比较的过程不是两两匹配,每个不同的算法都有不同的简化的方式

局部敏感性hash详细请参考:https://www.cnblogs.com/fengfenggirl/p/lsh.html

一、原生python实现

文章、代码地址:https://blog.csdn.net/sgyuanshi/article/details/108132214

import numpy as np
from typing import List, Union


class EuclideanLSH(object):
    def __init__(self, tables_num: int, a: int, depth: int):
        """

        :param tables_num: hash_table的个数
        :param a: a越大,被纳入同个位置的向量就越多,即可以提高原来相似的向量映射到同个位置的概率,
                反之,则可以降低原来不相似的向量映射到同个位置的概率。
        :param depth: 向量的维度数
        """
        self.tables_num = tables_num
        self.a = a
        # 为了方便矩阵运算,调整了shape,每一列代表一个hash_table的随机向量
        self.R = np.random.random([depth, tables_num])
        self.b = np.random.uniform(0, a, [1, tables_num])
        # 初始化空的hash_table
        self.hash_tables = [dict() for i in range(tables_num)]

    def _hash(self, inputs: Union[List[List], np.ndarray]):
        """
        将向量映射到对应的hash_table的索引
        :param inputs: 输入的单个或多个向量
        :return: 每一行代表一个向量输出的所有索引,每一列代表位于一个hash_table中的索引
        """
        # H(V) = |V·R + b| / a,R是一个随机向量,a是桶宽,b是一个在[0,a]之间均匀分布的随机变量
        hash_val = np.floor(np.abs(np.matmul(inputs, self.R) + self.b) / self.a)

        return hash_val

    def insert(self, inputs):
        """
        将向量映射到对应的hash_table的索引,并插入到所有hash_table中
        :param inputs:
        :return:
        """
        # 将inputs转化为二维向量
        inputs = np.array(inputs)
        if len(inputs.shape) == 1:
            inputs = inputs.reshape([1, -1])

        hash_index = self._hash(inputs)
        for inputs_one, indexs in zip(inputs, hash_index):
            for i, key in enumerate(indexs):
                # i代表第i个hash_table,key则为当前hash_table的索引位置
                # inputs_one代表当前向量
                self.hash_tables[i].setdefault(key, []).append(tuple(inputs_one))

    def query(self, inputs, nums=20):
        """
        查询与inputs相似的向量,并输出相似度最高的nums个
        :param inputs: 输入向量
        :param nums:
        :return:
        """
        hash_val = self._hash(inputs).ravel()
        candidates = set()

        # 将相同索引位置的向量添加到候选集中
        for i, key in enumerate(hash_val):
            candidates.update(self.hash_tables[i][key])

        # 根据向量距离进行排序
        candidates = sorted(candidates, key=lambda x: self.euclidean_dis(x, inputs))
        return candidates[:nums]

    @staticmethod
    def euclidean_dis(x, y):
        """
        计算欧式距离
        :param x:
        :param y:
        :return:
        """
        x = np.array(x)
        y = np.array(y)
        return np.sqrt(np.sum(np.power(x - y, 2)))


if __name__ == '__main__':
    data = np.random.random([10000, 100])
    query = np.random.random([100])

    lsh = EuclideanLSH(10, 1, 100)
    lsh.insert(data)
    # 开始查询
    res = lsh.query(query, 20)
    res = np.array(res)
    print(np.sum(np.power(res - query, 2), axis=-1))  # 计算LSH的结果与query的结果的差距
    all_data = np.concatenate((data, [query]))
    sort = np.argsort(np.sum(np.power(all_data - query, 2), axis=-1))  # 线性查找真正的最接近的曲线
    print(np.sum(np.power(all_data[sort[:20]] - query, 2), axis=-1))  # 计算最接近的20个结果
    print(np.sum(np.power(all_data[sort[-20:]] - query, 2), axis=-1))  # 对比计算最远的20个结果

二、第三方库datasketch使用

github项目地址:https://github.com/ekzhu/datasketch

pip安装:pip install datasketch

1. 官方示例

from datasketch import MinHash, MinHashLSH

set1 = set(['minhash', 'is', 'a', 'probabilistic', 'data', 'structure', 'for',
            'estimating', 'the', 'similarity', 'between', 'datasets'])
set2 = set(['minhash', 'is', 'a', 'probability', 'data', 'structure', 'for',
            'estimating', 'the', 'similarity', 'between', 'documents'])
set3 = set(['minhash', 'is', 'probability', 'data', 'structure', 'for',
            'estimating', 'the', 'similarity', 'between', 'documents'])

m1 = MinHash(num_perm=128)
m2 = MinHash(num_perm=128)
m3 = MinHash(num_perm=128)
for d in set1:
    m1.update(d.encode('utf8'))
for d in set2:
    m2.update(d.encode('utf8'))
for d in set3:
    m3.update(d.encode('utf8'))

# Create LSH index
lsh = MinHashLSH(threshold=0.5, num_perm=128)
lsh.insert("m2", m2)
lsh.insert("m3", m3)
result = lsh.query(m1)
print("Approximate neighbours with Jaccard similarity > 0.5", result)

得到的结果:

Approximate neighbours with Jaccard similarity > 0.5 ['m3', 'm2']

2. LSH算法

文档地址:http://ekzhu.com/datasketch/documentation.html?highlight=minhashgenerator#minhash-lsh

import numpy as np
from datasketch import WeightedMinHashGenerator
from datasketch import MinHashLSH
from tqdm import tqdm

all_data = np.random.random([10000, 100])
query = np.random.random([100])

mg = WeightedMinHashGenerator(all_data.shape[1])
lsh = MinHashLSH(threshold=0.7)
for index, value in tqdm(enumerate(all_data)):
    m_hash = mg.minhash(value)
    lsh.insert(index, m_hash)

result = lsh.query(mg.minhash(query))
print(result)

# 开始验证
print(np.sum(np.power(all_data[result] - query, 2), axis=-1))  # 计算LSH的结果与query的结果的差距
total_data = np.concatenate((all_data, [query]))
sort = np.argsort(np.sum(np.power(total_data - query, 2), axis=-1))  # 线性查找真正的最接近的曲线
print(np.sum(np.power(total_data[sort[:20]] - query, 2), axis=-1))  # 计算最接近的曲线
print(np.sum(np.power(total_data[sort[-20:]] - query, 2), axis=-1))

3. MinHashLSHForest

MinHashLSHForest可以选择Top K的内容

import numpy as np
from datasketch import WeightedMinHashGenerator
from datasketch import MinHashLSHForest
from tqdm import tqdm

all_data = np.random.random([10000, 100])
query = np.random.random([100])

mg = WeightedMinHashGenerator(all_data.shape[1])
forest = MinHashLSHForest()
for index, value in tqdm(enumerate(all_data)):
    m_hash = mg.minhash(value)
    forest.add(index, m_hash)

forest.index()  # 重要!在此之后才可以使用查询功能
result = forest.query(mg.minhash(query), 20)  # 选择top20
print(result)

# 开始验证
print(np.sum(np.power(all_data[result] - query, 2), axis=-1))  # 计算LSH的结果与query的结果的差距
total_data = np.concatenate((all_data, [query]))
sort = np.argsort(np.sum(np.power(total_data - query, 2), axis=-1))  # 线性查找真正的最接近的曲线
print(np.sum(np.power(total_data[sort[:20]] - query, 2), axis=-1))  # 计算最接近的曲线
print(np.sum(np.power(total_data[sort[-20:]] - query, 2), axis=-1))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python使用局部敏感性哈希算法,在海量数据中查询相似序列 的相关文章

随机推荐

  • Leetcode动态规划部分典型题目分类及总结

    参考内容 https leetcode cn com problems longest palindromic substring solution zhong xin kuo san dong tai gui hua by liweiwe
  • 创建vue脚手架时,npmERR报错的解决方法

    创建vue脚手架 1 我是刚学vue的小白 在安装vue脚手架的时候 遇到了安装时出现的问题 查阅了我几个小时 苦苦在挣扎着 确实难受 想借此机会把它给记录下来 希望能帮助更多的初学者解决疑惑 2 我在安装时遇到了这个问题 当时我一直在网上
  • Ubuntu安装nvidia显卡驱动,CUDA与CUDNN

    本文提到的文件可以在这里下载 链接 https pan baidu com s 1cfo0xqrXoK3pA4pHUN3Mcw 提取码 kdjq 目录 1 安装nvidia显卡驱动 2 安装CUDA 3 安装CUDNN 1 安装nvidia
  • [错误解决] paramiko.ssh_exception.SSHException: Error reading SSH protocol banner

    最近项目中需配置sftp上传下载 配置好环境后连接报错 报错信息如图 paramiko ssh exception SSHException Error reading SSH protocol banner 解决方式一 设置banner
  • 域名解析的查看

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 目录 一 配置域名解析 DNS与Host 1 hosts文件 2 配置DNS 3 Host表解析与DNS机械的次序由文件 etc host conf决定 Hosts优先于DN
  • 图的广度优先遍历 + 拓扑排序(笔记)

    广度优先遍历 模板题 广度优先遍历的大体思路就是 每次扩展当前一步能到达的未标记的点加入队列中并标记 每次也从队列中拿出一个点进行扩展 该题是让求最权值都相等的短路我们就可以利用广度优先搜索来求 include
  • 数据仓库理论知识

    一 数据仓库与数据集市 可以简单理解为数据仓库是面向整个企业 而数据集市是面向某个部门的 数据集市的数据来自数据仓库 当然 如果没有数据仓库 数据集市的数据也可以直接取自业务数据库 1 离线与实时 离线数仓 从业务上看 对已知范围的数据定时
  • linux 动态库 段错误,dlopen加载so动态链接库出现段错误的问题

    so库中暴露出来的函数 写在某基类头文件中 大体如下 ifdef cplusplus extern C endif Object construct return new Object void destroy Object object
  • Linux操作系统基础知识学习

    Q1 什么是GNU Linux与GNU有什么关系 A 1 GNU是GNU is Not Unix的递归缩写 是自由软件基金会 Free Software Foundation FSF 的一个项目 该项目已经开发了许多高质量的编程工具 包括e
  • STM32串口调试一直打印 00 00

    在STM32串口调试过程中 通过printf函数往串口打印英文字母 串口助手却一直收到 00 凭直觉 这种情况一般都是时钟没配置好 但是查代码很难找到原因 经过反复查找 发现是STM32CubeMX中时钟源选择错误 就是下面这个地方 切记一
  • Go 语言运行时环境变量快速导览

    原文 http dave cheney net 2015 11 29 a whirlwind tour of gos runtime environment variables Go 语言运行时环境变量快速导览 介绍 Go Runtime除
  • ubuntu 打包deb并带有安装目录

    0 简介 当在ubuntu下开发了一个工程 期望以deb包的形式发布出去的时候 会涉及到打包操作 基本指令是 dpkg b
  • docker registry2 仓库搭建与使用

    docker registry2 仓库搭建与使用 docker pull registry 1 docker io distribution registry 2 1 1 以TLS证书认证启动docker registry2 产生证书 mk
  • hibernate关联关系

    前言 今天要分享的知识是hibernate框架的关联关系 码字不易 点个赞 转载请说明 开发工具 eclipse 目录 一 一对多的配置 二 懒加载 1 定义 懒加载可以这样理解 只加载某一项东西 其他的东西不会加载 2 操作 在我们进行项
  • 问题解决:WSL2 中进行 apt-get-update 失败

    WSL2 子系统在一些操作上还是很方便的 但因为有些配置和 Windows 共用的原因 总会出现这样那样的问题 比如今天安装 Redis 的时候需要提前进行包更新 结果却报错 Failed to fetch 这个问题的出现我首先是考虑国外源
  • Error: JAVA_HOME is not set

    启动Hadoop时显示这句话 解决方法 通过echo JAVA HOME找到java安装目录 在hadoop的配置目录etc hadoop中 我的是 usr local hadoop etc hadoop 修改hadoop env sh配置
  • jenkins - Manage and Assign Roles

    Role Strategy Plugin 插件 针对多个project进行权限控制 访问 上几张图 希望你能看明白 哈哈 1 png 710dba0dgy1fkgqp3cze1j219g0kmn24 jpg 710dba0dgy1fkgqp
  • MySQL查询语句in子查询的优化

    项目中有需要 使用MySQL的in子查询 查询符合in子查询集合中条件的数据 但是没想到的是 MySQL的in子查询会如此的慢 让人无法接收 于是上网搜索解决办法 下面记录下 一 原始in子查询 SELECT FROM basic zdjb
  • Ubuntu系统上安装WPS

    前言 在Ubuntu系统下 想使用WPS的功能 觉得用起来更加方便 所以在此记录一下安装的步骤 记录两种安装方法 方法一 Ubuntu Software中搜索WPS 如图所示 在Ubuntu Software中搜索WPS 可能需要稍等一会再
  • python使用局部敏感性哈希算法,在海量数据中查询相似序列

    文章目录 一 原生python实现 二 第三方库datasketch使用 1 官方示例 2 LSH算法 3 MinHashLSHForest 局部敏感性哈希是指 相似的哈希具有相似的原始序列 整体思路 首先将数据装在不同的桶里 通过桶之间的