比较两个excel文件的指定列是否一致

python 复制代码
import pandas as pd
import os
from typing import Tuple, Dict, List
import warnings
warnings.filterwarnings('ignore')

def validate_file_and_columns(file_path: str, key_col: str, compare_cols: List[str]) -> Tuple[pd.DataFrame, bool]:
    """
    验证文件是否存在以及指定列是否存在
    :param file_path: Excel文件路径
    :param key_col: 检索列(用于匹配行的列)
    :param compare_cols: 要比较的目标列列表
    :return: DataFrame和验证结果(True/False)
    """
    # 验证文件是否存在
    if not os.path.exists(file_path):
        print(f"错误:文件 {file_path} 不存在!")
        return pd.DataFrame(), False
    
    # 读取Excel文件
    try:
        df = pd.read_excel(file_path)
    except Exception as e:
        print(f"错误:读取文件 {file_path} 失败 - {str(e)}")
        return pd.DataFrame(), False
    
    # 验证检索列是否存在
    all_cols = df.columns.tolist()
    if key_col not in all_cols:
        print(f"错误:文件 {file_path} 中不存在检索列 '{key_col}'")
        print(f"该文件包含的列:{all_cols}")
        return pd.DataFrame(), False
    
    # 验证所有比较列是否存在
    missing_cols = [col for col in compare_cols if col not in all_cols]
    if missing_cols:
        print(f"错误:文件 {file_path} 中缺少以下比较列:{missing_cols}")
        print(f"该文件包含的列:{all_cols}")
        return pd.DataFrame(), False
    
    # 检查检索列是否有重复值
    if df[key_col].duplicated().any():
        duplicate_values = df[df[key_col].duplicated(keep=False)][key_col].unique()
        print(f"警告:文件 {file_path} 的检索列 '{key_col}' 存在重复值:{duplicate_values[:5]}...")
    
    return df, True

def compare_excel_columns(
    file1_path: str,
    file2_path: str,
    key_col: str,
    compare_cols: List[str],
    output_result: bool = True,
    output_path: str = "comparison_result.xlsx"
) -> Dict[str, List]:
    """
    比较两个Excel文件的指定列
    :param file1_path: 第一个Excel文件路径
    :param file2_path: 第二个Excel文件路径
    :param key_col: 检索列(用于匹配行的列)
    :param compare_cols: 要比较的目标列列表
    :param output_result: 是否保存比较结果到Excel
    :param output_path: 结果文件保存路径
    :return: 比较结果字典
    """
    print("="*50)
    print("开始比较Excel文件...")
    print(f"文件1:{file1_path}")
    print(f"文件2:{file2_path}")
    print(f"检索列:{key_col}")
    print(f"比较列:{compare_cols}")
    print("="*50)
    
    # 验证并读取两个文件
    df1, df1_valid = validate_file_and_columns(file1_path, key_col, compare_cols)
    df2, df2_valid = validate_file_and_columns(file2_path, key_col, compare_cols)
    
    if not df1_valid or not df2_valid:
        print("文件验证失败,终止比较!")
        return {"error": "文件验证失败"}
    
    # 以检索列为索引,方便匹配
    df1_indexed = df1.set_index(key_col)
    df2_indexed = df2.set_index(key_col)
    
    # 获取所有检索键
    keys1 = set(df1_indexed.index)
    keys2 = set(df2_indexed.index)
    
    # 分析键的匹配情况
    common_keys = sorted(keys1 & keys2)  # 共同存在的键(用于比较)
    only_in_file1 = sorted(keys1 - keys2)  # 只在文件1中存在的键
    only_in_file2 = sorted(keys2 - keys1)  # 只在文件2中存在的键
    
    print(f"\n检索列匹配情况:")
    print(f"共同存在的记录数:{len(common_keys)}")
    print(f"仅文件1存在的记录数:{len(only_in_file1)}")
    print(f"仅文件2存在的记录数:{len(only_in_file2)}")
    
    # 比较共同键的目标列
    match_results = []
    mismatch_results = []
    
    print(f"\n正在比较 {len(common_keys)} 条共同记录...")
    
    for key in common_keys:
        row1 = df1_indexed.loc[key]
        row2 = df2_indexed.loc[key]
        
        row_result = {key_col: key}
        is_mismatch = False
        
        for col in compare_cols:
            val1 = row1[col]
            val2 = row2[col]
            
            # 处理NaN值的比较(NaN == NaN 结果为False,这里视为相等)
            if pd.isna(val1) and pd.isna(val2):
                match_status = "一致"
            elif pd.isna(val1) or pd.isna(val2):
                match_status = "不一致"
                is_mismatch = True
            elif str(val1) == str(val2):  # 转为字符串比较,避免数值类型差异(如int和float)
                match_status = "一致"
            else:
                match_status = "不一致"
                is_mismatch = True
            
            row_result[f"{col}_文件1"] = val1
            row_result[f"{col}_文件2"] = val2
            row_result[f"{col}_比较结果"] = match_status
        
        if is_mismatch:
            mismatch_results.append(row_result)
        else:
            match_results.append(row_result)
    
    # 统计结果
    total_common = len(common_keys)
    match_count = len(match_results)
    mismatch_count = len(mismatch_results)
    
    print(f"\n比较结果统计:")
    print(f"完全一致的记录数:{match_count}")
    print(f"存在不一致的记录数:{mismatch_count}")
    print(f"一致率:{match_count/total_common*100:.2f}%" if total_common > 0 else "无共同记录可比较")
    
    # 整理最终结果
    final_results = {
        "共同记录_完全一致": match_results,
        "共同记录_存在不一致": mismatch_results,
        "仅文件1存在的记录": [{key_col: key} for key in only_in_file1],
        "仅文件2存在的记录": [{key_col: key} for key in only_in_file2],
        "统计信息": {
            "文件1总记录数": len(df1),
            "文件2总记录数": len(df2),
            "共同记录数": total_common,
            "完全一致记录数": match_count,
            "不一致记录数": mismatch_count,
            "仅文件1记录数": len(only_in_file1),
            "仅文件2记录数": len(only_in_file2),
            "一致率(%)": match_count/total_common*100 if total_common > 0 else 0
        }
    }
    
    # 保存结果到Excel
    if output_result:
        try:
            with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
                # 写入各个结果表
                if match_results:
                    pd.DataFrame(match_results).to_excel(writer, sheet_name="完全一致", index=False)
                if mismatch_results:
                    pd.DataFrame(mismatch_results).to_excel(writer, sheet_name="存在不一致", index=False)
                if only_in_file1:
                    pd.DataFrame(only_in_file1, columns=[key_col]).to_excel(writer, sheet_name="仅文件1存在", index=False)
                if only_in_file2:
                    pd.DataFrame(only_in_file2, columns=[key_col]).to_excel(writer, sheet_name="仅文件2存在", index=False)
                
                # 写入统计信息
                stats_df = pd.DataFrame(final_results["统计信息"].items(), columns=["统计项", "数值"])
                stats_df.to_excel(writer, sheet_name="统计信息", index=False)
            
            print(f"\n比较结果已保存到:{output_path}")
        except Exception as e:
            print(f"警告:保存结果文件失败 - {str(e)}")
    
    print("\n" + "="*50)
    print("比较完成!")
    print("="*50)
    
    return final_results

# ------------------- 示例使用 -------------------
if __name__ == "__main__":
    # 配置参数(请根据实际需求修改)
    FILE1_PATH = "file1.xlsx"       # 第一个Excel文件路径
    FILE2_PATH = "file2.xlsx"       # 第二个Excel文件路径
    KEY_COLUMN = "ID"               # 检索列(用于匹配行的唯一标识列)
    COMPARE_COLUMNS = ["姓名", "年龄", "成绩"]  # 要比较的目标列列表
    OUTPUT_PATH = "comparison_result.xlsx"  # 结果输出路径
    
    # 执行比较
    results = compare_excel_columns(
        file1_path=FILE1_PATH,
        file2_path=FILE2_PATH,
        key_col=KEY_COLUMN,
        compare_cols=COMPARE_COLUMNS,
        output_result=True,
        output_path=OUTPUT_PATH
    )

代码核心功能说明:

  1. 文件验证

    • 检查文件是否存在
    • 验证检索列和比较列是否存在于两个文件中
    • 检测检索列是否有重复值(避免一对多匹配问题)
  2. 行匹配逻辑

    • 以指定的「检索列」(如 ID)作为唯一标识,匹配两个文件中的对应行
    • 自动识别三种情况:共同存在的行、仅在文件 1 存在的行、仅在文件 2 存在的行
  3. 值比较规则

    • 支持多列同时比较
    • 处理 NaN / 空值(两个空值视为一致)
    • 转为字符串比较,避免数值类型差异(如 100 和 100.0 视为一致)
    • 详细记录每列的比较结果
  4. 结果输出

    • 控制台显示统计信息(匹配率、各类记录数)
    • 生成 Excel 结果文件,包含 5 个工作表:
      • 完全一致:所有比较列都匹配的记录
      • 存在不一致:至少有一列不匹配的记录(显示具体差异)
      • 仅文件 1 存在:只在第一个文件中出现的记录
      • 仅文件 2 存在:只在第二个文件中出现的记录
      • 统计信息:详细的数量统计

使用方法:

  1. 安装依赖

    bash

    复制代码
    pip install pandas openpyxl
  2. 修改配置参数

    • FILE1_PATHFILE2_PATH:改为你的两个 Excel 文件路径
    • KEY_COLUMN:改为用于匹配行的列名(如 ID、编号等唯一标识)
    • COMPARE_COLUMNS:改为需要比较的列名列表(可多个)
    • OUTPUT_PATH:结果文件保存路径(默认即可)
  3. 运行代码

    • 直接运行脚本,会自动完成比较并生成结果文件

注意事项:

  1. 检索列建议使用唯一标识(如 ID),避免重复值导致匹配混乱
  2. 支持.xlsx 和.xls 格式(.xls 需要额外安装 xlrd 库:pip install xlrd==1.2.0
  3. 对于日期类型,会转为字符串比较(确保两个文件的日期格式一致)
  4. 结果文件会覆盖同名文件,请确保输出路径正确
相关推荐
0小豆03 小时前
【系列开篇】从零构建智能字幕校准系统:一个AI+微服务的完整实战之旅
spring boot·python·nlp·微服务架构·实战项目·spacy·ai算法
周杰伦_Jay3 小时前
【主流开发语言深度对比】Python/Go/Java/JS/Rust/C++评测
开发语言·python·golang
盈电智控3 小时前
体力劳动反而更难被AI取代?物联网科技如何守护最后的劳动阵地
开发语言·人工智能·python
隔壁阿布都3 小时前
Spring Boot中的Optional如何使用
开发语言·spring boot·python
谢景行^顾4 小时前
深度学习--激活函数
人工智能·python·机器学习
三千院本院4 小时前
LlaMA_Factory实战微调Qwen-LLM大模型
人工智能·python·深度学习·llama
wljt4 小时前
Linux 常用命令速查手册(Java开发版)
java·linux·python
WPG大大通4 小时前
AIoT | 软件:Astra MCP边缘算力构建详解
经验分享·笔记·python·硬件架构·代码
波诺波4 小时前
环境管理器
linux·前端·python