chore(ledger): 조사 860-3 — 불러오기 재료 단위 차이 전수

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-11-15 14:33:28 +09:00
co-authored by Claude
parent 7f1695c1a7
commit 63b2ea53fd
2 changed files with 2078 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,124 @@
# 조사 860-3 — 일위대가 불러오기 재료 단위 차이
읽기 전용 · 제품 코드 · 마스터 불변 · 측정 도구와 결과 = `tmp/brain_860/` 안. 사실 = 코드 읽기 · 실측, 짐작 = 「짐작」 표시.
## 한 줄 결론
- 불러오기는 재료를 이은 뒤 **단위 환산을 하지 않음** — 우리 값(낮은 값)을 경쟁사 수량에 그대로 곱함. 단위 경고도 안 뜸.
- 견본 전수(이어진 재료 줄 1,953)에서 단위가 어긋난 줄 = **48 줄(2.5 %)**, 그 중 금액이 실제로 틀어진 줄 = **12 줄**(잔디 5 · 각재 4 · 골재시험 3 · 줄 금액 3 ~ 300 배 아래).
- 블록 합계가 2 배 이상 · 0.5 배 이하로 벌어진 블록 = **단위 때문에는 0**(최대 −28 %). 사용자가 본 「완전히 달라짐」 은 줄 금액 수준에서 확인됨 · 블록 수준에서는 견본에 없음.
- 견본에 없는 위험 = kg ↔ 톤 · g ↔ kg(우리 DB 에 같은 품목 쌍둥이 92 품목 · 가격비 정확히 1,000) — 지금은 걸린 줄 0 이나, 단위 문(same_kind)을 통과하므로 걸리면 1,000 배.
## 1. 지금 엔진이 단위를 다루는 곳
| 단계 | 자리 | 단위 처리 |
| --- | --- | --- |
| 코드 길(EST 자재 코드) | `M02_San_Link.py` 45~47 → `mf.done` | 단위 안 봄 |
| 별칭 · 정확 일치 · 표기 길 | `M02_San_MatFind.py` 150 · `_how` 183~196 | 단위 안 봄(별칭 · `ea.exact` · `ms.same`) |
| 정확 일치 후보 고르기 | `M02_Hopyo_Row.py` 141 · 143 `_alias` → `ea.one` | 같은 이름 · 규격 줄이 여럿이면 「같은 단위 먼저」 순위(`M02_Elem_Alias.py` 110)가 있으나 **줄에 단위를 안 넘겨**(`{"이름","규격"}` 만) 순위가 빠지고 키 차례 첫째가 뽑힘 — 재현함(잔디 ㎡ 줄인데 매 줄 MT006796 선택 · ㎡ 쌍둥이 MT006799 가 있었음) |
| 자동 규칙 A ~ F2 | `M02_San_MatFind.py` `_unit_ok` 224(B · E · 같은이름 후보) · `_unit_same` 228(C · F · F2) | `_unit_ok` = `hm.fits`(`M02_Hopyo_Match.py` 197 = 같은 글 또는 `same_kind`) → kg ↔ 톤 · 개 ↔ 본 ↔ 매 ↔ 개소 통과 · 길이 ↔ 개수 · 넓이 ↔ 개수는 거름 |
| 후보 모으기 | `M02_Hopyo_Material.py` 245 · 295 · `M02_Hopyo_MatSame.py` 196 | 같은 성격만 · 같은 단위 먼저(순위) · 후보 목록(`_cands`)에는 성격 다른 단위도 섞임 |
| 이은 뒤 값 넣기 | `M02_Doc_Import.py` 257~259 `_link_of` | 연결 `{갈래: 요소, 키}` — 단위는 품셈재료(MP)만 붙임, 자재품목(MT)은 안 붙임 |
| 값 읽기 | `master_material.py` 270~271 | MT 키 = `_lowest`(5 칸 중 낮은 값) 그대로 · 환산 없음 |
| 환산 코드(있음) | `master_unit.py` `convert` 96 · `master_pick.py` `_priced` 148~166(159~163 검색어 · 고름 길만 환산 · 같은 성격만 · 아니면 단위경고) | **불러오기 길은 안 지남**(165 else 가지 = 환산 없음 · 경고 없음) — 실측 경고 칸 전부 비어 있음 |
사실 요약: 단위가 달라도 이어짐(코드 · 별칭 · 정확 · 표기 길) · 이어진 뒤 환산 없음 · 같은 성격 문(`same_kind`)은 통과시키되 값은 안 바꿈.
## 2. 전수 결과
도구 = `tmp/brain_860/census_860.py`(828-1 census 를 줄여 복사 · 줄 단위로 단위 · 수량 · 단가 · 금액 · 우리 품목 단위 · 우리 값을 떠냄) + `ilwi_860.py`(STmate 일위 구성 자재 줄) + `final_860.py`. 대상 = 원파일 EST 6 · STC 7 + 실무 엑셀 11 · 3,241 산근 블록 · 이어진 재료 줄 1,953(산근 1,750 · 일위 203). 전수 목록 = `_목록_860-3_단위차이.tsv`(줄 1,953 · 구분 열 · 불일치 먼저).
| 구분 | 줄 | 품목 | EST 원파일 | EST 엑셀 | STmate 원파일 | STmate 엑셀 |
| --- | --- | --- | --- | --- | --- | --- |
| 이어진 재료 줄 전체 | 1,953 | 479 | 1,430 | 176 | 190 | 157 |
| ㉠ 단위 다름 — 성격 다름 | 42 | 17 | 7 | 15 | 7 | 13 |
| ㉠ 단위 다름 — 같은 성격(환산 가능) | 6 | 3 | 0 | 4 | 1 | 1 |
| ㉠′ 단위 글만 다름(같은 뜻) | 190 | 59 | 0 | 17 | 97 | 76 |
| ㉡ 단위 같음 · 단가 10 배 이상 · 0.1 배 이하 | 5 | 3 | 3 | 2 | 0 | 0 |
- EST 원파일 1,430 줄 중 1,294 줄 = `main`(다산소프트 EST 내장 DB 1,569 블록 · 실무 견본 아님). main 안 ㉠ 3 줄 · ㉡ 3 줄.
- ㉠′ = 같은 뜻 글만 다름(KG/kg 61 · M3/㎥ 41 · m/M 20 · M2/㎡ 19 · EA/개 30 · L/ℓ 7 · TON/Ton 6 · ㎏/kg 4 · Kg/kg 2) — 엔진 `plain` 이 같게 봄 · 금액 이상 없음(10 배 벗어난 줄 0).
- 일위 줄의 「우리 금액」 = 수량 × 우리 낮은 값(추정 · 별도계상 줄은 단가 0 유지로 제외).
## 3. 꼴별 (㉠ 48 줄 + ㉡ 5 줄)
| 꼴 | 경쟁사 → 우리 단위 | 줄 | 품목 | 원천(EST원 / EST엑 / STm원 / STm엑) | 금액 배(우리/엑셀) | 금액 영향 |
| --- | --- | --- | --- | --- | --- | --- |
| 무게 kg ↔ 톤 | — | 0 | 0 | — | — | 견본 없음 |
| 길이 m ↔ 본 · 롤 · 100 m | — | 0 | 0 | — | — | 견본 없음 |
| 넓이 | ㎡ → 매 | 5 | 2 | 4 / 1 / 0 / 0 | 0.032 · 0.044 | **틀림** |
| 부피 | ㎥ → 재 | 4 | 2 | 0 / 4 / 0 / 0 | 0.003 · 0.004 | **틀림** |
| 회 ↔ 무게(잘못 이음) | 회 → kg | 3 | 3 | 3 / 0 / 0 / 0 | 0.003 · 0.007 | **틀림** |
| 넓이 ↔ 무게(별도계상) | ㎡ → kg | 18 | 1 | 0 / 0 / 6 / 12 | — | 없음(단가 0 유지 · 이음 비움) |
| 낱개 1 : 1 | 본 → EA | 4 | 2 | 0 / 4 / 0 / 0 | 1.00 | 없음 |
| 낱개 1 : 1 | 개소 → 개 | 2 | 1 | 0 / 0 / 1 / 1 | 우리 값 없음 | 없음(0 원) |
| 낱개 | EA → 동 | 4 | 2 | 0 / 4 / 0 / 0 | 1.107 | 작음 |
| 낱개 | EA → 조 | 3 | 2 | 0 / 1 / 1 / 1 | 0.90 ~ 1.18 | 작음 |
| 낱개 | 본 → set | 1 | 1 | 0 / 1 / 0 / 0 | 1.03 | 작음 |
| 운반(Ton ↔ 회) | Ton → 회 | 4 | 4 | 0 / 4 / 0 / 0 | 1.00 | 없음(값이 같게 적혀 있음) |
| 규격에 숨은 묶음 | 경쟁사 kg · ㎡ ↔ 우리 포 · 매 | 0 | 0 | — | — | 견본 불일치 없음(우리 DB 61 줄에 「N kg/포」 꼴 · 같은 단위로만 이어짐) |
| 단위 글만 다름 | M ↔ m · EA ↔ 개 · ㎥ ↔ m3 … | 190 | 59 | 0 / 17 / 97 / 76 | 정상 | 없음 |
| ㉡ 단위 같음 · 단가만 벌어짐 | kg · Ton · ℓ | 5 | 3 | 3 / 2 / 0 / 0 | 0.02 · 20 · 126 | 큼(아래) |
대표 예 5(틀린 것):
| 경쟁사 글 · 단위 · 단가 | → 우리 키 · 이름 · 규격 · 단위 · 값 | 금액 |
| --- | --- | --- |
| 천연잔디(한국형) 0.18×0.18×0.01 · ㎡ · 6,172 | MT006796 천연잔디(한국형) 0.18*0.18*0.01 · 매 · 200 | 2,240 → 72.6 (0.032 배) · 같은 ㎡ 줄 MT006799(6,172)가 따로 있음 |
| 각재(외송) 3.6×3.0×3.0 · ㎥ · 577,844 | MT000393 외송 각재 · 재 · 2,059 | 8,344 → 29.7 (0.004 배) |
| 골재시험 0.08mm체 통과량시험 · 회 · 25,000 | MT009890 SS 골재 혼합골재 · kg · 171 | 25,000 → 171 (0.007 배) |
| 고철 중량A · kg · −21,150(㉡) | MT007570 고철 중량A · kg · −423 | 0.02 배(정확히 1/50 · 짐작 = 경쟁사 값에 50 kg 묶음이 얹힘) |
| 산소 고압가스 · ℓ · 4.17(㉡) | MT003166 산소 고압상태 · ℓ · 525 | 126 배(짐작 = 우리 줄 값이 ㎥ 당 크기 · 단위 칸 ℓ 와 어긋남) |
잔디 ㎡ → 매 는 규격으로 맞춰짐: 200 ÷ (0.18×0.18) = 6,173 ≈ 6,172 · 294 ÷ (0.21×0.21) = 6,667 ≈ 6,664.
## 4. 영향
산근 블록(「우리 단가로」 실제 재계산 · `M02_Sangeun_Imported.to_price`):
| 항목 | 블록 수 |
| --- | --- |
| ㉠ 줄이 든 산근 블록 | 23 (EST 엑셀 16 · EST 원파일 5 · STmate 원파일 1 · STmate 엑셀 1) |
| 그 중 합계 「우리 / 엑셀」 2 배 이상 · 0.5 배 이하 | **0** |
| 그 중 합계가 크게 틀어진 것(단위 줄 빼면 1.00 으로 돌아옴) | 줄떼심기 5 블록 0.72 배 · 합판거푸집 4 블록 0.82 ~ 0.83 배 · 도로반사경 설치 2 블록 0.94 배 · 품질시험비(main) 0.96 배 |
| ㉡ 줄이 든 산근 블록 | 5 (그 중 0.5 배 이하 1 = SHEET-PILE(손율 50 %) 0.45 · 산소 든 철근콘크리트깨기 2 블록 1.63 · 1.73 배) |
| 산근 전체에서 2 배 이상 · 0.5 배 이하(원인 무관) | 3(SHEET-PILE · 중기운반 2 — 중기운반은 재료 줄 없음 · 노임 · 기계 값 차이) |
| ㉠ 줄이 든 일위 블록(STmate) | 20 (STmate 원파일 7 · 엑셀 13) — 파쇄암(별도계상) 18 블록 · 취수장 설치 2 블록 |
| 일위 블록 2 배 이상 · 0.5 배 이하(재료 줄만 다시 센 추정) | 0 |
- 블록 합계가 덜 벌어지는 까닭 = 단위 틀린 줄이 블록 금액의 작은 몫(노무 · 기계가 큼). 줄 금액만 보면 최대 약 300 배(각재 · 잔디).
- 우리 DB 안 같은 품목 · 단위만 다른 줄 쌍둥이: 이름 · 규격 같은 그룹 중 단위가 둘 이상 = **103 그룹 · 206 줄** (kg ↔ 톤 92 · ㎡ ↔ 매 6 · ㎡ ↔ 개 4 · ㎡ ↔ ℓ 1). kg ↔ 톤 92 쌍은 톤/kg 가격비가 모두 정확히 1,000.
- 이어진 줄 중 쌍둥이 품목에 닿은 줄 18 · 그 중 단위가 맞게 이어진 14 · 어긋난 4(잔디 ㎡ → 매 · 올바른 ㎡ 줄이 따로 있었음).
- 못 이은 재료 종 103(284 줄 · 단서 없이 새로 찾아 근사) 중 후보가 있는 82 종 · 후보에 단위 다른 줄이 섞인 50 종 · 1 순위가 단위 다른 36 종(같은 성격 g ↔ kg 종자류 10 종 29 줄 · 성격 다름 26 종 40 줄 · 같은 단위 14 종 44 줄) — 사람이 그 후보를 고르면 같은 이음 길이라 환산 없음 · 목록 = `_목록_860-3_후보단위.tsv`. 종자(초본류 · 목본류) 후보 첫 줄이 g 단위 → 경쟁사 KG 로 고르면 1,000 배.
## 5. 고를 거리(사실만)
| 길 | 풀 수 있는 줄(견본) | 비고 |
| --- | --- | --- |
| A. 단위가 다르면 안 잇고 「고를 재료」 로 | ㉠ 48 줄 전부 이음 해제 — 그 중 금액 틀린 12 줄 · 별도계상 18 · 값 없음 2 · 금액 영향 없는 1 : 1 류 16 | 금액 안 틀리는 줄(본 ↔ EA · Ton ↔ 회 등)까지 사람 일로 넘어감 · ㉡ 5 줄은 못 거름 |
| B. 같은 뜻 단위 사전 | ㉠′ 190 줄은 이미 `plain` 으로 같게 봄(추가 0) · 새 사전 항목(본 = EA · 개소 = 개 · EA = 동)으로 10 줄 | 금액은 이미 정상 · 고쳐지는 금액 0 |
| C. 환산 규칙(확실한 것만 kg ↔ 톤 · g ↔ kg · m ↔ mm · ℓ ↔ ㎥ · 개수 1 : 1) | 견본 줄 6(1 : 1 · 금액 이미 정상) · 위험은 견본 밖(DB 쌍둥이 92 품목 · 후보 g ↔ kg 29 줄) | `master_unit.convert` 이미 있음 — 불러오기 길에 안 붙었을 뿐 |
| D. 규격의 묶음 수로 환산(0.18×0.18 → 매당 0.0324 ㎡ · 「20kg/포」) | 잔디 5 줄 | 각재 ㎥ ↔ 재 4 줄은 규격이 아니라 「1 재 = 0.00835 ㎥」 상수가 필요 · 우리 DB 「N kg/포」 꼴 61 줄 |
| E. 같은 품목 쌍둥이에서 경쟁사 단위와 같은 줄을 먼저 고름 | 잔디 5 줄(올바른 ㎡ 줄이 있음) | 환산 없이 풀림 · 쌍둥이 없는 줄은 못 풂 |
| F. 사람이 고름 | 남는 줄 전부(골재시험 3 · 각재 4 · 도로반사경 3 …) | 고름 길도 이음이라 환산 없음 → 위 길과 같이 가야 함 |
바뀌는 코드 자리(후보):
- `M02_Hopyo_Row.py` 141 · 143 — `ea.one` 에 줄 단위 넘김(길 E).
- `M02_San_MatFind.py` 150 · `_how` 183 — 이은 뒤 단위 검사 · 어긋나면 판정 「고르기」 로(길 A) · 코드 길 `M02_San_Link.py` 45~47 도 같음.
- `M02_Doc_Import.py` 257~259 — MT 연결에도 `단위` 붙임 + `master_material.py` 270~271 에서 `master_unit.convert` · 같은 성격 · 규격 묶음 환산(길 C · D) + 불가 시 `단위경고`(`master_pick.py` 159~165 가지와 한 벌로).
- `M02_Hopyo_Match.py` 197 `fits` — same_kind 통과 줄이 환산 없이 이어지는 구멍.
## 못 함 · 한계
- EST 일위대가 구성 줄(`saved["일위"]` 비어 있음 · 읽기기가 구성 줄을 안 냄) — STmate 일위 203 줄만 봄.
- 일위 블록은 엔진이 「우리 단가로」 를 실제로 다시 셈하는지 미확인 — 추정(수량 × 우리 낮은 값)만.
- 후보 단위 대조는 단서(산근 머리 · 같은 파일 줄) 없이 `find` 새로 돌린 근사.
- sub_laptop_3 census 는 읽기만 하고 복사 · 수정본으로 메인 저장소에서 새로 돌림(옛 결과 pkl 은 단위 · 단가가 없어 안 씀). 낙찰률 보정 등 `to_price` 안쪽은 그대로.
- 산소 · 고철 ㉡ 의 원인은 짐작(경쟁사 · 우리 값 정의 차이) — 경쟁사 원파일 재분석 안 함.
- 견본 밖 파일(사용자가 본 사례)은 없어 재현 못 함 — 견본에서는 kg ↔ 톤 · m ↔ 본 · ㎡ ↔ 롤 · ℓ ↔ 드럼 줄이 0.
## 산출물
- `tmp/brain_860/_목록_860-3_단위차이.tsv`(전수 1,953 줄) · `_목록_860-3_후보단위.tsv`(후보 단위 다른 종)
- 도구 · 중간 결과 = `tmp/brain_860/*.py` · `rows/` · `lines.pkl` · `rows_final.pkl`