office便捷办公06:根据相似度去掉excel中的重复行

需求说明

给定一个excel表格,希望判断各行与其他行的相似度,只有局部不同,希望根据各行的相似度,将重复度较高的行删掉。

方法1:一个最简单的方法就是将每行文本转化为字符串,然后比较字符串的重复率。

python 复制代码
from difflib import SequenceMatcher
import pandas as pd
import os
# 将每行的所有列拼成一个字符串,比较相似度,如果某行与其他行相似度大于0.9,则删除该行
def simple_duplicate_removal(input_file, threshold=0.95):
    """
    简化版本 - 直接比较重复率
    """
    # 读取数据
    df = pd.read_excel(input_file,engine='openpyxl')
    original_count = len(df)
    print(f"读取 {original_count} 行数据")

    # 将每行转换为字符串
    rows_as_strings = []
    for _, row in df.iterrows():
        row_str = "|".join([str(cell) if pd.notna(cell) else "" for cell in row])
        rows_as_strings.append(row_str)

    # 找出要保留的行
    keep_indices = []

    for i, current_row in enumerate(rows_as_strings):
        is_duplicate = False
        # 与已保留的行比较
        for j in keep_indices:
            similarity = SequenceMatcher(None, current_row, rows_as_strings[j]).ratio()
            if similarity >= threshold:
                is_duplicate = True
                print(f"行 {i+1} 与行 {j+1} 相似度: {similarity:.2%}")
                break

        if not is_duplicate:
            keep_indices.append(i)

    # 创建结果DataFrame
    result_df = df.iloc[keep_indices].reset_index(drop=True)

    # 保存结果
    result_df.to_excel(input_file, index=False)

    print(f"\n处理完成!")
    print(f"保留 {len(result_df)} 行,删除 {original_count - len(result_df)} 行")
    return result_df

def get_all_files(directory, extension):
    """
    获取指定目录下所有指定扩展名的文件
    Args:
        directory (str): 目录路径
        extension (str): 文件扩展名,如 'xlsx'

    Returns:
        list: 包含所有匹配文件路径的列表
    """
    files_list = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith('.' + extension):
                files_list.append(os.path.join(root, file))
    return files_list
# 使用示例
if __name__ == "__main__":
    for excel_file in get_all_files(r"G:\res", 'xlsx'):
        print(excel_file)
        simple_duplicate_removal(excel_file, 0.95)
        print(f'{excel_file}已去重')

这种方法的缺点是效率不高,我用一个150行的excel表格。

对于大规模数据,效率最高的方法是使用向量化操作和高效的算法。我们既要考虑相似度(而非完全相等)又要效率,可以考虑使用以下方法:

  1. 使用局部敏感哈希(LSH)或MinHash来近似计算相似度,这样可以大大减少计算量。

  2. 如果数据是数值型的,可以考虑使用聚类方法,将相似行聚类,然后每个类中只保留一个代表。

但是,由于问题要求相似度大于95%的行,且我们希望保留一个,这里推荐使用MinHash方法,因为它特别适用于大规模文档去重,可以快速估计相似度。

方法2:下面我们使用MinHash和LSH来快速查找相似行,并删除重复行

python 复制代码
import pandas as pd
from datasketch import MinHash, MinHashLSH
import jieba  # 用于中文分词,如果数据是英文可以不用

def preprocess_text(text):
    """预处理文本:这里如果是中文需要分词,英文可以按空格分或者使用n-gram"""
    # 如果是英文,可以直接用空格分割
    # return text.split()
    # 如果是中文,使用结巴分词
    return jieba.cut(text)

def create_minhash(row_str, num_perm=128):
    """为一行字符串创建MinHash"""
    m = MinHash(num_perm=num_perm)
    # 将字符串分词(或按n-gram)后添加到MinHash中
    tokens = preprocess_text(row_str)
    for token in tokens:
        m.update(token.encode('utf8'))
    return m

def remove_duplicates_with_minhash(input_file, output_file, threshold=0.95):
    """使用MinHash和LSH去除重复行"""
    # 读取数据
    df = pd.read_excel(input_file)
    print(f"原始数据行数: {len(df)}")

    # 将每行数据转换为字符串
    row_strings = []
    for index, row in df.iterrows():
        row_cleaned = [str(cell) if pd.notna(cell) else "" for cell in row]
        row_str = " ".join(row_cleaned)
        row_strings.append(row_str)

    # 创建LSH索引
    lsh = MinHashLSH(threshold=threshold, num_perm=128)
    rows_to_keep = []  # 保存保留的行索引
    minhashes = {}     # 保存每行的MinHash和行索引

    # 第一遍:为每行创建MinHash并插入LSH,同时记录需要保留的行
    for idx, row_str in enumerate(row_strings):
        minhash = create_minhash(row_str)
        minhashes[idx] = minhash

        # 查询LSH中是否有与当前行相似的行
        result = lsh.query(minhash)
        if not result:
            # 如果没有相似行,则插入LSH并保留该行
            lsh.insert(idx, minhash)
            rows_to_keep.append(idx)
        else:
            # 如果找到相似行,则打印信息并跳过(不保留当前行)
            print(f"行 {idx+1} 与行 {result[0]+1} 相似,跳过")

    # 根据保留的行索引创建新的DataFrame
    df_cleaned = df.iloc[rows_to_keep].reset_index(drop=True)
    
    # 保存结果
    df_cleaned.to_excel(output_file, index=False)
    print(f"去重后行数: {len(df_cleaned)}")
    print(f"删除行数: {len(df) - len(df_cleaned)}")
    print(f"结果已保存到: {output_file}")

if __name__ == "__main__":
    input_file = r"G:\res\输入.xlsx"
    output_file = r"G:\res\输出.xlsx"
    remove_duplicates_with_minhash(input_file, output_file, 0.95)

耗时5秒。

相关推荐
我的xiaodoujiao35 分钟前
API 接口自动化测试详细图文教程学习系列15--项目实战演练2
python·学习·测试工具·pytest
多思考少编码2 小时前
PAT甲级真题1001 - 1005题详细题解(C++)(个人题解)
c++·python·最短路·pat·算法竞赛
ZhengEnCi2 小时前
M5-markconv自定义CSS样式指南 📝
前端·css·python
ZhengEnCi2 小时前
M4-更新日志v0.1.3-Mermaid图表支持 📝
python
hsjcjh2 小时前
多模态长文本协同:用Gemini 3.1 Pro镜像官网破解复杂办公场景的效率困局(国内实测方案)
python
凯瑟琳.奥古斯特2 小时前
SQLAlchemy核心功能解析
开发语言·python·flask
卷Java3 小时前
GPTQ vs AWQ vs GGUF:模型量化工具横向测评
开发语言·windows·python
x-cmd4 小时前
[260429] x-cmd v0.9.1:一键开启 DeepSeek-V4-Pro Max 模式 + 1M 上下文;顺手重构了 uuid 模块
windows·重构·uuid·claude·curl·x-cmd·deepseek-v4-pro
念恒123064 小时前
Python(复杂判断)
python·学习
无敌的黑星星4 小时前
Java8 CompletableFuture 实战指南
linux·前端·python