HOWTO · Python

두 개의 CSV 파일을 비교하고 Python을 사용하여 차이점 인쇄

이 문서에서는 두 CSV 파일을 비교하고 파일의 차이점을 인쇄하는 다양한 방법에 대해 설명합니다.

이 페이지의 내용

비교 도구를 고르기 전에 비교 기준부터 정하세요. 전체 행 비교는 레코드의 모든 필드가 다른 레코드와 일치하는지 확인합니다. 키 기반 비교는 id 같은 공통 열로 레코드를 짝지은 뒤 추가, 삭제 또는 변경된 필드를 보고합니다. 전체 행을 비교할 때는 Python 표준 라이브러리의 csv 모듈이면 충분합니다. 키 기반 보고서에는 csv-diff가 편리하고, 파일이 이미 DataFrame 작업 흐름에 맞는 경우에는 pandas가 유용합니다. 아래 예제에서는 file1.csv와 file2.csv라는 파일명을 일관되게 사용합니다.

데이터에 맞는 비교 방법 선택하기

필드 순서가 중요하고 모든 값이 일치해야 같은 레코드로 볼 수 있다면 전체 행 비교를 사용하세요. 같은 항목의 값이 달라졌을 수 있다면 키 기반 비교를 사용하세요. id 열을 이용하면 다른 열의 값이 달라도 해당 레코드를 짝지을 수 있습니다. 작은 파일을 빠르게 비교하려면 패키지를 설치할 필요가 없는 표준 라이브러리를 사용하면 됩니다. 변경된 필드를 보고 싶다면 csv-diff 또는 pandas를 선택하세요. 각 방법은 서로 다른 질문에 답하므로 결과를 해석하기 전에 중복과 레코드 순서가 중요한지 결정해야 합니다.

Python의 csv 모듈로 CSV 전체 행 비교하기

원시 텍스트 행을 비교하는 대신 csv.reader로 각 파일을 파싱하세요. CSV에서는 따옴표로 묶인 필드 안에 쉼표나 줄바꿈이 들어갈 수 있으므로, 물리적인 한 줄이 완전한 레코드라고 볼 수는 없습니다. 이 예제는 각 파일의 파싱된 행을 세고 한쪽에 더 많이 나타나는 행을 출력합니다. 자체 샘플 파일을 임시 디렉터리에 작성하므로 스크립트 옆에 별도 파일이 없어도 됩니다. 이 방법은 입력 크기에 비례하는 메모리를 사용합니다. 매우 큰 파일이라면 정렬된 스트리밍 비교나 데이터베이스 기반 작업 흐름을 고려하세요.

이 예제를 실행하세요:

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

import csv
import tempfile
from collections import Counter
from pathlib import Path

with tempfile.TemporaryDirectory() as directory:
    root = Path(directory)
    (root / "file1.csv").write_text("id,name\n1,Ada\n2,Lin\n", encoding="utf-8")
    (root / "file2.csv").write_text("id,name\n1,Ada\n3,Sam\n", encoding="utf-8")

    def read_rows(path):
        with path.open(newline="", encoding="utf-8") as source:
            return list(csv.reader(source))

    left = Counter(map(tuple, read_rows(root / "file1.csv")))
    right = Counter(map(tuple, read_rows(root / "file2.csv")))
    print("Only in file1:", list((left - right).elements()))
    print("Only in file2:", list((right - left).elements()))
Only in file1: [('2', 'Lin')]
Only in file2: [('3', 'Sam')]

제공된 실행 결과에서 이 예제는 오류 없이 종료되었고 위 출력을 출력했습니다. 이 비교에서는 헤더도 하나의 행으로 취급합니다. 데이터 레코드만 비교하려면 각 입력에서 파싱된 첫 번째 행을 제외하세요. Counter는 중복 횟수를 유지합니다. 한쪽에 어떤 행이 두 번 있고 다른 쪽에는 한 번 있다면, 그 행 한 건이 해당 쪽의 차이에 남습니다.

csv-diff로 키 기반 행 비교하기

레코드 수준의 변경을 확인하려면 두 파일 모두에 동일한 고유 키가 포함된 헤더를 사용하세요. 예를 들어 file1.csv에는 id,name 헤더와 1,Ada, 2,Lin 행을 넣고, file2.csv에는 id,name 헤더와 1,Ada Lovelace, 3,Sam 행을 넣을 수 있습니다. python3 -m pip install csv-diff로 패키지를 설치한 다음 csv-diff file1.csv file2.csv --key=id를 실행하세요. 두 헤더에 키가 있어야 하며, 키가 각 레코드를 일관되게 식별해야 합니다. 명령줄 인터페이스는 전체 행을 단순 비교하는 대신 추가되거나 삭제된 레코드와 일치하는 키의 변경된 값을 보고합니다. csv-diff 프로젝트 문서에는 명령 구문과 load_csv, compare를 포함한 Python API가 설명되어 있습니다. 이 외부 명령은 사용 안내이며 제공된 실행 증거로 검증된 것은 아닙니다.

pandas로 행 비교하기

pandas에서는 외부 병합을 사용해 한쪽에만 있는 전체 행을 찾을 수 있습니다. 헤더가 없는 파일을 읽을 때는 header=None를 사용하세요. 첫 번째 행에 열 이름이 있다면 기본 헤더 처리를 사용하면 됩니다. 키 기반 레코드 비교에서는 키 열로 병합한 뒤 나머지 열을 살펴 변경된 값을 확인하세요. _merge 표시는 병합된 각 행이 왼쪽 입력, 오른쪽 입력 또는 양쪽 모두에서 왔는지를 나타내며 행 인덱스를 뜻하지 않습니다. left_only와 right_only 표시는 각각 해당 입력에서 일치하는 행을 찾지 못한 경우를 가리킵니다.

pandas를 설치한 뒤 이 예제를 실행하세요:

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

try:
    import pandas as pd
except ImportError:
    pd = None

if pd is not None:
    import tempfile
    from pathlib import Path

    with tempfile.TemporaryDirectory() as directory:
        root = Path(directory)
        (root / "file1.csv").write_text("id,name\n1,Ada\n2,Lin\n", encoding="utf-8")
        (root / "file2.csv").write_text("id,name\n1,Ada\n3,Sam\n", encoding="utf-8")

        left = pd.read_csv(root / "file1.csv")
        right = pd.read_csv(root / "file2.csv")
        merged = left.merge(right, how="outer", indicator=True)
        print(merged.loc[merged["_merge"] != "both", ["id", "_merge"]])

이 예제는 의존 패키지를 사용하는 예제이며 제공된 실행 증거로 검증되지 않았으므로 관찰된 출력은 제시하지 않습니다. 병합은 공통된 id와 동일한 name 열을 사용해 완전히 일치하는 레코드를 찾고, _merge는 일치하지 않는 행이 어느 파일에 있는지 나타냅니다. 헤더가 없는 파일을 읽을 때는 두 입력 모두에 header=None를 전달하고 병합 전에 같은 열 이름을 지정하세요.

헤더, 중복, 행 순서 고려하기

헤더를 데이터로 볼지 메타데이터로 볼지 결정하세요. 비교 대상에 포함하려는 경우에만 헤더를 넣고, pandas에서 헤더가 없는 입력을 읽을 때는 header=None를 사용하세요. 두 파일의 헤더가 다르면 일치하는 열 이름을 지정하세요. 집합 비교는 중복 횟수를 무시하지만 Counter 예제 같은 다중집합 비교는 그 횟수를 유지합니다. 행 단위 비교에서는 순서가 중요합니다. 포함 여부 확인, 키 기반 매칭 또는 비교 전 정렬을 사용하면 순서를 무시할 수 있지만, 각 선택에 따라 ‘다르다’는 의미가 달라집니다. 키 기반 비교에서는 키 값이 중복되면 레코드 짝짓기가 모호해지므로 선택한 키가 고유한지 확인하거나 중복 처리 방식을 정하세요. 이런 차이를 고려하면 모든 차이를 같은 종류의 변경으로 취급하지 않고 데이터의 목적에 맞는 비교 방법을 선택할 수 있습니다.