파이썬으로 탐색적 데이터 분석(EDA)을 해보자

해당 포스팅에서는 load_wine 데이터를 사용한다.

import pandas as pd
import numpy as np
from sklearn.datasets import load_wine

# 데이터 불러오기
df, y = load_wine(as_frame=True, return_X_y=True)
df["quality"] = y

필요한 패키지를 불러오고 시작해야 한다.

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()

EDA란?

데이터 분포, 중앙값·사분위수·상관관계 등을 시각화를 통해 탐색하는 기법이다.

실제 현실의 데이터들은 깔끔하지 않아서 모델링 과정보다, 데이터를 처리하고 정리하는데 더 많은 시간을 쏟을 수 있다.

그만큼 데이터를 정제하는 것은 중요한 과정이고, 그 전에 데이터가 어떤 특성을 가지는지 살펴보는 것이 그 시작이다.

상관관계

# 상관관계 저장
corr = df.corr()

# 그래프 그리기
plt.figure(figsize=(10, 8))
sns.heatmap(
    corr,
    annot=True,
    fmt=".2f",
    cmap="coolwarm",
    mask=np.triu(np.ones_like(corr, dtype=bool)),
    square=True,
    cbar=True,
)
plt.title("Correlation between features")
plt.show()

도수 분포표

plt.figure(figsize=(6, 4))
sns.histplot(data=df, x='flavanoids', bins=20, kde=True)
plt.title('Flavanoids Distribution')
plt.show()

산점도

sns.scatterplot(
    data=df,
    x='flavanoids',
    y='total_phenols',
    hue='quality',
    alpha=0.7
)

plt.show()

이렇게 그래프 한개씩 그리지 말고 한꺼번에 다 그리고 싶다면? pairplot 을 사용하면 된다.

# 1. 상관관계 행렬 계산
corr = df.corr(numeric_only=True)

# 2. 예를 들어 flavanoids와 상관 높은 feature 4~5개를 선택
# Exclude 'quality' from the top features calculation as it's the target variable
top_features = corr['flavanoids'].abs().sort_values(ascending=False).drop('quality').head(5).index
print(top_features)

# 3. 선택한 feature들과 quality를 함께 pairplot으로 시각화
# Create a new DataFrame with only the selected features and the quality column
plot_df = df[top_features.tolist() + ['quality']]

sns.pairplot(
    plot_df,
    hue='quality',
    palette='mako',
    diag_kind='kde'
)
plt.show()

결측치 & 이상치 확인

데이터가 누락되거나 잘못 기입된 경우는 없는지 확인해야 한다.

실제로 데이터를 처리해보시면 이러한 경우가 비일비재하기 때문에 확인하는 것이 필수적이다.

  1. 결측치 확인 결측치는 데이터가 비어 있는 경우를 말한다.

    처리 방법에는 크게 두 가지가 있다.

    첫째, 결측치가 있는 행이나 열을 통째로 삭제하는 방법이 있다. 데이터가 충분히 많고 결측이 일부일 때는 유용하지만, 데이터 손실이 클 수 있다.

    둘째, 결측 값을 다른 값으로 채우는 방법이 있다. 숫자형 데이터의 경우 평균값, 중앙값, 최빈값으로 채우거나, 시계열 데이터에서는 이전 값이나 다음 값으로 채우는 방법을 쓴다. 더 나아가 머신러닝 모델로 결측치를 예측해 채우는 고급 기법도 있다.

     df.isnull().sum()
    
  2. 이상치 확인 이상치는 다른 데이터와 비교했을 때 값이 너무 크거나 작아서 눈에 띄는 데이터를 말한다.

    이상치는 데이터 입력 실수, 측정 오류, 혹은 정말 드문 특별한 경우 때문에 발생할 수 있다.

    분석 전에 이런 값을 확인하고, 잘못된 값이면 제거하거나 경계값으로 바꾸고, 의미가 있다면 그대로 두는 것이 좋다.

    IQR(사분위 범위)은 이상치를 찾는 대표적인 방법 중 하나이다!

     def detect_outliers_iqr(data, column):
         Q1 = data[column].quantile(0.25)
         Q3 = data[column].quantile(0.75)
         IQR = Q3 - Q1
         lower_bound = Q1 - 1.5 * IQR
         upper_bound = Q3 + 1.5 * IQR
         return data[(data[column] < lower_bound) | (data[column] > upper_bound)]
    
     outliers_alcohol = detect_outliers_iqr(df_missing, 'alcohol')
     print(f"alcohol 이상치 개수: {len(outliers_alcohol)}")
    
     # boxplot으로 이상치 확인
     sns.boxplot(x=df_missing['alcohol'])
     plt.title("Outliers of Alcohol")
     plt.show()
    

무엇보다 중요한 점은, 결측치나 이상치를 무조건 제거하거나 바꾸기 전에 왜 생겼는지를 먼저 확인하는 것이다.

실측 오류라면 제거하는 것이 맞지만, 의미 있는 값이라면 보존하거나 변환하는 것이 더 적절할 수 있다.

그리고 때로는 결측 그 자체가 데이터 분석에서 중요한 특징이 될 수도 있다.