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秒。

相关推荐
缺点内向2 小时前
C#: 高效移动与删除Excel工作表
开发语言·c#·.net·excel
@forever@2 小时前
【JAVA】LinkedList与链表
java·python·链表
程序员爱钓鱼3 小时前
Python编程实战:面向对象与进阶语法——类型注解与代码规范(PEP 8)
后端·python·ipython
程序员爱钓鱼3 小时前
Python实战:用高德地图API批量获取地址所属街道并写回Excel
后端·python·ipython
天地之于壹炁兮3 小时前
编程I/O入门指南:核心操作全解析
数据库·windows·microsoft
深圳市恒讯科技4 小时前
英国服务器Windows系统远程桌面安装与优化
运维·服务器·windows
reasonsummer4 小时前
【教学类-97-06】20251105“葡萄”橡皮泥黏贴(小班主题《苹果与橘子》)
python
卖个几把萌4 小时前
【16】Selenium+Python 接管已打开谷歌浏览器
python·selenium·测试工具
像风一样的男人@5 小时前
python --两个文件夹文件名比对(yolo 图和label标注比对检查)
windows·python·yolo
lllsure5 小时前
【Python】Dict(字典)
开发语言·python