[Kaggle] Day-2. Child Mind Institute : EDA

DD[Dev_Diary]·2024년 11월 17일

EDA: 데이터 전처리 및 SII 재계산 🛠️

이번 EDA 과정에서는 PCIAT 데이터의 결측치 처리 및 SII 점수 재계산을 수행하였습니다. 이후 결과를 바탕으로 데이터의 이상값을 분석하고 시각화하는 과정까지 진행했습니다.


1. PCIAT-PCIAT_Total 검증 및 합계 재계산 🧮

PCIAT_cols = [f'PCIAT-PCIAT_{i+1:02d}' for i in range(20)]

recalc_total_score = train_with_sii[PCIAT_cols].sum(
    axis=1, skipna=True
)

(recalc_total_score == train_with_sii['PCIAT-PCIAT_Total']).all() # PCIAT Valuse Sum == Total

설명

  • PCIAT_cols: 각 질문 열 이름을 동적으로 생성합니다.
  • sum(axis=1, skipna=True): 결측치(NaN)를 무시하고 각 행의 합계를 계산합니다.
  • all(): 합계가 PCIAT-PCIAT_Total과 동일한지 전체적으로 확인합니다.

결과

합계가 동일한지를 확인하여, 데이터의 정합성을 검증할 수 있습니다. 이후 이 정보를 바탕으로 SII 값을 재계산하였습니다.


2. SII 재계산 함수 정의 및 적용 🛠️

def recalculate_sii(row):
    # PCIAT-PCIAT_Total 값이 결측치인 경우 NaN 반환
    if pd.isna(row['PCIAT-PCIAT_Total']):
        return np.nan, np.nan

    # 최대 가능한 점수 계산
    max_possible = row['PCIAT-PCIAT_Total'] + row[PCIAT_cols].isna().sum() * 5

    # 디버깅용 출력 (필요 없으면 제거 가능)
    print(f"PCIAT-PCIAT_Total: {row['PCIAT-PCIAT_Total']}")
    print(f"Missing questions: {row[PCIAT_cols].isna().sum()}")
    print(f"Added to max_possible: {row[PCIAT_cols].isna().sum() * 5}")
    print('-' * 80)

    # SII 카테고리 재계산
    if row['PCIAT-PCIAT_Total'] <= 30 and max_possible <= 30:
        return max_possible, 0
    elif 31 <= row['PCIAT-PCIAT_Total'] <= 49 and max_possible <= 49:
        return max_possible, 1
    elif 50 <= row['PCIAT-PCIAT_Total'] <= 79 and max_possible <= 79:
        return max_possible, 2
    elif row['PCIAT-PCIAT_Total'] >= 80 and max_possible >= 80:
        return max_possible, 3

    # 범위에 해당하지 않을 경우
    return max_possible, np.nan

# train 데이터프레임에 함수 적용
train[['recalc_total', 'recalc_sii']] = train.apply(
    recalculate_sii, axis=1, result_type='expand'
)

설명

  • 결측치를 포함한 최대 점수를 계산하여 SII 카테고리를 재분류합니다.
  • apply()를 통해 각 행에 대해 recalculate_sii() 함수를 적용합니다.
  • 결과적으로 재계산된 총점(recalc_total)재분류된 SII(recalc_sii)를 데이터프레임에 추가합니다.

3. 이상 행(Mismatch Rows) 분석 🔍

mismatch_rows = train[
    (train['recalc_sii'] != train['sii']) & train['sii'].notna()
]

mismatch_rows[PCIAT_cols + [
    'PCIAT-PCIAT_Total', 'sii', 'recalc_sii'
]].style.applymap(
    lambda x: 'background-color: #FFC0CB' if pd.isna(x) else ''
)

설명

  • Mismatch Rows: 기존 sii와 재계산된 recalc_sii가 일치하지 않는 행을 필터링합니다.
  • style.applymap(): 결측치(NaN)가 있는 셀에 배경색(핑크색)을 추가하여 직관적으로 확인할 수 있도록 합니다.

4. 데이터 정제 및 시각화 🎨

데이터 정제

# 기존 SII 값을 재계산 값으로 교체
train['sii'] = train['recalc_sii']

# 완전한 응답의 총합만 유지, 결측치가 있으면 NaN으로 설정
train['complete_resp_total'] = train['PCIAT-PCIAT_Total'].where(
    train[PCIAT_cols].notna().all(axis=1), np.nan
)

# SII 범주화 및 순서 지정
sii_map = {0: '0 (None)', 1: '1 (Mild)', 2: '2 (Moderate)', 3: '3 (Severe)'}
train['sii'] = train['sii'].map(sii_map).fillna('Missing')
sii_order = ['Missing', '0 (None)', '1 (Mild)', '2 (Moderate)', '3 (Severe)']
train['sii'] = pd.Categorical(train['sii'], categories=sii_order, ordered=True)

# 불필요한 열 삭제
train.drop(columns='recalc_sii', inplace=True)

시각화

sii_counts = train['sii'].value_counts().reset_index()
total = sii_counts['count'].sum()
sii_counts['percentage'] = (sii_counts['count'] / total) * 100

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# SII 분포 시각화
sns.barplot(x='sii', y='count', data=sii_counts, palette='Blues_d', ax=axes[0])
axes[0].set_title('Distribution of Severity Impairment Index (sii)', fontsize=14)
for p in axes[0].patches:
    height = p.get_height()
    percentage = sii_counts.loc[sii_counts['count'] == height, 'percentage'].values[0]
    axes[0].text(
        p.get_x() + p.get_width() / 2,
        height + 5, f'{int(height)} ({percentage:.1f}%)',
        ha="center", fontsize=12
    )

# PCIAT_Total 분포 시각화
sns.histplot(train['complete_resp_total'].dropna(), bins=20, ax=axes[1])
axes[1].set_title('Distribution of PCIAT_Total', fontsize=14)
axes[1].set_xlabel('PCIAT_Total for Complete PCIAT Responses')

plt.tight_layout()
plt.show()

설명

  • SII 분포 시각화: 각 SII 수준별 분포를 막대 그래프로 나타내고, 각 카테고리의 비율(%)을 표시합니다.
  • PCIAT_Total 분포 시각화: 완전한 응답(complete_resp_total)에 대해 점수 분포를 히스토그램으로 표시합니다.

주요 결과 📋

  1. SII 재계산: 데이터 결측치를 고려한 점수 재계산 및 SII 분류 결과를 확인했습니다.
  2. 이상 행 식별: 기존 SII 값과 불일치하는 행을 추출하여 검토하였습니다.
  3. 시각화: SII와 PCIAT_Total의 분포를 시각화하여 데이터를 더 직관적으로 이해할 수 있도록 정리하였습니다.

P.S 🤔

데이터 컬럼이 너무 많아서 분석할 내용이 많다 보니 하나씩 공부해가는 과정이라 EDA 작업이 늦어지고 있네요,,,
다음 글에서는 다른 컬럼들의 정보를 바탕으로 추가적인 EDA를 진행해볼게요. 🚀

profile
AI로 유용한 서비스 개발을 꿈꾸는 A린이

0개의 댓글