데이터 정제와 탐색적 데이터 분석
원시 데이터 세트를 불러오고, 분포와 상관관계를 분석하며, 데이터 품질 문제를 식별하고, 재현 가능한 Jupyter 노트북에 결과를 기록합니다.
데이터 정제와 탐색적 데이터 분석은(는) CoddyKit의 무료 Machine Learning Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Machine Learning Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
What Is Exploratory Data Analysis?
Exploratory Data Analysis (EDA) is the practice of profiling a dataset before modelling to understand its structure, distributions, relationships, and quality issues. Coined by John Tukey, EDA follows a simple principle: let the data speak. Rushing past EDA and jumping straight to modelling is the second most common reason ML projects fail, after poor problem scoping. EDA prevents you from building models on faulty foundations.
Loading and First Inspection
Always start with a structural inspection: how many rows, columns, and what data types? Use df.shape, df.dtypes, df.head(), and df.info(). Look for columns that appear numeric but are stored as object (strings), and columns that appear categorical but are encoded as integers. Mismatched dtypes cause silent bugs downstream when scikit-learn treats an integer-encoded category as a continuous variable.
import pandas as pd
import numpy as np
# Load dataset
df = pd.read_csv('customer_churn.csv')
print('Shape:', df.shape)
print('\nData types:')
print(df.dtypes)
print('\nFirst 5 rows:')
print(df.head())
print('\nSummary info:')
df.info()Univariate Analysis: Distributions
Univariate analysis examines one variable at a time. For numeric features, plot histograms and compute summary statistics (mean, median, std, skewness). Highly skewed distributions (skewness > 2) often benefit from a log transform before modelling. For categorical features, plot bar charts of value counts. Categories that appear in fewer than 1% of rows may cause issues with one-hot encoding and stratified splitting.
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Numeric: histogram of account age
df['account_age_days'].hist(bins=40, ax=axes[0])
axes[0].set_title('Account age distribution')
axes[0].set_xlabel('Days')
# Categorical: churn rate by plan type
df.groupby('plan_type')['churned'].mean().plot(kind='bar', ax=axes[1])
axes[1].set_title('Churn rate by plan type')
axes[1].set_ylabel('Churn rate')
plt.tight_layout()
plt.savefig('univariate.png', dpi=150)Summary Statistics Table
df.describe() produces count, mean, std, min, quartiles, and max for every numeric column. Examine it carefully: a max value orders of magnitude above the 99th percentile signals outliers. A min of zero in a 'days since last purchase' column may mean the customer purchased today — or it may be a sentinel for missing data. Understanding these edge cases prevents silent errors in downstream preprocessing.
stats = df.describe(percentiles=[0.01, 0.25, 0.5, 0.75, 0.99])
print(stats.T) # transpose for readability
# Flag suspicious columns
for col in df.select_dtypes(include='number').columns:
skew = df[col].skew()
pct99 = df[col].quantile(0.99)
max_val = df[col].max()
if max_val > 5 * pct99:
print(f'OUTLIER WARNING: {col} — max ({max_val:.1f}) >> 99th pct ({pct99:.1f}), skew={skew:.2f}')Missing Value Analysis
Missing values must be profiled before imputation decisions are made. Compute the percentage of nulls per column with df.isnull().mean(). Columns with more than 50% missing may need to be dropped entirely. Understand the mechanism of missingness: is it missing completely at random (MCAR), or is it missing not at random (MNAR) — e.g., customers who churned deleted their account info? MNAR missingness is itself informative and should be encoded as a binary indicator.
missing = df.isnull().mean().sort_values(ascending=False)
missing_pct = missing[missing > 0] * 100
print('Missing value percentages:')
print(missing_pct.round(1))
import matplotlib.pyplot as plt
missing_pct.plot(kind='barh', figsize=(8, 5))
plt.xlabel('% missing')
plt.title('Missing values by column')
plt.tight_layout()
plt.savefig('missing.png', dpi=150)Bivariate Analysis: Correlations
Bivariate analysis examines relationships between pairs of variables. For numeric-numeric relationships, compute a correlation matrix and visualise it as a heat map with seaborn.heatmap. Correlations above 0.95 between two features signal multicollinearity — both features carry almost identical information, so one can be dropped without losing predictive power. Also compute point-biserial correlations between numeric features and the binary target to identify the most predictive features upfront.
import seaborn as sns
import matplotlib.pyplot as plt
numeric_df = df.select_dtypes(include='number')
corr = numeric_df.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr, annot=True, fmt='.2f', cmap='coolwarm', center=0)
plt.title('Correlation matrix')
plt.tight_layout()
plt.savefig('corr_heatmap.png', dpi=150)
# Highest corr pairs (excluding self-correlation)
high_corr = (
corr.where(np.triu(np.ones(corr.shape), k=1).astype(bool))
.stack().abs().sort_values(ascending=False)
)
print('Top correlated pairs:')
print(high_corr.head(5))Target Variable Analysis
Always analyse the target variable separately. For binary classification, compute the positive class rate (df['churned'].mean()). Rates below 5% or above 95% indicate severe imbalance that affects algorithm choice and evaluation metrics. For regression targets, check normality — skewed targets often benefit from a log transform before training, especially for tree-based models which are immune, but critical for linear regression.
target = 'churned'
class_dist = df[target].value_counts(normalize=True)
print('Class distribution:')
print(class_dist)
print(f'\nPositive class rate: {df[target].mean():.3f}')
print(f'Imbalance ratio: {class_dist.max() / class_dist.min():.1f}:1')
# Visual
df[target].value_counts().plot(kind='bar')
import matplotlib.pyplot as plt
plt.title('Target class distribution')
plt.ylabel('Count')
plt.xticks([0, 1], ['Retained', 'Churned'], rotation=0)
plt.tight_layout()
plt.savefig('target_dist.png', dpi=150)Outlier Detection and Treatment
Outliers can distort model training, especially for distance-based models (KNN, SVM) and linear regression. Use the IQR method (flag values outside [Q1 - 1.5·IQR, Q3 + 1.5·IQR]) or Z-score (flag values with |z| > 3) for initial detection. For each flagged outlier, investigate: is it a data entry error, a legitimate extreme value, or a sensor malfunction? Legitimate extreme values should be kept; errors should be corrected or removed.
def iqr_outliers(series):
Q1, Q3 = series.quantile(0.25), series.quantile(0.75)
IQR = Q3 - Q1
lower, upper = Q1 - 1.5 * IQR, Q3 + 1.5 * IQR
outlier_mask = (series < lower) | (series > upper)
return outlier_mask, lower, upper
for col in df.select_dtypes(include='number').columns:
mask, lo, hi = iqr_outliers(df[col])
n_out = mask.sum()
if n_out > 0:
print(f'{col}: {n_out} outliers ({n_out/len(df)*100:.1f}%), '
f'valid range=[{lo:.2f}, {hi:.2f}]')Feature-Target Relationship Plots
For classification tasks, visualise how each numeric feature's distribution differs between classes using a violin plot or box plot grouped by the target. Features where the distributions strongly separate the two classes are likely to be predictive. For categorical features, a grouped bar chart of churn rate per category value quickly reveals which categories are associated with higher risk.
import seaborn as sns
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Numeric feature vs target: violin plot
sns.violinplot(
data=df, x='churned', y='account_age_days',
palette=['#2196F3', '#F44336'], ax=axes[0]
)
axes[0].set_xticklabels(['Retained', 'Churned'])
axes[0].set_title('Account age by churn status')
# Categorical feature vs target: bar plot
df.groupby('plan_type')['churned'].mean().plot(kind='bar', ax=axes[1])
axes[1].set_title('Churn rate by plan type')
axes[1].set_ylabel('Churn rate')
plt.tight_layout()
plt.savefig('feature_target.png', dpi=150)Documenting EDA Findings
EDA findings must be documented in a reproducible Jupyter notebook shared with the team. At minimum, document: columns dropped and why, imputation decisions per column, outlier treatment, class imbalance magnitude, top predictive features, and any data quality issues escalated to the data engineering team. This notebook becomes the data quality section of the eventual model card and is invaluable when debugging production regressions months later.
# EDA findings summary (add as a markdown cell in the notebook)
findings = {
'dropped_columns': ['customer_id (identifier)', 'last_login_ip (PII, not predictive)'],
'imputation': {
'days_since_support_contact': 'median (12% missing, MCAR)',
'contract_end_days': 'mode (3% missing)'
},
'outliers': 'total_spend: 14 values > $50k capped at 99th percentile ($48,200)',
'class_imbalance': '8.3% churn rate — use SMOTE or class_weight=balanced',
'top_features': ['days_since_last_purchase', 'total_spend_90d', 'support_tickets'],
'escalations': ['contract_type column has 847 unmapped legacy codes — check with engineering']
}
for key, val in findings.items():
print(f'{key}: {val}')Automated EDA Tools
For large datasets with hundreds of features, manual EDA is impractical. ydata-profiling (formerly pandas-profiling) generates an interactive HTML report with distributions, correlations, missing values, and outlier alerts for every column with a single function call. sweetviz produces comparison reports across train/test splits or target class segments. Use these as a starting point, but always follow up with domain-specific custom plots for the most important features.
# ydata-profiling: one line EDA report
# pip install ydata-profiling
from ydata_profiling import ProfileReport
profile = ProfileReport(
df,
title='Customer Churn EDA Report',
explorative=True
)
profile.to_file('eda_report.html')
print('Report saved to eda_report.html')
# sweetviz: compare train vs test distribution
# pip install sweetviz
import sweetviz as sv
report = sv.analyze(df, target_feat='churned')
report.show_html('sweetviz_report.html')Quick Check
Test your understanding of Machine Learning with Python concepts from this lesson.
Lesson Recap
In this lesson you learned: EDA profiles distributions, relationships, missing values, and outliers before any modelling, bivariate analysis (correlations, feature-target plots) identifies the most predictive features, and EDA findings must be documented in a reproducible notebook to guide preprocessing decisions and serve as the data quality record. Next up we run a model selection tournament to compare five algorithms on the same processed dataset.
자주 묻는 질문
“데이터 정제와 탐색적 데이터 분석” 강의는 무료인가요?
네 — “데이터 정제와 탐색적 데이터 분석” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Machine Learning Academy 강의 전체를 잠금 해제할 수 있습니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“데이터 정제와 탐색적 데이터 분석”에서 뭘 배우나요?
원시 데이터 세트를 불러오고, 분포와 상관관계를 분석하며, 데이터 품질 문제를 식별하고, 재현 가능한 Jupyter 노트북에 결과를 기록합니다. 브라우저에서 직접 실행하는 실습 코드로 Machine Learning Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Machine Learning Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Machine Learning Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“데이터 정제와 탐색적 데이터 분석” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Machine Learning Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Machine Learning Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 프로젝트 범위 설정: 문제와 성공 기준 정의
- 데이터 정제와 탐색적 데이터 분석
- 모델 선택 토너먼트: 다섯 가지 알고리즘 비교
- 최종 모델 패키징, 문서화 및 발표