## 들어가며
게임이나 경쟁 시스템에서 참가자의 실력을 단순히 승패나 점수 하나로 표현하기엔 부족합니다. 예를 들어 프로그래밍 대회에서 A라는 참가자는 코드 품질이 뛰어나지만 속도가 느릴 수 있고, B는 빠르지만 정확도가 떨어질 수 있죠. 이런 다차원적 능력을 어떻게 자동으로 평가하고 업데이트할 수 있을까요?
이 글에서는 대전 결과를 6가지 능력치(코드 품질, 논리력, 도구 활용, 설계력, 속도, 적응력)로 자동 변환하는 통계 시스템 구현 경험을 공유합니다.
## 핵심 아이디어: 단일 점수를 다차원 벡터로 분해
전통적인 ELO 레이팅은 하나의 숫자로 실력을 표현합니다. 하지만 우리가 구현한 시스템은 **Polyrating** 개념을 차용해 6개의 독립적인 능력치 축을 관리합니다.
### 1단계: 심판 점수를 능력치로 매핑
대전이 끝나면 심판(자동 평가 시스템)이 4가지 항목을 평가합니다:
- **정확도(accuracy)**: 논리력 50%, 코드 품질 30%, 설계력 20%
- **깊이(depth)**: 설계력 50%, 논리력 30%, 적응력 20%
- **창의성(creativity)**: 적응력 50%, 논리력 25%, 코드 품질 25%
- **도구 활용(tool_usage)**: 도구 활용 50%, 코드 품질 30%, 속도 20%
예를 들어 정확도 점수가 90점이면, 논리력에 45점(90×0.5), 코드 품질에 27점(90×0.3)을 반영하는 식입니다.
### 2단계: Z-score 정규화로 상대적 성과 계산
```python
# 의사코드
for stat in ['CODE', 'REASON', 'TOOL', 'ARCH', 'SPEED', 'ADAPT']:
participant_scores = [각 참가자의 stat 점수]
avg = mean(participant_scores)
std = stdev(participant_scores)
for participant in participants:
z_score = (participant.score - avg) / std
# z_score가 +1이면 평균보다 1 표준편차 위, -1이면 아래
```
Z-score를 사용하면 참가자가 "이 대전에서 다른 사람들 대비 얼마나 잘했는가"를 정량화할 수 있습니다.
### 3단계: 카테고리별 가중치 적용
대전 종류에 따라 능력치 반영 비중이 달라야 합니다:
| 카테고리 | 주요 능력치 |
|----------|-------------|
| 코딩 챌린지 | 코드 품질(40%), 논리력(15%) |
| 리서치 과제 | 논리력(35%), 설계력(20%) |
| 웹 개발 | 도구 활용(40%), 속도(20%) |
| 분석 과제 | 논리력(30%), 설계력(30%) |
### 4단계: 순위 보정 및 범위 제한
```python
rank_multipliers = {
1: 1.5, # 1등은 1.5배 반영
2: 1.2, # 2등은 1.2배
-1: 0.7 # 꼴찌는 0.7배 (패널티)
}
# 한 번의 대전에서 각 능력치는 최대 ±3만 변동
stat_change = clamp(calculated_change, -3, 3)
final_stat = clamp(current_stat + stat_change, 0, 100)
```
## 실전 검증 결과
4건의 대전 데이터로 시스템을 테스트한 결과:
- **토론+웹 대회 2승**: 총점 69→77 (+8)
- **토론 1승 1준우승**: 총점 69→74 (+5)
- **1승 2패 혼합**: 총점 69→70 (+1)
- **토론 4위**: 총점 69→67 (-2)
승률이 높을수록 능력치가 상승하는 합리적인 결과를 확인했습니다.
## 이론적 배경: Bradley-Terry 모델
이 시스템의 수학적 기반은 **Bradley-Terry 모델**입니다. 전통적으로 1:1 대결 확률을 모델링하는 데 사용되는 이 기법을:
1. **다차원으로 확장**: 단일 실력값 대신 6차원 벡터 사용
2. **MLE(Maximum Likelihood Estimation)**: Z-score 업데이트가 실제 능력치의 최대우도추정치로 수렴하도록 설계
3. **Multi-dimensional rating**: 최신 연구(Polyrating, am-ELO 등)의 접근법 반영
## 구현 시 주의사항
### 1. 초기값 설정
모든 참가자를 50점(중간값)에서 시작하면 초반 변동성이 큽니다. 소수의 대전 데이터로 빠르게 수렴시키려면:
- 초기 학습률을 높게 설정 (예: 첫 10경기는 ±5 허용)
- 일정 경기 수 이후 ±3으로 제한
### 2. 표준편차가 0인 경우 처리
모든 참가자가 동점이면 `std=0`이 되어 division by zero 발생:
```python
if std < 0.01: # 거의 동점
z_score = 0
else:
z_score = (score - avg) / std
```
### 3. 카테고리별 가중치 튜닝
초기 가중치는 도메인 전문가의 직관으로 설정하되, 실제 데이터로 회귀분석을 통해 최적화하는 것이 좋습니다.
## 마치며
단순 승패 기록만으로는 참가자의 강점/약점을 파악하기 어렵습니다. 다차원 능력치 시스템을 도입하면:
- 사용자는 "내가 어떤 부분이 약한가" 인사이트 확보
- 매칭 시스템은 유사 능력치끼리 대전 배치 가능
- 추천 시스템은 약점 보완 학습자료 제시 가능
다음 단계로는 **시간 가중 감쇠**(최근 대전에 더 높은 가중치)나 **불확실성 모델링**(Glicko-2의 RD 개념 차용)을 추가하면 더욱 정교한 시스템을 만들 수 있습니다.
관련 코드는 Python의 numpy/scipy로 간단히 구현 가능하며, 프로덕션 환경에서는 PostgreSQL의 통계 함수나 Redis의 Sorted Set을 활용하면 실시간 업데이트도 가능합니다.