比较两个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. 结果文件会覆盖同名文件,请确保输出路径正确
相关推荐
Pocker_Spades_A16 小时前
在家写的代码,办公室接着改?Jupyter通过cpolar实现远程访问这么玩
ide·python·jupyter
m5655bj16 小时前
使用 Python 高效复制 Excel 行、列、单元格
开发语言·python·excel
龙言龙论16 小时前
身份证信息批量处理系统:从入门到实战(附exe工具+核心源码)
数据库·python
m0_6265352017 小时前
代码分析 长音频分割为短音频
javascript·python·音视频
Wpa.wk17 小时前
自动化测试环境配置-java+python
java·开发语言·python·测试工具·自动化
带刺的坐椅17 小时前
AI 应用工作流:LangGraph 和 Solon AI Flow,我该选谁?
java·python·ai·solon·flow·langgraph
工业互联网专业17 小时前
图片推荐系统_django+spider
python·django·毕业设计·源码·课程设计·spider·图片推荐系统
Lwcah18 小时前
Python | LGBM+SHAP可解释性分析回归预测及可视化算法
python·算法·回归
@一辈子爱你18 小时前
归来九十余日:在时代的夹缝中,与你共筑一道光
python
HsuHeinrich18 小时前
利用面积图探索历史温度的变化趋势
python·数据可视化