Phase 7 · 회계 분석 및 시각화

회계사의 직관을 수치화하다, Python 이상거래/부정 탐지

40단계까지 정제된 회계 데이터베이스를 바탕으로, 이제부터는 회계사에게 가장 중요한 "어떤 거래를 우선적으로 검토(Audit)해야 하는가?"에 대한 답을 구합니다.
수만 건의 거래 데이터 속에서 고액, 심야, 중복 패턴 등 Rule 기반 탐지는 물론 Z-score, 벤포드의 법칙, 머신러닝을 활용하여 '검토 우선순위(Risk Score)'를 자동으로 산출하는 강력한 감사(Audit) 툴을 구축합니다.

예상 학습 시간 : 450분
난이도 : ★★★★★
사전 단계 : OCR + AI 회계 증빙 자동처리 (Step 40)
다음 단계 : 42단계 - 회계 데이터 시각화 및 재무 대시보드 (예정)
01

이상거래 ≠ 부정거래 (중요한 마인드셋)

프로그램이 "이것은 부정(Fraud)입니다!"라고 확정 짓는 것은 매우 위험합니다. 평균 거래가 100만 원인데 특정일 5,000만 원이 지출되었다면 이상거래(Anomaly)이긴 하지만, 장비 구입 등 정당한 사유가 있을 수 있습니다.

시스템의 목적: 검토 우선순위(Triage) 선정

우리가 만드는 파이썬 시스템의 역할은 "부정거래 확정"이 아니라, 회계사가 수만 건의 데이터 중 "가장 먼저 눈으로 확인하고 증빙을 대조해야 할 고위험 거래(검토 대상) 리스트를 추려주는 것"입니다.

02

Rule 기반 조건 탐지 (고액, 심야, 주말)

가장 직관적이고 강력한 방법입니다. 사전에 정의된 '의심스러운 조건'을 Pandas 필터링으로 걸러냅니다.

🐍 python
# 1. 특정 금액 이상 + 계정과목 필터링
condition = (df["amount"] >= 5_000_000) & (df["account"] == "접대비")
high_risk_rule = df[condition]

# 2. 심야(23시~06시) 및 주말 거래 탐지
df["hour"] = pd.to_datetime(df["transaction_date"]).dt.hour
df["weekday"] = pd.to_datetime(df["transaction_date"]).dt.weekday # 5:토, 6:일

night_weekend = df[(df["hour"] < 6) | (df["hour"] >= 23) | (df["weekday"] >= 5)]
03

중복 거래와 분할 거래 패턴 탐지

동일한 날짜, 거래처에 동일한 금액이 실수로 두 번 계상되었는지, 혹은 내부 규정을 피하기 위해 금액을 쪼개어 결제(분할 결제)했는지 찾습니다.

# 1. 완전 동일한 거래 찾기 (날짜, 거래처, 금액이 모두 같음)
duplicates = df[df.duplicated(subset=["transaction_date", "customer", "amount"], keep=False)]

# 2. 거래처별 특정 기간(7일) Rolling Sum (단기간 결제 집중 탐지)
df = df.sort_values("transaction_date")
df["rolling_sum_7d"] = df.groupby("customer")["amount"].rolling(7).sum().reset_index(level=0, drop=True)
04

통계적 이상치 (Z-score & IQR)

특정 거래처나 계정과목의 '평소 거래' 대비 과도하게 튀는 값을 찾습니다.

# 1. 계정과목 내 평소 대비 몇 배나 큰가?
account_mean = df.groupby("account")["amount"].transform("mean")
df["ratio_to_mean"] = df["amount"] / account_mean  # 예: 10배 이상이면 의심

# 2. Z-score (표준편차 이용)
mean, std = df["amount"].mean(), df["amount"].std()
df["z_score"] = (df["amount"] - mean) / std
outlier_z = df[df["z_score"].abs() > 3] # |Z| > 3 이면 통계적으로 드문 값

# 3. IQR (사분위수 범위 이용 - 비정규 분포인 회계데이터에 더 적합)
Q1 = df["amount"].quantile(0.25)
Q3 = df["amount"].quantile(0.75)
IQR = Q3 - Q1
outlier_iqr = df[df["amount"] > (Q3 + 1.5 * IQR)]
05

감사의 클래식: 벤포드의 법칙 (Benford's Law)

자연적으로 발생한 숫자들의 첫 번째 자리는 1이 약 30%, 9가 약 5%로 균등하지 않게 나타난다는 통계적 성질입니다. 장부를 조작해 임의로 숫자를 지어내면 이 분포가 깨지게 됩니다.

# 금액에서 첫 번째 숫자(1~9)만 추출
df["first_digit"] = df["amount"].astype(str).str.replace(r"\D", "", regex=True).str[0]

# 빈도 분포 확인
distribution = df["first_digit"].value_counts(normalize=True).sort_index()
# -> 이 분포가 이론적 수치(1: 30.1%, 2: 17.6%...)와 현저히 다르면 인위적 조작 의심!

단, 급여나 정액 임차료처럼 인위적으로 고정된 금액 데이터에는 맞지 않으므로 추가 검토를 위한 힌트로만 사용합니다.

06

비지도학습(ML) 기반 이상탐지: Isolation Forest

규칙(Rule)으로 다 걸러낼 수 없는 다차원적인 복합 패턴(예: 금액은 크지 않으나, 특정 요일에 낯선 거래처와 거래 등)은 머신러닝 알고리즘에 맡깁니다.

from sklearn.ensemble import IsolationForest

# Feature: 거래금액, 요일, 시간대 등
features = df[["amount", "weekday", "hour"]] 

# 전체 데이터의 1% 정도를 이상치로 간주하도록 모델 설정
model = IsolationForest(contamination=0.01, random_state=42)
df["anomaly_ml"] = model.fit_predict(features)  # -1 반환 시 이상치로 판별
07

종합 위험점수(Risk Score) 모델 구축

위의 모든 탐지 기법들을 하나의 '점수(Max 100점)'로 합산하여 HIGH / MEDIUM / LOW 등급을 부여합니다.

df["risk_score"] = 0
df["risk_reason"] = ""

# 조건별 점수 가산
df.loc[df["amount"] >= 10_000_000, ["risk_score", "risk_reason"]] += [30, "고액거래; "]
df.loc[df["ratio_to_mean"] >= 10, ["risk_score", "risk_reason"]] += [20, "평균대비 10배 초과; "]
df.loc[df["anomaly_ml"] == -1, ["risk_score", "risk_reason"]] += [20, "ML이상치 탐지; "]
df.loc[df["hour"] < 6, ["risk_score", "risk_reason"]] += [10, "심야거래; "]

# 위험 등급 판정
def set_risk_level(score):
    if score >= 70: return "HIGH"
    elif score >= 40: return "MEDIUM"
    return "LOW"

df["risk_level"] = df["risk_score"].apply(set_risk_level)
08

AI 종합 요약 및 검토대상 선정

최종적으로 `HIGH` 등급을 받은 거래 내역과 `risk_reason`(위험 사유) 데이터를 AI(LLM)에게 전달하여 회계사가 읽기 좋은 자연어 보고서를 작성하게 합니다.

AI 어시스턴트의 최종 출력 예시

[우선 검토 권고]
XYZ 거래처에서 15,000,000원의 거래가 발생했습니다. (위험점수: 80점)
해당 거래는 평소 평균 거래금액 대비 14.2배 높으며(20점), 동일한 날짜와 금액의 거래가 중복으로 확인(30점)되어 우선적인 원본 증빙(세금계산서) 대조가 필요합니다.

이렇게 만들어진 `HIGH / MEDIUM / LOW` 결과셋을 39단계에서 배운 xlsxwriter를 활용하여 다중 시트가 포함된 `audit_risk_report.xlsx` 파일로 자동 생성해 내면 이번 단계가 완성됩니다.

09

42단계 예고: 데이터 시각화와 재무 대시보드

이제 우리는 완벽하게 정제되고 필터링된 회계 데이터를 손에 쥐었습니다.

다음 42단계에서는 숫자만 가득한 엑셀과 터미널 창을 벗어나, Pandas와 시각화 라이브러리(Matplotlib, Plotly)를 활용하여 화려하고 직관적인 '회계/재무 시각화 대시보드'를 그려보겠습니다.

Step 40 : 증빙 자동처리 파이프라인 Phase 7 공사중