最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python最小哈希實現(xiàn)海量文檔去重的具體方案

 更新時間:2026年01月27日 09:17:14   作者:AI手記叨叨  
本文介紹了使用最小哈希和局部敏感哈希進行海量文檔去重的解決方案,通過Jaccard相似度衡量文檔相似性,將文檔轉換為特征集合,利用多個哈希函數(shù)生成最小哈希簽名,通過比較簽名相似度來估計文檔相似度,該方法能有效解決百萬級數(shù)據(jù)去重的性能瓶頸問題,需要的朋友可以參考下

對百萬級以上的數(shù)據(jù)做相似文檔去重時,往往會面臨性能瓶頸。最小哈希(MinHash)結合局部敏感哈希(LSH)為我們提供了高效的解決方案。

一、 Jaccard相似度:相似性度量的基礎

Jaccard相似度衡量兩個集合的相似程度:

J(A,B) = |A ∩ B| / |A ∪ B|

在文檔去重中,我們首先將文檔轉換為特征集合。常用方法包括:

1. 詞級別的Shingles

對于中文文檔,通常先分詞,然后生成k個連續(xù)詞的片段:

# 示例:文檔"我在學習編程"
分詞后:["我", "在", "學習", "編程"]
3-shingles:{"我 在 學習", "在 學習 編程"}

代碼實現(xiàn):

import jieba


def generate_word_shingles(text, k=3):
    """
    生成詞級別的shingles
    """
    # 分詞
    words = list(jieba.cut(text))

    # 生成k個連續(xù)詞的片段
    shingles = set()
    for i in range(len(words) - k + 1):
        shingle = ' '.join(words[i:i + k])
        shingles.add(shingle)

    return shingles


# 示例
text = "我在學習編程"
shingles = generate_word_shingles(text, k=3)
print("3-shingles:", shingles)
# 輸出: {'我 在 學習', '在 學習 編程'}

2. 字符級別的n-grams

text1的3-grams集合: {"我在學", "在學習", "學習編", "習編程"}
text2的3-grams集合: {"我現(xiàn)在", "現(xiàn)在學", "在學習", "學習編", "習編程"}

交集 = {"在學習", "學習編", "習編程"} = 3個
并集 = {"我在學", "在學習", "學習編", "習編程", "我現(xiàn)在", "現(xiàn)在學"} = 6個
Jaccard相似度 = 3/6 = 0.5

代碼實現(xiàn):

def generate_char_ngrams(text, n=3):
    """
    生成字符級別的n-grams

    參數(shù):
    text: 輸入文本
    n: n-gram的大小

    返回:
    set: n-grams集合
    """
    ngrams = set()
    for i in range(len(text) - n + 1):
        ngram = text[i:i + n]
        ngrams.add(ngram)

    return ngrams


# 示例
text1 = "我在學習編程"
text2 = "我現(xiàn)在學習編程"

ngrams1 = generate_char_ngrams(text1, n=3)
ngrams2 = generate_char_ngrams(text2, n=3)

print("text1的3-grams集合:", ngrams1)
print("text2的3-grams集合:", ngrams2)

# 計算Jaccard相似度
intersection = ngrams1.intersection(ngrams2)
union = ngrams1.union(ngrams2)
jaccard_sim = len(intersection) / len(union)

print("交集:", intersection)
print("并集:", union)
print("Jaccard相似度:", jaccard_sim)

二、 最小哈希:從集合相似度到簽名相似度

1. 數(shù)學原理

對于一次隨機排列π:

P[min(π(A)) = min(π(B))] = J(A,B)

其中min(π(S))表示集合S在排列π中的最小元素

2. 最小哈希過程

我們使用哈希函數(shù)模擬隨機排列。以下示例展示3個不同哈希函數(shù)的工作過程:

文檔A的shingles: {"我在學", "在學習", "學習編", "習編程"}
文檔B的shingles: {"我現(xiàn)在", "現(xiàn)在學", "在學習", "學習編", "習編程"}

哈希函數(shù)h?:
h?("我在學") = 150
h?("在學習") = 80    ← 兩個文檔的最小值!
h?("學習編") = 200
h?("習編程") = 180
h?("我現(xiàn)在") = 250
h?("現(xiàn)在學") = 300

文檔A的min-hash? = min(150,80,200,180) = 80
文檔B的min-hash? = min(250,300,80,200,180) = 80
結果:相等 

哈希函數(shù)h?:
h?("我在學") = 30    ← 文檔A的最小值!
h?("在學習") = 150
h?("學習編") = 200
h?("習編程") = 180
h?("我現(xiàn)在") = 25    ← 文檔B的最小值!
h?("現(xiàn)在學") = 300

文檔A的min-hash? = 30
文檔B的min-hash? = 25
結果:不相等 

哈希函數(shù)h?:
h?("我在學") = 400
h?("在學習") = 250
h?("學習編") = 50    ← 兩個文檔的最小值!
h?("習編程") = 150
h?("我現(xiàn)在") = 300
h?("現(xiàn)在學") = 350

文檔A的min-hash? = 50
文檔B的min-hash? = 50
結果:相等 

代碼實現(xiàn)(注:與示例數(shù)據(jù)不同):

import hashlib


def hash_shingle(shingle, hash_func_num):
    """
    對shingle進行哈希
    """
    # 使用不同的哈希函數(shù)模擬隨機排列
    # 使用不同的鹽值來模擬不同的哈希函數(shù)
    salt = f"salt_{hash_func_num}"
    data = (shingle + salt).encode('utf-8')

    # 使用MD5哈希并轉換為整數(shù)
    hash_hex = hashlib.md5(data).hexdigest()
    hash_int = int(hash_hex, 16) % (10 ** 6)  # 取模得到合適大小的整數(shù)

    return hash_int


def calculate_minhash(shingles_set, num_hash_funcs=3):
    """
    計算文檔的最小哈希簽名
    """
    # 初始化最小哈希值為無窮大
    minhash_signature = [float('inf')] * num_hash_funcs

    for shingle in shingles_set:
        for i in range(num_hash_funcs):
            hash_value = hash_shingle(shingle, i)
            if hash_value < minhash_signature[i]:
                minhash_signature[i] = hash_value

    return minhash_signature


# 文檔A和B的shingles(使用字符級別的3-grams)
docA_shingles = {"我在學", "在學習", "學習編", "習編程"}
docB_shingles = {"我現(xiàn)在", "現(xiàn)在學", "在學習", "學習編", "習編程"}

# 計算最小哈希簽名
minhash_A = calculate_minhash(docA_shingles, num_hash_funcs=300)
minhash_B = calculate_minhash(docB_shingles, num_hash_funcs=300)

print("文檔A的300維哈希簽名:", minhash_A)
print("文檔B的300維哈希簽名:", minhash_B)


# 計算簽名相似度
def signature_similarity(sigA, sigB):
    """計算兩個簽名的Jaccard相似度估計值"""
    matches = sum(1 for a, b in zip(sigA, sigB) if a == b)
    return matches / len(sigA)


similarity = signature_similarity(minhash_A, minhash_B)
print("簽名相似度估計值:", similarity)

3. N維哈希簽名

N維哈希簽名包含N個哈希函數(shù)對應的N個最小值:

文檔A的3維哈希簽名: [80, 30, 50]
文檔B的3維哈希簽名: [80, 25, 50]

簽名的相似度計算

def signature_similarity(sigA, sigB):
    """計算兩個簽名的Jaccard相似度估計值"""
    matches = sum(1 for a, b in zip(sigA, sigB) if a == b)
    return matches / len(sigA)

# 示例
similarity = signature_similarity([80, 30, 50], [80, 25, 50])
# 2/3 ≈ 0.667(接近真實值0.5)

三、 為什么需要多個哈希函數(shù)?

1. 統(tǒng)計精度原理

根據(jù)大數(shù)定律,當哈希函數(shù)足夠多時,簽名相似度會收斂到真實Jaccard相似度

2. 不同哈希數(shù)量下的精度

通過計算簽名相似度估計值的置信區(qū)間,展示隨著哈希函數(shù)數(shù)量的增加,最小哈希方法對真實Jaccard相似度的估計精度如何提升。

置信區(qū)間表示在一定的置信水平下(此處為95%),真實相似度落在一個區(qū)間內(nèi)的概率。

  • 區(qū)間越窄,表示估計越精確。
  • 區(qū)間越寬,表示估計的不確定性越高。
import math


def confidence_interval(n, s=0.5):
    """計算95%置信區(qū)間"""
    std = math.sqrt(s * (1 - s) / n)
    margin = 1.96 * std
    return [max(0, s - margin), min(1, s + margin)]


print(confidence_interval(1, s=0.5))
print(confidence_interval(10, s=0.5))
print(confidence_interval(100, s=0.5))
print(confidence_interval(500, s=0.5))
print(confidence_interval(1000, s=0.5))

[0, 1]
[0.19009678930349883, 0.8099032106965012]
[0.402, 0.598]
[0.4561730676410041, 0.5438269323589959]
[0.4690096789303499, 0.5309903210696502]

四、 局部敏感哈希:加速相似搜索

1. LSH核心思想

如果兩個文檔整體相似,那么它們的簽名在某些局部片段很可能完全相同。LSH將長簽名切分成多個片段(bands),只要求某些片段匹配。

2. 簽名分片示例

在實際應用中,我們通常設計bands數(shù)量能被簽名長度整除

假設120維原始簽名:
[123, 456, 789, 321, 654, 987, ..., 888]

以切成20個片為例(每片6維):
片 1: [123, 456, 789, ..., ...] 
片 2: [..., ..., ..., ..., ...] 
...
片 20: [..., ..., ..., ..., 888] 

為每個片哈希成一個鍵值

片 1: = hash(tuple(band1))  # 如 0x1a2b3c
片 2: = hash(tuple(band2))  # 如 0x4d5e6f
片 3: = hash(tuple(band3))  # 如 0x7a8b9c  
片 4: = hash(tuple(band4))  # 如 0xd1e2f3

3. 數(shù)學原理

設兩個文檔相似度為s,每個片有r行,共有b個片(band):

def lsh_probability(s, r=6, b=20):
    """計算LSH匹配概率"""
    prob_one_band = s ** r          # 單個band匹配的概率
    prob_at_least_one = 1 - (1 - prob_one_band) ** b
    return prob_at_least_one

# 示例:相似度0.8的文檔
prob = lsh_probability(0.8, 6, 20)  # ≈ 0.9940
# 99.4%的概率會被LSH放到同一個桶中

4. LSH索引構建

鍵值文檔
0x1a2b3c[123, 456, 789, …, …][文檔A, 文檔X, 文檔Y]
0x4d5e6f[…, …, …, …, …][文檔B, 文檔C]
0x7a8b9c[…, …, …, …, …][文檔D]

到此,我們便構建完成了LSH哈希與文檔的對應關系,在使用時,只檢查文檔的各個片在哈希表中是否存在,將匹配的文檔再合并為候選集,進一步精確相似度計算。

五、 應用場景

1. 適用場景

搜索引擎去重:去除重復網(wǎng)頁
新聞聚合:識別同一事件的不同報道
論文查重:檢測學術不端
代碼查重:識別抄襲代碼
商品去重:合并相似商品描述

2. 技術限制

短文本效果差:shingles數(shù)量不足時精度下降
語義相似度:對同義替換不敏感
參數(shù)敏感:需要根據(jù)數(shù)據(jù)調(diào)整參數(shù)
近似算法:存在假陽性和假陰性

六、 總結

最小哈希結合局部敏感哈希為大規(guī)模文檔去重提供了高效的解決方案
數(shù)學基礎堅實:基于Jaccard相似度的概率估計
計算高效:將O(n²)復雜度降為近似O(n)
內(nèi)存友好:固定維度簽名大幅減少存儲需求
可擴展性強:支持分布式和流式處理

以上就是Python最小哈希實現(xiàn)海量文檔去重的具體方案的詳細內(nèi)容,更多關于Python最小哈希文檔去重的資料請關注腳本之家其它相關文章!

相關文章

  • python異步Web框架sanic的實現(xiàn)

    python異步Web框架sanic的實現(xiàn)

    這篇文章主要介紹了python異步Web框架sanic的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • Python+wxPython實現(xiàn)自動生成PPTX文檔程序

    Python+wxPython實現(xiàn)自動生成PPTX文檔程序

    這篇文章主要介紹了如何使用 wxPython 模塊和 python-pptx 模塊來編寫一個程序,用于生成包含首頁、內(nèi)容頁和感謝頁的 PPTX 文檔,感興趣的小伙伴可以學習一下
    2023-08-08
  • Python基礎教程之正則表達式基本語法以及re模塊

    Python基礎教程之正則表達式基本語法以及re模塊

    正則表達式是可以匹配文本片段的模式,今天的Python就跟大家一起討論一下python中的re模塊,python re模塊感興趣的朋友一起學習吧
    2016-03-03
  • Python hexstring-list-str之間的轉換方法

    Python hexstring-list-str之間的轉換方法

    今天小編就為大家分享一篇Python hexstring-list-str之間的轉換方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Python不區(qū)分大小寫進行文本處理終極指南

    Python不區(qū)分大小寫進行文本處理終極指南

    Python標準庫提供了多種處理大小寫不敏感操作的工具和技巧,本文將深入解析不區(qū)分大小寫文本處理的技術體系,有需要的小伙伴可以跟隨小編一起學習一下
    2025-08-08
  • Python結合多線程與協(xié)程實現(xiàn)高效異步請求處理

    Python結合多線程與協(xié)程實現(xiàn)高效異步請求處理

    在現(xiàn)代Web開發(fā)和數(shù)據(jù)處理中,高效處理HTTP請求是關鍵挑戰(zhàn)之一,本文將結合Python異步IO(asyncio)和多線程技術,探討如何優(yōu)化請求處理邏輯,解決常見的線程事件循環(huán)問題,有需要的小伙伴可以根據(jù)需求進行選擇
    2025-04-04
  • Python實現(xiàn)將JSON轉換為CSV格式

    Python實現(xiàn)將JSON轉換為CSV格式

    JSON(JavaScript??Object?Notation)和?CSV(Comma-Separated?Values)是數(shù)據(jù)交換和存儲中最常用的兩種格式,本文將詳細介紹如何使用Free?Spire.XLS?for?Python將JSON數(shù)據(jù)轉換為?CSV?文件,感興趣的小伙伴可以了解下
    2026-03-03
  • 在終端啟動Python時報錯的解決方案

    在終端啟動Python時報錯的解決方案

    這篇文章主要介紹了在終端啟動Python時報錯的解決方案,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-11-11
  • python攻防-破解附近局域網(wǎng)WIFI密碼實現(xiàn)上網(wǎng)自由

    python攻防-破解附近局域網(wǎng)WIFI密碼實現(xiàn)上網(wǎng)自由

    本文將記錄學習如何通過 Python 腳本實破解附近局域網(wǎng) WIFI 密碼的暴力破解,隨時隨地免費蹭網(wǎng),再也不被WiFi密碼困擾,實現(xiàn)蹭網(wǎng)自由
    2021-08-08
  • python簡單批量梯度下降代碼

    python簡單批量梯度下降代碼

    大家好,本篇文章主要講的是python簡單批量梯度下降代碼,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評論

科技| 卓尼县| 宿迁市| 岐山县| 濮阳县| 呼伦贝尔市| 丰台区| 塔城市| 景泰县| 云南省| 浑源县| 遂平县| 睢宁县| 赣州市| 阳城县| 绥中县| 天门市| 申扎县| 柘城县| 玛曲县| 乃东县| 甘泉县| 华宁县| 青岛市| 岚皋县| 卢氏县| 长丰县| 鹤岗市| 久治县| 华容县| 交口县| 昔阳县| 温宿县| 贡山| 仁怀市| 浑源县| 大方县| 安福县| 博兴县| 泽库县| 新绛县|