"""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})
정답 = 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}")