ai

# Ridge Regression으로 라벨 보정 — 감으로 정한 가중치를 데이터로 대체한 후기

막차 탄 개발자 2026. 4. 26. 21:37

## 문제의 시작: 감정 분석 라벨의 주관성

연예인 얼굴 이미지로 감정 분석 모델을 만들다 보니 골치 아픈 문제가 하나 있었다. 같은 표정이라도 사람마다 '강도'를 다르게 느끼는 것이다. 어떤 이는 미세한 미소를 '행복도 7'로 보고, 다른 이는 '행복도 4'로 본다.

초기에는 이런 라벨 불일치를 그냥 "데이터가 원래 그런 거지"라고 넘어갔다. 하지만 모델 성능이 계속 기대치를 못 채우자, 라벨 자체에 문제가 있을 수도 있겠다는 생각이 들었다.

## 기존 방식: 감으로 정한 가중치

처음에는 주관성 문제를 이렇게 해결하려고 했다:

```python
# 기존 가중치 적용 방식
weights = {
    'happiness': 0.8,  # 행복은 좀 낮게
    'sadness': 1.2,    # 슬픔은 좀 높게
    'anger': 1.0,      # 분노는 그대로
    'surprise': 0.9    # 놀람은 살짝 낮게
}

adjusted_labels = original_labels * weights[emotion_type]
```

완전히 감정적인 결정이었다. "행복 표정은 사람들이 과하게 점수를 주는 것 같으니까 0.8 곱하자", "슬픔은 과소평가되는 것 같으니까 1.2 곱하자" 이런 식으로.

당연히 결과는 별로였다. 검증 데이터에서 일관성이 없었고, 새로운 이미지에 대한 예측도 들쑥날쑥했다.

## Ridge Regression 도입

그러다가 문득 "라벨 보정도 학습으로 할 수 있지 않을까?"라는 생각이 들었다. 연예인 데이터의 특징을 보면:

- 같은 연예인이라도 다양한 표정 데이터가 있다
- 일부 연예인은 전문 평가자들이 별도로 점수를 매긴 '골드 스탠다드' 라벨이 있다
- 크라우드소싱으로 모은 라벨과 전문가 라벨 사이에 체계적인 차이가 있다

이 상황에서 Ridge Regression을 써서 크라우드소싱 라벨을 전문가 라벨에 맞게 보정해보기로 했다.

```python
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error

# 골드 스탠다드가 있는 데이터만 추출
gold_data = df[df['has_expert_label'] == True]

# 특성: 크라우드소싱 점수들
X = gold_data[['crowd_happiness', 'crowd_sadness', 'crowd_anger', 'crowd_surprise']]
# 타겟: 전문가 점수들
y = gold_data[['expert_happiness', 'expert_sadness', 'expert_anger', 'expert_surprise']]

# 감정별로 Ridge 모델 학습
models = {}
for emotion in ['happiness', 'sadness', 'anger', 'surprise']:
    ridge = Ridge(alpha=1.0, random_state=42)
    ridge.fit(X, y[f'expert_{emotion}'])
    models[emotion] = ridge
```

## 알파 값 튜닝과 결과

Ridge의 정규화 강도(alpha)를 찾기 위해 간단한 그리드 서치를 돌렸다:

```python
alphas = [0.1, 0.5, 1.0, 2.0, 5.0, 10.0]
results = []

for alpha in alphas:
    mae_scores = []
    for emotion in emotions:
        ridge = Ridge(alpha=alpha, random_state=42)
        X_train, X_test, y_train, y_test = train_test_split(
            X, y[f'expert_{emotion}'], test_size=0.3, random_state=42
        )
        ridge.fit(X_train, y_train)
        y_pred = ridge.predict(X_test)
        mae = mean_absolute_error(y_test, y_pred)
        mae_scores.append(mae)
    
    results.append((alpha, np.mean(mae_scores)))
    print(f"Alpha {alpha}: 평균 MAE {np.mean(mae_scores):.3f}")
```

결과는 다음과 같았다:

| Alpha | 평균 MAE | 비고 |
|-------|----------|------|
| 0.1   | 0.285    | 과적합 경향 |
| 0.5   | 0.251    | |
| 1.0   | 0.238    | **최적** |
| 2.0   | 0.247    | |
| 5.0   | 0.271    | 과도한 정규화 |
| 10.0  | 0.289    | 과도한 정규화 |

Alpha=1.0일 때 가장 좋은 성능이 나왔다.

## 학습된 가중치 분석

최종 모델의 계수를 보니 흥미로운 패턴이 있었다:

```python
# 각 감정별 보정 계수
for emotion in emotions:
    coef = models[emotion].coef_
    print(f"{emotion} 보정 계수:")
    for i, feature in enumerate(['happiness', 'sadness', 'anger', 'surprise']):
        print(f"  {feature}: {coef[i]:.3f}")
    print(f"  절편: {models[emotion].intercept_:.3f}")
    print()
```

결과:

**Happiness 보정:**
- happiness: 0.742 (내가 감으로 정한 0.8과 유사)
- sadness: -0.089
- anger: -0.034
- surprise: 0.198
- 절편: 0.231

**Sadness 보정:**
- happiness: -0.156
- sadness: 1.089 (내가 감으로 정한 1.2보다 낮음)
- anger: 0.087
- surprise: -0.023
- 절편: 0.112

흥미롭게도 내가 감으로 정한 가중치와 어느 정도 비슷한 방향성을 보였다. 하지만 더 정교하게, 다른 감정들과의 상관관계까지 고려한 보정이 이뤄졌다.

## 실제 성능 개선

보정 전후 성능을 비교해봤다:

| 메트릭 | 기존 감정 가중치 | Ridge 보정 | 개선도 |
|--------|------------------|------------|--------|
| 행복도 MAE | 0.342 | 0.238 | -30.4% |
| 슬픔도 MAE | 0.298 | 0.221 | -25.8% |
| 분노도 MAE | 0.267 | 0.245 | -8.2% |
| 놀람도 MAE | 0.319 | 0.252 | -21.0% |
| **전체 평균** | **0.307** | **0.239** | **-22.1%** |

모든 감정에서 예측 정확도가 개선되었다. 특히 행복도와 슬픔도에서 큰 개선이 있었다.

## 추가 발견: 연예인별 편향

데이터를 더 파보니 연예인별로도 체계적인 편향이 있었다. 어떤 연예인은 항상 '더 행복해 보인다'고 평가받고, 어떤 연예인은 '더 차갑게' 평가받는다.

```python
# 연예인별 평균 편향 계산
celebrity_bias = df.groupby('celebrity_name').agg({
    'crowd_happiness': 'mean',
    'expert_happiness': 'mean'
}).reset_index()

celebrity_bias['happiness_bias'] = (celebrity_bias['crowd_happiness'] - 
                                   celebrity_bias['expert_happiness'])

# 편향이 큰 연예인들
print(celebrity_bias.sort_values('happiness_bias', ascending=False).head())
```

이 부분은 아직 완전히 해결하지 못했지만, 다음 단계에서는 연예인별 편향까지 고려한 hierarchical 보정을 시도해볼 예정이다.

## 배운 점들

1. **감보다는 데이터**: 내가 감으로 정한 가중치가 방향성은 맞았지만, 데이터 기반 보정이 훨씬 정교했다.

2. **교차 감정 효과**: 단순히 각 감정을 독립적으로 보정하는 게 아니라, 다른 감정 점수들도 함께 고려하는 게 중요했다.

3. **정규화의 중요성**: Ridge의 L2 정규화가 과적합을 방지하면서도 일반화 성능을 높였다.

4. **골드 스탠다드의 가치**: 소량이라도 고품질 라벨이 있으면 전체 데이터셋의 품질을 높일 수 있다.

## 다음 단계

현재 Ridge Regression으로 기본적인 라벨 보정은 성공했지만, 아직 개선할 부분들이 많다:

- 연예인별 편향 보정
- 시간에 따른 평가 기준 변화 (트렌드 효과)
- 더 복잡한 모델 (Random Forest, XGBoost) 시도
- 능동 학습으로 골드 스탠다드 데이터 효율적 확장

라벨 품질 문제로 고민 중인 분들이 있다면, 일단 간단한 Ridge Regression부터 시작해보는 것을 추천한다.