Data Cleaning Horror Stories: Lessons from 10 Years of Messy CSVs

March 2026 · 19 min read · 4,565 words · Last Updated: March 31, 2026Advanced
# 데이터 클리닝 공포 이야기: 10년 간의 지저분한 CSV에서 배운 교훈 2019년 제가 함께 일했던 한 통신사에서 CSV 헤더의 단일 보이지 않는 유니코드 문자로 인해 $340K의 청구 오류가 발생했습니다. 파일은 Excel, Notepad++, VS Code에서 완벽해 보였으며, 터미널에서 `cat`을 통해 파이프 처리할 때도 마찬가지였습니다. 모든 시각적 검사는 깨끗하고 적절하게 포맷된 열 이름을 보여 주었습니다. 그러나 청구 시스템은 계속해서 "customer_id" 필드를 거부하며 존재하지 않는다고 주장했습니다. 3주. 그것이 문제를 찾기 위해 5명의 엔지니어, 2명의 데이터 분석가, 그리고 한 명의 매우 스트레스 받는 프로젝트 관리자가 걸린 시간입니다. 우리는 가져오기 스크립트를 다시 작성하고, 데이터베이스 스키마를 의심하며, 심지어 ETL 파이프라인의 버그를 의심하기도 했습니다. 답은? "customer"와 "_id" 사이에 보이지 않게 위치한 제로 너비 비연결자(U+200C) 문자였습니다. 헤더는 "customer_id"가 아닌 "customer‌_id"였습니다. 사람의 눈에 보기에는 동일하지만, 모든 컴퓨터 시스템에는 완전히 다른 필드입니다. 이 사건은 회사에 지연된 청구 주기, 긴급 계약자 시간 및 지연 청구서에 대한 고객 크레딧으로 $340K를 비용으로 초래했습니다. 또한 저의 경력에서 가장 중요한 교훈을 주었습니다: CSV 파일은 단순하지 않습니다. 그것들은 스프레드시트로 위장한 지뢰밭이며, 모든 데이터 엔지니어는 이를 진지하게 다룰 필요가 있습니다. 지난 10년간 금융, 의료, 소매 및 통신 분야의 Fortune 500 회사를 위해 데이터 세트를 정리해왔습니다. 환자 기록을 손상시키는 인코딩 악몽, 재무 조정을 깨뜨리는 유령 화이트스페이스, 미래의 데이터 엔지니어를 진심으로 미워하는 사람에 의해 설계된 것만 같은 창의적인 날짜 포맷을 보았습니다. 이 글은 여러분이 같은 고통을 겪지 않도록 하기 위한 제 시도입니다.

인코딩 대재앙: UTF-8이 아닌 경우

제가 목격한 최악의 데이터 재앙은 2017년에 다국적 소매 체인에서 발생했습니다. 그들은 12개국의 47개 지역 데이터베이스에서 고객 데이터를 단일 데이터 웨어하우스로 통합하고 있었습니다. 간단해 보이죠? CSV로 내보내고, 웨어하우스에 가져오고, 중복 제거 로직을 실행하면 끝입니다. 하지만 프랑스 지부의 CSV는 계속해서 이름을 손상시켰습니다. "François"는 "François"가 되었고, "Chloé"는 "Chloé"가 되었습니다. 독일 지부도 움라우트와 함께 유사한 문제를 겪었습니다. 일본 지부의 데이터는 완전히 읽을 수 없었으며—질문 부호와 대체 문자의 행이었습니다. 근본적인 원인은 무엇이었을까요? 모든 지역 팀이 서로 다른 인코딩을 사용하여 CSV를 내보냈습니다. 프랑스는 ISO-8859-1 (Latin-1)을 사용했고, 독일은 Windows-1252를 사용했습니다. 일본은 Shift-JIS를 사용했습니다. 영국과 미국 팀은 UTF-8을 사용했지만, 일부는 BOM (바이트 순서 마크)이 있는 UTF-8을, 다른 일부는 BOM이 없는 UTF-8을 사용했습니다. 스페인 팀의 한 팀은 어떻게든 UTF-16LE로 데이터를 내보냈습니다. 원래 3개월 동안 계획된 통합 프로젝트는 11개월이 걸렸습니다. 우리는 다음과 같은 사용자 정의 인코딩 감지 파이프라인을 구축해야 했습니다: 1. 여러 라이브러리(chardet, charset-normalizer와 사용자 정의 휴리스틱)를 사용하여 인코딩을 감지하려 시도 2. 각 언어의 공통 문자 패턴을 확인하여 감지를 검증 3. 모든 것을 BOM 없는 UTF-8로 변환 4. 수동 검토를 위해 신뢰도 점수와 함께 모든 변환 기록 이 파이프라인에도 불구하고 3%의 오류율이 있었고 이는 수동 수정이 필요했습니다. 4700만 고객 기록의 3%—140만 개의 이름이 사람의 검토가 필요했습니다. 교훈은? CSV의 인코딩을 절대 믿지 말라. 절대. 누군가 "확실히 UTF-8이다"고 말하더라도 확인하십시오. 메타데이터에서 UTF-8이라고 주장하였지만 실제로는 Windows-1252의 고급 ASCII 문자가 포함된 파일을 보았습니다. 누군가 구형 시스템에서 복사-붙여넣기를 했던 ISO-8859-1 청크가 포함된 UTF-8 파일도 보았습니다. 수출 스크립트가 충돌하여 다른 로케일 설정으로 다시 시작되면서 도중에 인코딩이 변경된 파일도 보았습니다. 이제 제 책상에서 건너오는 모든 CSV는 제가 데이터를 보기 전 인코딩 검증 스크립트를 통해 실행됩니다. 덕분에 수많은 시간을 절약하고 적어도 12건의 주요 사건을 예방했습니다.

거기 없던 화이트스페이스 (있긴 했지만)

2018년, 6개월 동안 실패한 재무 조정 시스템을 수정하기 위해 불려갔습니다. 그 회사는 수십억 달러의 거래를 처리하는 결제 프로세서였습니다. 그들의 조정 프로세스는 데이터베이스의 거래 기록과 은행 파트너의 CSV 보고서를 비교했습니다. 시스템은 매일 수천 개의 불일치를 보고했습니다—은행 보고서에는 나타났지만 데이터베이스에는 없는 거래, 반대의 경우도 마찬가지였습니다. 재무 팀은 이러한 불일치를 수동으로 조정하며 60시간씩 일하며 따라잡고 있었습니다. 그들은 각 플래그가 있는 거래를 확인하고 실제로 두 시스템 모두에 존재한다는 것을 발견했습니다. 거래 ID는 완벽하게 일치했습니다. 그러나 자동 시스템은 계속해서 이를 불일치로 표시했습니다. 저는 코드를 분석하고, 데이터베이스 쿼리 및 CSV 파싱 로직을 2일 동안 살펴보았습니다. 모든 것이 올바르게 보였습니다. 그러다 제가 처음부터 너무 당연했어야 할 것을 했습니다: CSV를 헥스 에디터에서 열었습니다. 거기에 있었습니다. 은행의 CSV 파일에 있는 모든 거래 ID는 후행 공백을 가지고 있었습니다. Excel에서는 보이지 않았고, 대부분의 텍스트 편집기에서도 보이지 않았습니다. 하지만 헥스 덤프에는: `54 52 41 4E 53 31 32 33 34 35 20` 대신 `54 52 41 4E 53 31 32 33 34 35`가 있었습니다. 마지막 `20`은 공백 문자였습니다. 데이터베이스는 후행 공백 없이 거래 ID를 저장했습니다. 비교 로직은 정확한 문자열 일치를 수행하고 있었습니다. "TRANS12345" ≠ "TRANS12345 ". 수천 건의 거짓 불일치와 수백 시간의 낭비는 모두 단 하나의 후행 공백 문자 때문이었습니다. 하지만 상황은 더 나빠집니다: 후행 공백이 일관되지 않았습니다. 일부 거래 ID는 공백을 가졌고, 일부는 없었습니다. 일부는 후행 공백이 있었고, 일부는 선행 공백이 있었으며, 일부는 둘 다 있었습니다. 몇몇은 공백 대신 탭을 사용했습니다. 기억에 남는 한 파일에는 공백, 탭, 비주얼 스페이스(U+00A0)의 혼합이 있었습니다. 해결책은 간단했습니다—가져오는 동안 모든 화이트스페이스를 제거했습니다. 그러나 교훈은 심오했습니다: CSV의 화이트스페이스는 결코 우연이 아니며 항상 문제를 일으키고 빈번하게 보이지 않습니다. 이제 저에게는 규칙이 있습니다: 모든 문자열 필드는 가져오는 동안 잘라냅니다, 예외는 없습니다. 비즈니스 로직이 필드가 화이트스페이스를 유지해야 한다고 말해도 상관없습니다. 누군가 데이터가 깨끗하다고 주장해도 상관없습니다. 모든 것을 잘라냅니다. 저는 또한 다른 보이지 않는 문자를 경계하는 법을 배웠습니다: 제로 너비 공백(U+200B), 제로 너비 비연결자(U+200C), 제로 너비 연결자(U+200D), 그리고 때때로 파일 중간에 나타나는 악명 높은 바이트 순서 마크(U+FEFF). 이러한 문자는 기계의 유령이며, 인간에게는 보이지 않지만 컴퓨터에게는 매우 현실적입니다.

국제 상업을 망친 날짜 형식

제가 만나본 날짜 형식 중 가장 저주받고 근본적으로broken, 그로 인해 여전히 저의 꿈을 괴롭히는에 대해 말씀드리겠습니다. 물류 회사에서 아시아의 제조업체와 북미 및 유럽의 소매업체 간의 운송을 조정하는 업무를 했었습니다. 시스템은 이렇게 작동했습니다: 제조업체들은 픽업 날짜, 예상 배송 날짜 및 세관 통관 날짜를 포함한 배송 세부 정보를 담은 CSV 파일을 업로드했습니다. 시스템은 이러한 날짜를 파싱하고 전환 시간을 계산하며, 배송 회사 및 세관 중개인과 조정했습니다. 수년간 모든 것이 잘 작동했습니다. 그리고 2016년 3월, 시스템은 과거 날짜에 배송 일정을 잡기 시작했습니다. 2016년 3월 15일에 픽업해야 할 컨테이너가 1916년 3월 15일로 일정이 잡히고 있었습니다. 세관 서류가 컨테이너 운송의 발명 전에 해당하는 날짜에 제출되고 있었습니다. 근본적인 원인은? Excel의 자동 날짜 형식 지정이 지역 날짜 형식의 차이와 결합되었고, 날짜 작동 방식에 대한 정말로 놀라운 오해가 있었습니다. 무슨 일이 벌어지고 있었는지: 1. 중국의 제조업체가 "3/15/2016" (MM/DD/YYYY 형식의 2016년 3월 15일)과 같은 날짜를 입력 2. Excel은 이를 날짜로 해석하고 내부적으로 일련 번호(2016년 3월 15일에 대해 42444)로 저장합니다. 3. CSV로 내보내지면, Excel은 시스템 로케일에 따라 형식을 지정합니다. 4. 중국의 시스템 로케일은 YYYY-MM-DD 형식을 사용하여 "2016-03-15"로 내보냅니다. 5. 우리의 가져오기 시스템은 MM/DD/YYYY 형식에 맞게 구성되어 있으므로 "2016-03-15"를 "2016/03/15"(2016년 3월의 15일)로 파싱합니다. 6. 2016년은 유효하지 않은 월이므로, 파서가 "20/16/03/15"로 해석하게 됩니다. 7. 점점 더 절망적인 파싱 시도를 통해 결국 "03/15/1916"으로 정착하게 됩니다. 하지만 기다리세요, 상황이 더 악화됩니다. 일부 제조업체는 DD/MM/YYYY 형식을 사용하고 있었고, 일부는 YYYY-MM-DD를, 어떤 제조업체는 MM/DD/YY(2자리 연도 형식)를 사용하고 있었습니다. 대만에 있는 한 제조업체는 민국 달력을 사용하고 있었는데, 여기서 105년은 2016년 CE(1912 + 105)에 해당합니다. 우리는 1916년부터 2116년까지의 날짜를 갖게 되었고, 특히 1970년(유닉스 에포크) 주변에 밀집된 클러스터가 있었습니다. 왜냐하면 일부 시스템은 날짜를 유닉스 타임스탬프로 내보내고, 우리의 파서가 이를 YYYYMMDD 형식으로 해석하고 있었기 때문입니다. 해결책은 다음을 요구했습니다: - 형식을 감지하기 위해 다중 전략 날짜 파서를 구현 - 유효성 검사 규칙 추가 (2000년 이전 또는 2050년 이후 날짜 거부) - 제조업체가 ISO 8601 형식(YYYY-MM-DD)을 독점적으로 사용하도록 요구 - 가져오기 전에 구문 분석된 날짜를 미리 볼 수 있도록 CSV 업로드를 위한 웹 인터페이스 구축 - 모든 상상 가능한 형식의 날짜를 포함한 포괄적인 테스트 스위트 생성 이 모든 안전 장치에도 불구하고 우리는 여전히 간혹 날짜 파싱 오류가 발생합니다. 지난 달에도 누군가 "2/29/2023" (2023년 2월 29일—2023년은 윤년이 아니기 때문에 존재하지 않는 날짜)를 입력한 CSV를 만났습니다. Excel은 이를 문제 없이 받아들이고, 일련 번호 45000으로 저장했으며 "2023-02-29"로 내보냈습니다. 우리의 시스템은 이를 가져와서 올바른 형식임을 검증하고 존재하지 않는 날짜에 대한 출하를 일정으로 잡았습니다.
"날짜와 관련된 문제는 모든 사람 다 이해하고 있다고 생각하지만 실제로는 아무도 이해하지 못한다는 것입니다. 날짜는 문화적 구성물이지 수학적이지 않습니다. 날짜는 시간대, 서머타임, 윤년, 윤초, 달력 개혁이 있습니다. 각기 다른 국가에서 다른 형식을 가지고 있으며, 서로 다른 시대에서 다른 시작점을 가지며, 서로 다른 맥락에서 서로 다른 의미를 가집니다. CSV 파일은 메타데이터가 전혀 없기 때문에 어느 해석이 맞는지 알 방법이 없습니다."
이 동료의 인용은 날짜 문제를 완벽하게 포착하고 있습니다. CSV는 데이터 유형이 없습니다. 스키마가 없습니다. 그냥 텍스트일 뿐입니다. CSV에서 "01/02/03"을 보았을 때, 그것은 2003년 1월 2일입니까? 2003년 2월 1일입니까? 2001년 3월 2일입니까? 2001년 2월 3일입니까? 맥락 없이는 알 수 없으며, 바로 그 맥락이 CSV가 제공하지 않는 것입니다.

숫자이지 않은 숫자들

제가 경험한 가장 일반적인 수치 데이터 문제의 표입니다. 각 문제 유형과 그 빈도 및 전형적인 영향을 포함하고 있습니다:
문제 유형 빈도 전형적인 영향 예시
천 단위 구분자 매우 높음 (60%) 수입 실패, 유형 오류 "1,234.56"가 문자열로 파싱됨
통화 기호 높음 (45%) 수입 실패, 계산 오류 "$1,234.56" 또는 "€1.234,56"
소수점 구분자 차이 높음 (40%) 치명적인 계산 오류 "1.234,56" (유럽식)과 "1,234.56" (미국식)
과학적 표기법 중간 (25%) 정밀도 손실, 오해 "1.23E+05" 또는 "1.23456789E-10"
선행 제로 중간 (30%) 데이터 손실, ID 손상 "00123"이 "123"으로 바뀜
백분율 기호 중간 (20%) 100배 계산 오류 "15%"가 0.15가 아닌 15로 저장됨
음수 숫자 형식 낮음 (15%) 기호 손실, 잘못된 계산 "(123"는 ...
C

Written by the CSV-X Team

Our editorial team specializes in data analysis and spreadsheet management. We research, test, and write in-depth guides to help you work smarter with the right tools.

Share This Article

Twitter LinkedIn Reddit HN

Put this into practice

Try Our Free Tools →

📬 Stay Updated

Get notified about new tools and features. No spam.