# CORD-v2 100장 벤치마크 — 원자료 공개

이 폴더는 `/benchmark` 페이지에 실린 CORD-v2 100장 측정치의 근거 자료입니다.
표본 목록·채점 방법·감점 내역 원자료를 그대로 공개합니다.

## ① 이 폴더는 무엇인가

- **측정일**: 2026-09-04 (CORD-v2 100장 실행 — 공개 페이지 표기와 동일. 결과 폴더명의
  09-05는 작업 폴더 생성 기준). 아래 "⑥ 정밀도 66.8%의 내역"에 실린 감점 세부
  재검토는 2026-09-06에 진행했습니다.
- **출처 데이터셋**: NAVER CLOVA **CORD-v2** (`naver-clova-ix/cord-v2`) test 분할.
  라이선스 **CC BY 4.0**.
- **데이터셋 원본(영수증 이미지)은 이 폴더에 재공개하지 않습니다.** CORD-v2는
  공개 데이터셋이라 원본은 출처에서 직접 받으실 수 있고, 여기서는 우리가 어떤
  표본을 어떤 순서로 썼는지 확인할 수 있도록 **표본 색인(sample_list.csv)만**
  공개합니다.

## ② 표본 선정 규칙

- CORD-v2의 **test 분할**에서 **앞 100장을 순서 그대로**(idx 0~99) 사용했습니다.
- 임의로 뺀 표본은 없습니다 — 판독이 어려웠던 장(흐림 2장)과 영수증이 아닌
  설문지 1장도 100장 안에 그대로 포함해 채점했습니다(각 장의 사정은
  `sample_list.csv`의 note 열에 표시).
- 순서를 고정했기 때문에 같은 방식으로 재현하면 같은 100장이 나옵니다.

## ③ 실행 조건

- 저희 서비스가 실제로 쓰는 판독 파이프라인을 **그대로** 이번 측정에 사용했습니다.
  이 측정을 위해 별도로 조정하거나 학습시킨 부분은 없습니다.
- 내부 처리 단계(처리 단계 구성·설정값 등)의 구체적인 내용은 이 문서를 포함해
  어떤 공개 자료에도 밝히지 않습니다 — 여기서 공개하는 것은 "무엇을 얼마나
  회수했는가"라는 결과와 채점 방식이며, "어떻게 처리하는가"는 비공개입니다.

## ④ 채점 정의 (자체 채점 — 공식 CORD 채점과 다른 기준입니다)

CORD-v2의 정답 파일(`ground_truth`의 `gt_parse`)에는 표 셀 같은 자리 정보 없이
**값들이 계층 구조로만** 들어 있습니다. 그래서 "칸 위치가 맞았는가"가 아니라
**"정답 값을 우리 결과 어딘가에서 회수했는가"**로 채점했습니다.

1. **정답 값 펼치기(flatten)**: `gt_parse`를 재귀적으로 훑어 문자열 값만 전부
   모읍니다(빈 문자열·공백만 있는 값은 제외). 예를 들어
   `{"menu": [{"nm": "아메리카노", "price": "4,500"}]}`이면 정답 값 목록은
   `["아메리카노", "4,500"]`이 됩니다.
2. **정규화(normalize)**: 비교 전에 값을 다음 규칙으로 다듬습니다 —
   공백·쉼표 제거, 영문 대소문자 통일(소문자화). 숫자가 섞인 값은 **숫자만
   추출해서** 비교합니다(예: `"4,500원"`과 `"4500"`은 숫자만 비교하면 같은
   값으로 봅니다 — 통화 단위·쉼표 표기 차이를 실제 오류로 세지 않기 위함).
3. **재현율(recall) 판정**: 정답 값 하나하나에 대해, 그 값이 우리 결과(표
   셀 값 + 본문 문단 값)의 숫자열 또는 정규화된 문자열 어딘가에 **포함**되어
   있으면 "회수됨"으로 셉니다. 예: 정답이 `"4500"`이고 우리 결과에
   `"4,500원"`이 있으면 숫자만 비교해 일치 → 회수. **재현율 = 회수된 정답 값
   수 ÷ 전체 정답 값 수.**
4. **정밀도(precision) 판정**: 반대 방향 — 우리가 낸 값 하나하나에 대해, 그
   값이 정답 값들의 숫자열 또는 문자열 어딘가에 포함되어 있으면 "근거 있음"으로
   셉니다. **정밀도 = 근거 있는 우리 값 수 ÷ 우리가 낸 전체 값 수.**
5. **F1**: 재현율과 정밀도의 조화평균 `2·R·P / (R+P)`.
6. **문서별 평균(macro) vs 전체 합산(pooled/micro)**: `/benchmark`에 실린
   정밀도 **66.8%**는 100장 각각의 정밀도를 구한 뒤 **100장 평균을 낸 값**
   (macro-average, `scores.csv`의 precision 열 평균)입니다. 반면
   `breakdown_summary.json`의 `measured_precision_pooled` **68.9%**는 100장의
   모든 값(1,660개)을 한데 모아 "근거 있는 값 수 ÷ 전체 값 수"로 한 번에 계산한
   값(pooled/micro-average)입니다. 문서마다 값 개수가 다르기 때문에 두 계산
   방식의 결과가 소폭 다릅니다 — **둘 다 정확한 계산이며, 계산 단위(문서 단위
   평균이냐 값 단위 합산이냐)가 다를 뿐**입니다. `/benchmark`는 macro(66.8%)를
   대표값으로 씁니다.

## ⑤ 정답(ground truth) 포맷 설명

CORD-v2 정답(`gt_parse`)에는 아래 종류의 값만 들어 있습니다 — 예를 들어
영수증 상단의 상호명·주소나 하단의 안내 문구 같은 것은 **정답에 포함되지
않습니다.**

- `menu` (품목별): `nm`(품목명), `cnt`(수량), `price`(가격), `unitprice`(단가),
  `discountprice`(할인가), `num`(번호), `sub_*`(하위 항목) 등
- `sub_total` (소계 영역): `subtotal_price`(소계), `discount_price`(할인),
  `service_price`(봉사료), `tax_price`(세금), `etc_price`(기타)
- `total` (합계 영역): `total_price`(합계), `cashprice`(현금 결제액),
  `changeprice`(거스름돈), `creditcardprice`(카드 결제액),
  `emoneyprice`(전자화폐 결제액), `menuqty_cnt`(품목 총수량),
  `menutype_cnt`(품목 종류 수)

> **정리하면: 상호·주소·전화번호·발행 안내 문구 같은 "표 밖" 정보는 정답에
> 없습니다.** 우리 서비스는 문서 전체(표+본문)를 복원하는 것이 목표이기
> 때문에, 정답에 없는 값도 결과에 담아 정밀도 계산에서는 "근거 없음"으로
> 잡히는 경우가 많습니다 — 아래 ⑥에서 그 실제 비중을 공개합니다.

## ⑥ 정밀도 66.8%의 내역 — 감점(FP, false positive) 분류

우리가 낸 1,660개 값 중 1,144개는 정답에 근거가 있었고(TP), **516개(31.1%)는
근거를 찾지 못했습니다(FP)**. 이 516개가 왜 "근거 없음"으로 잡혔는지 아래
7가지 규칙으로 분류했습니다(우선순위 순서대로 적용 — 하나에 걸리면 그 칸에
분류하고 다음 규칙은 보지 않습니다).

| 분류 | 건수 | 설명 |
|---|---|---|
| 범위밖_열제목라벨 | 255 | 표의 열 제목(헤더) 글자 — 정답은 값만 담고 열 제목은 담지 않아 구조적으로 "근거 없음"이 됩니다. |
| 범위밖_머리말꼬리말 | 32 | 영수증 상단 상호·주소·전화번호, 하단 안내 문구 등 — ⑤에서 설명한 "정답 범위 밖" 정보입니다. |
| 범위밖_결제요약값 | 7 | 결제 요약 영역의 숫자값인데 정답 스키마의 대응 필드가 없어 근거를 못 찾은 경우입니다. |
| 분할차이_병합 | 18 | 정답은 여러 값으로 나눠 담았는데 우리는 한 칸에 합쳐 담아, 정답과 문자 그대로는 안 겹친 경우입니다. |
| 분할차이_쪼갬 | 0 | (반대 경우 — 이번 100장에서는 발생 0건) |
| 숫자형식 | 14 | 숫자 표기 방식(자리수·구분자 등)만 달라 자동 비교 규칙이 못 맞춘 경우입니다. |
| 오독_창작 | 190 | 위 6가지 어디에도 안 걸린 나머지 — 아래에서 사람이 직접 하나씩 확인했습니다. |

**"오독_창작" 190건을 사람이 직접 열어 확인한 결과** (2026-09-06 재검토):

- **48건** — 우리 결과 자체가 "판독 불가"로 표시된 값(원본이 흐리거나 잘려
  읽을 수 없다고 정직하게 표시한 경우 — 지어낸 값이 아닙니다).
- **63건** — 정답에 없는 언어(인도네시아어·베트남어 등)로 된 라벨, 장식용
  구분선, 설문 항목 이름 등 — ⑤의 "정답 범위 밖" 성격이지만 자동 분류
  규칙(위 7종)이 라벨 사전에 없어 걸러내지 못한 경우입니다.
- **62건** — 상호명·품목 분류명(예: 메뉴 대분류명) 등, 정답 스키마에 대응
  자리가 없는 값입니다.
- **14건** — 품목명 형태의 값으로, 정답과 표기가 달라 자동 비교로는 못
  맞췄으나 범위 밖 성격에 가깝습니다.
- **약 25건(전체 값의 약 1.5%)** — 위 분류로도 설명되지 않는, **실제 오독이나
  결함으로 보이는 값**입니다(예: 숫자를 잘못 읽은 경우, 같은 단어를 반복해서
  출력한 경우 등).

즉 정밀도가 낮게 나온 516건 중 **대부분(약 93%)은 정답 스키마가 애초에 담지
않는 정보(표 밖 정보·열 제목 등)를 우리가 추가로 복원해서 생긴 것**이고,
채점 방식 차이(병합/숫자 표기)가 일부(약 6%)이며, **순수한 오독·결함으로
볼 수 있는 값은 전체 1,660개 중 약 25개(약 1.5%) 정도**로 파악됩니다.

**참고 — 가정적(가상) 수치**: `breakdown_summary.json`에는 "위 범위 밖
카테고리(1·2·3번)를 전부 뺀다면 정밀도가 얼마가 될까"를 계산한 가정적
수치(`가상_precision_범위제외`)가 함께 들어 있습니다. **이 값은 실제 측정치가
아니라 가정에 따른 계산값**이며, 품질 판단에 그대로 쓰지 않도록 파일 안에도
주의 문구를 남겨 두었습니다.

## ⑦ 파일 목록

| 파일 | 설명 |
|---|---|
| `README.md` | 이 문서 |
| `sample_list.csv` | 표본 100장의 색인. 열: `idx`(0~99, CORD-v2 test 분할 내 순번), `split`(고정값 `test`), `note`(판독이 특별히 어려웠던 장에만 표시 — 흐림·비영수증 등) |
| `scores.csv` | 장별 채점 결과. 열: `idx`(표본 번호) · `recall`(재현율) · `precision`(정밀도) · `f1`(F1, 계산 불가 시 빈 값) · `gt_n`(정답 값 개수) · `our_n`(우리 결과 값 개수) · `hit`(회수된 정답 값 개수) · `sec`(처리 시간, 초) · `err`(처리 오류 메시지, 없으면 빈 값) |
| `value_breakdown.csv` | 우리가 낸 값 1,660개 전체의 판정 명세. 열: `idx`(표본 번호) · `value`(우리가 낸 값) · `source`(값이 나온 위치 — `cell`은 표 칸, `text_block`은 본문 문단) · `category`(판정 분류 — `TP_일치`는 정답과 일치, 그 외는 위 ⑥의 7분류 중 하나) · `nearest_gt`(참고용으로 가장 가까운 정답 값을 표시한 것 — 비어 있을 수 있음) |
| `breakdown_summary.json` | ⑥의 집계 수치 원본(JSON) — 분류별 건수·비율, pooled 정밀도, 가정적(가상) 수치 포함 |

## ⑧ 한계

- CORD-v2는 인도네시아 소재 매장 영수증이 다수라 **영어·인도네시아어 위주의
  데이터셋**입니다. 한국어 촬영 문서를 주로 다루는 저희 서비스의 실제 사용
  조건과는 다릅니다 — 이 측정은 국제적으로 통용되는 공개 데이터셋에서 우리
  파이프라인이 어떻게 동작하는지 보여주는 참고 자료입니다.
- 이 채점은 **저희가 직접 설계한 자체 채점 방식**이며, CORD의 공식 채점
  방식(구조까지 비교하는 방식)과는 다릅니다. 공식 채점 결과가 아닙니다.
- 그래서 공개된 다른 모델의 CORD 점수와 **직접 순위를 비교하는 데 이 수치를
  쓰지 않습니다.** 참고 비교 목적으로만 `/benchmark` 페이지에 병기했습니다.
- 100장은 표본입니다 — 더 큰 표본이나 다른 표본에서는 수치가 달라질 수
  있습니다.
