PIA-SPACE_LeaderBoard / utils /column_rules.py
irfanrah's picture
refactor: 리더보드 메인 탭만 남기고 전부 제거 (Google Sheets 표출 경량화)
3c5a6a0
Raw
History Blame Contribute Delete
6.47 kB
"""리더보드 컬럼 규칙.
벤치마크 컬럼은 `<데이터셋>_<카테고리>` 명명 규칙(예: Coupang_Fire, Soil_v2_Smoke,
AVG_Falldown)을 따른다. 이 규칙으로 df.columns 만 보고 카테고리/데이터셋 축을
자동 분류하고 표시/숨김 컬럼을 계산한다 — 신규 벤치마크가 등록되어도
config 목록을 손볼 필요가 없다 (기존 ON_LOAD_COLUMNS/HIDE_COLUMNS 대체).
"""
from typing import List, Optional, Sequence, Tuple
import pandas as pd
import enviroments.config as config
# AVG_* 컬럼의 prefix. 데이터셋 축에서는 가상 데이터셋으로 취급한다.
AVG_DATASET = "AVG"
def split_benchmark_column(column: str) -> Optional[Tuple[str, str]]:
"""`<데이터셋>_<카테고리>` 컬럼을 (데이터셋, 카테고리)로 분해.
규칙 밖 컬럼(TASK, Model, "Model name" 등)은 None.
"""
if "_" not in column or " " in column:
return None
dataset, _, category = column.rpartition("_")
if not dataset or not category:
return None
return dataset, category
def build_hide_columns(columns: Sequence[str]) -> List[str]:
"""테이블에서 아예 제외할 컬럼 (숨김 카테고리 패턴 + 개별 지정)."""
hidden = []
for col in columns:
if col in config.HIDE_COLUMN_EXACT:
hidden.append(col)
continue
parsed = split_benchmark_column(col)
if parsed and parsed[1] in config.HIDE_CATEGORIES:
hidden.append(col)
return hidden
def parse_axes(columns: Sequence[str]) -> Tuple[List[str], List[str]]:
"""df.columns → (카테고리 목록, 데이터셋 목록). 숨김 컬럼/AVG 데이터셋 제외."""
hidden = set(build_hide_columns(columns))
categories, datasets = set(), set()
for col in columns:
if col in hidden:
continue
parsed = split_benchmark_column(col)
if parsed is None:
continue
dataset, category = parsed
categories.add(category)
if dataset != AVG_DATASET:
datasets.add(dataset)
return sorted(categories), sorted(datasets)
def extra_columns(columns: Sequence[str]) -> List[str]:
"""벤치마크 명명 규칙 밖이면서 기본/필수 컬럼도 아닌 부가 컬럼.
예: "Datasets Used", "Infer Speed". 셀렉터의 '추가 정보' 축이 된다.
"""
always_on = set(config.LEADERBOARD_BASE_COLUMNS) | set(config.OFF_LOAD_COLUMNS)
hidden = set(build_hide_columns(columns))
return [
col
for col in columns
if col not in always_on
and col not in hidden
and split_benchmark_column(col) is None
]
def avg_categories(columns: Sequence[str]) -> List[str]:
"""AVG_<카테고리> 컬럼이 존재하는 카테고리 목록 (숨김 제외, df 순서)."""
hidden = set(build_hide_columns(columns))
cats = []
for col in columns:
if col in hidden:
continue
parsed = split_benchmark_column(col)
if parsed and parsed[0] == AVG_DATASET:
cats.append(parsed[1])
return cats
def datasets_for_category(columns: Sequence[str], category: str) -> List[str]:
"""해당 카테고리 벤치마크(<데이터셋>_<카테고리>)를 가진 전체 데이터셋."""
out = set()
for col in columns:
parsed = split_benchmark_column(col)
if parsed and parsed[1] == category and parsed[0] != AVG_DATASET:
out.add(parsed[0])
return sorted(out)
def default_avg_map(columns: Sequence[str]) -> dict:
"""카테고리별 AVG 계산 기준의 기본값: 정식 세트 ∩ 해당 카테고리 보유 데이터셋."""
return {
cat: [
d
for d in config.DEFAULT_AVG_DATASETS
if d in datasets_for_category(columns, cat)
]
for cat in avg_categories(columns)
}
def apply_avg_override(df: pd.DataFrame, avg_map: Optional[dict] = None) -> pd.DataFrame:
"""AVG_<카테고리> 컬럼을 카테고리별 기준 데이터셋의 행별 평균으로 대체.
구글 시트의 AVG 원본은 건드리지 않고 화면 표시값만 교체한다.
- avg_map: {카테고리: [데이터셋, ...]}. 카테고리가 없거나 빈 리스트면
config.DEFAULT_AVG_DATASETS (정식 벤치마크 세트) 기준으로 계산.
- 그룹 컬럼 값이 하나라도 비어 있는 모델은 빈칸 (완주한 모델만 AVG 표시).
- 기준 데이터셋에 해당 카테고리 컬럼이 하나도 없으면 전체 빈칸.
"""
avg_map = avg_map or {}
df = df.copy()
for col in df.columns:
parsed = split_benchmark_column(col)
if parsed is None or parsed[0] != AVG_DATASET:
continue
category = parsed[1]
selected = avg_map.get(category) or config.DEFAULT_AVG_DATASETS
members = [
f"{d}_{category}" for d in selected if f"{d}_{category}" in df.columns
]
if not members:
df[col] = ""
continue
vals = df[members].apply(pd.to_numeric, errors="coerce")
avg = vals.mean(axis=1)
avg[vals.isna().any(axis=1)] = float("nan")
df[col] = avg.map(lambda v: "" if pd.isna(v) else f"{v:.4f}")
return df
def compute_display_columns(
columns: Sequence[str],
categories: Sequence[str],
datasets: Sequence[str],
extras: Sequence[str] = (),
) -> List[str]:
"""선택된 카테고리 × 데이터셋 교집합 + 부가 컬럼의 표시 목록 (df 컬럼 순서 유지).
datasets 가 비어 있으면 전체 데이터셋(AVG 포함)으로 취급.
기본/필수 컬럼(TASK, Model, Model name 등)은 항상 표시.
"""
selected_cats = set(categories or [])
selected_ds = set(datasets or [])
selected_extras = set(extras or [])
always_on = set(config.LEADERBOARD_BASE_COLUMNS) | set(config.OFF_LOAD_COLUMNS)
hidden = set(build_hide_columns(columns))
display = []
for col in columns:
if col in hidden:
continue
parsed = split_benchmark_column(col)
if parsed is None:
if col in always_on or col in selected_extras:
display.append(col)
continue
dataset, category = parsed
if category not in selected_cats:
continue
if selected_ds and dataset not in selected_ds:
continue
display.append(col)
return display