LabHub
배우기 러닝패스 코스

顧客データを扱う

検証器は緑なのに数字がおかしい

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

칼럼별 프로파일과 전달분 사이의 분포 변화, 그리고 첫 자리 숫자 분포로 형식은 맞는데 값이 이상한 자료를 찾아내는 도구 profile.py 를 만든다. 벤포드가 통하지 않는 칼럼을 반례로 넣어, 이것이 증거가 아니라 단서임을 코드가 스스로 말하게 한다.

왜 중요한가

스키마도 맞고 결측도 규칙대로인데 숫자가 이상한 일이 있다. 이때 "이상합니다" 만으로는 아무도 움직이지 않는다. 근거가 필요하고, 그 근거는 값 하나가 아니라 분포다. 프로파일 하나만으로는 판단이 어렵다. 이상은 절대적인 값이 아니라 지난 전달분과의 차이로 드러나기 때문이다. 그래서 프로파일은 전달분마다 남겨 두고 견주며, 문턱값을 코드에 적어 둔다 — 적어 두지 않은 문턱값은 다음 사람이 고칠 수 없다. 첫 자리 숫자 분포는 값싸고 잘 듣는 신호이지만 가장 오해받는 신호이기도 하다. 분포가 어긋났다는 것은 사람이 봐야 한다는 뜻이지 누가 조작했다는 뜻이 아니고, 값 범위가 좁은 칼럼에서는 정직한 자료도 늘 어긋난다. 그래서 적용 가능성을 먼저 판정해야 한다. 채점기는 여러분의 문구를 믿지 않는다. 임시 디렉터리에 채점기가 만든 전달분을 차려 놓고 여러분의 도구를 실제로 실행해 프로파일과 판정을 채점기가 직접 계산한 값과 대조한다. 거래처와 금액은 실행마다 바뀐다.

단계

  1. /root/prof/gen_feed.py 를 만들어 실행해 /root/prof/feed 아래 2026-04.csv·2026-05.csv·2026-06.csv 를 만드세요. 셋 다 형식 검증은 통과합니다.
  2. /root/prof/profile.pyprofile <파일> 을 만들어 칼럼마다 타입·결측·고유 비율·값 길이·최빈값·범위를 내게 하세요.
  3. digits <파일> <칼럼> 을 더해 값 길이 분포와 최빈 길이에서 벗어난 값을 내게 하세요.
  4. drift <파일A> <파일B> 를 더해 전달분 사이의 분포 변화를 문턱값으로 판정하게 하세요.
  5. benford <파일> <칼럼> 을 더해 첫 자리 숫자 분포와 기대 분포의 차이를 내게 하고, 두 전달분을 비교해 /root/prof/benford.json 에 적으세요.
  6. benford 에 적용 가능성 판정을 더해, 값 범위가 좁은 칼럼에 applicable 을 false 로 하고 verdict 를 not_applicable 로 하세요. 결과는 /root/prof/narrow.json 에 적습니다.
  7. 여러 신호를 겹쳐 조사 대상 목록을 만들고 칼럼마다 다음에 확인할 것을 /root/prof/leads.json 에 적으세요.
  8. 전체를 한 장으로 정리해 /root/prof/prof_report.json/root/prof/prof_report.md 를 만드세요.

참고

세 달치 전달분 만들기

/root/prof/gen_feed.py 를 만들어 실행해 /root/prof/feed 아래 2026-04.csv·2026-05.csv·2026-06.csv 를 만드세요. 두 달은 평범하고 한 달은 형식은 맞는데 값이 이상합니다.

금액은 자릿수가 고르게 퍼지도록 만드세요 — 지수를 균등하게 뽑아 10의 거듭제곱으로 만들면 첫 자리 분포가 자연스러워집니다. 손댄 달에는 사람이 적어 넣은 듯한 금액 몇 가지를 섞고, 거래처가 비는 줄과 전화번호 자릿수가 다른 줄을 함께 넣으세요. 표준 라이브러리 난수 대신 고정 씨앗 생성기를 쓰면 누가 돌려도 같은 파일이 나옵니다.

칼럼마다 자기 소개를 시키기

/root/prof/profile.pyprofile <파일> 을 만들어 rows 와 columns 를 내게 하세요. 칼럼마다 type·nulls·null_rate·distinct·unique_ratio·len_min·len_max·modal_length·top 을 담고, 숫자 칼럼에는 min·max 를 더합니다.

비율의 분모는 전체 행 수이고, 길이와 고유값은 없음을 뺀 값들로만 셉니다. top 은 건수 내림차순이되 건수가 같으면 값의 사전 순으로 정해야 실행마다 같은 답이 나옵니다.

값 길이에서 벗어난 것 꺼내 보기

digits <파일> <칼럼> 을 더해 lengths·modal_length·outliers·sample_outliers 를 내게 하세요. sample_outliers 는 서로 다른 값을 정렬해 앞 3개입니다.

형식 검사를 통과하는 값이라도 길이가 다르면 만든 쪽이 달라진 것입니다. 벗어난 값을 몇 개 직접 꺼내 보면 원인이 대개 바로 보입니다 — 전화번호라면 지역번호가 빠졌거나 하이픈이 사라진 것입니다.

지난 전달분과 견주기

drift <파일A> <파일B> 를 더해 칼럼마다 네 가지 변화를 재고 문턱값을 넘은 것을 flags 에 담게 하세요. 응답에는 flags 가 하나라도 있는 칼럼 목록 flagged 도 넣습니다.

이상은 절대값이 아니라 차이로 드러납니다. 결측 비율 0.05, 고유 비율 0.20, 최빈값 점유율 0.10, 그리고 최빈 길이가 달라졌는지를 봅니다. 문턱값을 상수로 빼 두면 나중에 자료가 달라졌을 때 고칠 자리가 한 곳입니다.

첫 자리 숫자 분포 재기

benford <파일> <칼럼> 을 더해 observed·expected·max_deviation·deviation_digit·verdict 를 내게 하고, 평범한 달과 손댄 달의 amount 결과를 /root/prof/benford.json 에 normal·suspect 로 적으세요.

기대 비율은 자릿수 d 에 대해 log10(1 + 1/d) 입니다. 첫 자리는 부호와 앞쪽 0 과 소수점을 건너뛰고 처음 만나는 0 이 아닌 숫자이고, 값이 0 이면 세지 않습니다. 사람이 손으로 지어낸 금액은 특정 자릿수에 몰리므로 차이가 크게 벌어집니다.

벤포드가 통하지 않는 칼럼

benfordspanapplicable 을 더해, 건수가 200 미만이거나 최대/최소 비율이 100 미만이면 적용 불가로 보고 verdict 를 not_applicable 로 하세요. score 칼럼 결과를 /root/prof/narrow.json 에 column·n·span·applicable·verdict·why 로 적으세요.

값이 좁은 구간에만 있으면 첫 자리가 몇 가지로 제한되어 정직한 자료도 기대 분포와 크게 어긋납니다. 적용 가능성 판정 없이 돌린 벤포드는 멀쩡한 자료를 계속 신고하고, 그러면 아무도 그 신고를 읽지 않게 됩니다. why 에는 왜 적용할 수 없는지를 한두 문장으로 적으세요.

신호를 겹쳐 조사 대상 만들기

분포 변화와 벤포드 결과를 겹쳐 /root/prof/leads.json 에 leads·not_leads·note 를 적으세요. leads 의 각 항목은 column·signals·next_check 를 담고, not_leads 에는 벤포드를 적용할 수 없는 칼럼을 적습니다.

하나만 걸린 칼럼과 셋이 걸린 칼럼은 다르게 다뤄야 합니다. next_check 는 '이상하다' 가 아니라 '다음으로 무엇을 확인한다' 여야 합니다 — 손으로 적은 듯한 금액이 어느 담당자에게 몰려 있는지, 자릿수가 바뀐 전화번호가 어느 시스템에서 왔는지 같은 것입니다.

단서를 한 장으로 넘기기

/root/prof/prof_report.json 에 baseline·target·rows·flagged·benford·not_applicable·leads 를 적고, /root/prof/prof_report.md## 무엇을 봤나 ## 지난 전달분과 무엇이 달라졌나 ## 첫 자리 숫자가 말해 주는 것 ## 무엇을 더 확인해야 하나 네 절로 쓰세요.

benford 는 amount 칼럼의 column·max_deviation·verdict 를 담은 객체입니다. 보고서의 셋째 절에는 벤포드 결과와 함께 그것이 왜 증거가 아닌지를 반드시 적고, 넷째 절에는 칼럼마다 다음에 확인할 것을 적으세요. 앞 단계에서 남긴 파일들을 읽어 합치면 됩니다.