untracked files on main: dceb101 feat(#63): IMP-34 R1 donor capacity measured bound (u1+u2)

This commit is contained in:
2026-05-21 22:07:41 +09:00
commit 8f085a28d3
3220 changed files with 985495 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
"""Phase 5 — Case 2 통합표 (세부 단위 유닛에 대한 7개 방법 비교)
세로: 유닛(6, 12) × 순위(1/2/3)
가로: 7개 방법 (키워드 3 + 구조 1 + 의미 3 - SBERT 3 variant)
"""
import re
from pathlib import Path
HERE = Path(__file__).parent
# (유닛 번호, 유닛 이름, 종류, 정답 short ID, 정답 타이틀)
TARGET_UNITS = [
("6", "MDX01-2-details", "팝업+표", "18", "BIM과 DX의 이해"),
("12", "MDX02-2.2-table", "", "14", "(MDX02-2 primary)"),
]
# Phase 2 소스 방법명 → Case 2 표시 방법명
METHOD_MAP = [
("TF-IDF", "TF-IDF"),
("Char-ngram", "Char 3-gram"),
("Kiwi+BM25", "Kiwi+BM25"),
("Structural", "구조 메타"),
("SBERT-원본", "ko-srobert"),
("SBERT-축약", "축약+srobert"),
("SBERT-청크", "청킹+srobert"),
]
md = (HERE / "MATRIX_PHASE2.md").read_text(encoding="utf-8")
parts = re.split(r"\n## (\d+)\. ", md)
unit_blocks = {parts[i]: parts[i + 1] for i in range(1, len(parts), 2)}
def extract_top3(block_text, method_name):
"""Row 한 줄에서 1위/2위/3위 셀을 각각 반환"""
for line in block_text.split("\n"):
if line.startswith(f"| {method_name} |"):
cells = line.split(" | ")
if len(cells) >= 4:
# cells[0] = "| 방법명", cells[1..3] = 1위/2위/3위
# cells[3]에 trailing "|" 있을 수 있음 → rstrip
top3 = [c.strip().rstrip("|").strip() for c in cells[1:4]]
return top3
return ["-", "-", "-"]
def mark_correct(cell, correct_id):
"""정답 프레임이면 ⭐ 표시"""
if f"**{correct_id}**" in cell:
return "" + cell
return cell
# 리포트 조립
lines = []
lines.append("# Phase 5 — Case 2. 세부 단위(팝업·표) 매칭 통합표")
lines.append("")
lines.append("**비교 대상**: 7개 방법 (키워드 3 + 구조 1 + 의미 3)")
lines.append("- 의미 매칭은 **SBERT 한 모델에 3가지 전처리 전략** 적용 (원본/축약/청크)")
lines.append("- 세부 단위(팝업·표)가 키워드 vs 의미 매칭 성능 차이를 드러내는지 확인용")
lines.append("")
lines.append("정답 프레임은 ⭐로 표시했습니다.")
lines.append("")
# 헤더: 콘텐츠 | 7개 방법
header = ["콘텐츠"] + [display for _, display in METHOD_MAP]
lines.append("| " + " | ".join(header) + " |")
lines.append("|" + "|".join(["------"] * len(header)) + "|")
for num, uid, kind, correct_id, correct_title in TARGET_UNITS:
block = unit_blocks.get(num, "")
# 방법별 top3 추출
method_tops = {}
for src_name, display_name in METHOD_MAP:
method_tops[display_name] = extract_top3(block, src_name)
# 유닛 헤더 행 (7 col 전체 병합 느낌으로 굵게)
header_cell = f"**{num}. {uid}** ({kind})<br>정답 = Frame **{correct_id}**"
lines.append(f"| {header_cell} | " + " | ".join([""] * len(METHOD_MAP)) + " |")
# 1위/2위/3위 행
for rank_idx, rank_label in enumerate(["**1순위**", "**2순위**", "**3순위**"]):
row = [rank_label]
for _, display_name in METHOD_MAP:
cell = method_tops[display_name][rank_idx]
row.append(mark_correct(cell, correct_id))
lines.append("| " + " | ".join(row) + " |")
lines.append("")
lines.append("---")
lines.append("")
lines.append("## 관찰 포인트")
lines.append("")
lines.append("1. **세부 단위에서는 키워드 > 의미**: 팝업·표처럼 구체적 텍스트가 많은 유닛에서는 "
"TF-IDF/Char/Kiwi+BM25 모두 1위 정답. 직접 단어 겹침이 크기 때문.")
lines.append("2. **구조 메타**는 두 유닛 모두 동일 결과 (17/01/05) — 세부 단위는 구조적 특징이 "
"거의 같아서 변별력 없음.")
lines.append("3. **축약+srobert 전략은 세부 단위에 부적합**: 제목/볼드만 뽑으면 팝업·표의 핵심 "
"내용이 날아감. 두 유닛 모두 실패.")
lines.append("4. **청킹+srobert**: 블릿·섹션 구조가 명확한 팝업(6번)은 성공, 표만 있는 12번은 "
"청크 나누기가 애매해 실패.")
lines.append("5. **ko-srobert 원본**: 의미 방법 중 세부 단위에 가장 적합. 두 유닛 모두 1위 정답.")
lines.append("")
out_path = HERE / "MATRIX_PHASE5.md"
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"완료: {out_path}")