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

相关推荐
大飞记Python3 小时前
Chromedriver放项目里就行!Selenium 3 和 4 指定路径方法对比 + 兼容写法
开发语言·python
Hs_QY_FX3 小时前
Python 分类模型评估:从理论到实战(以信用卡欺诈检测为例)
人工智能·python·机器学习·数据挖掘·多分类评估
Gitpchy3 小时前
Day 18 推断聚类后簇的类型
python·机器学习·聚类
黑马金牌编程3 小时前
Jenkins的Linux与window部署方式
linux·运维·windows·jenkins·持续集成·cicd
查士丁尼·绵3 小时前
笔试-基站维护
python
deephub3 小时前
REFRAG技术详解:如何通过压缩让RAG处理速度提升30倍
人工智能·python·大语言模型·rag
唐叔在学习3 小时前
venv - Python最佳的轻量化环境隔离方式
后端·python
小白学大数据4 小时前
Python爬虫数据可视化:深度分析贝壳成交价格趋势与分布
爬虫·python·信息可视化
小小测试开发4 小时前
Python Arrow库:告别datetime繁琐,优雅处理时间与时区
开发语言·前端·python