0Pricing
Machine Learning Academy · 课时

数据整理与探索性数据分析

学习者将加载原始数据集,分析分布与相关性,识别数据质量问题,并在可复现的 Jupyter 笔记本中记录发现。

数据整理与探索性数据分析 是 CoddyKit 上的免费 Machine Learning Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 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.

常见问题解答

「数据整理与探索性数据分析」课时是免费的吗?

是的 — 「数据整理与探索性数据分析」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Machine Learning Academy 课程的其余内容,请升级到 CoddyKit PRO。 Machine Learning Academy 课程共包含 4 节课。

「数据整理与探索性数据分析」这节课中我会学到什么?

学习者将加载原始数据集,分析分布与相关性,识别数据质量问题,并在可复现的 Jupyter 笔记本中记录发现。 你通过在浏览器中直接运行的动手代码来练习 Machine Learning Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Machine Learning Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Machine Learning Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「数据整理与探索性数据分析」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Machine Learning Academy 课中编写并运行代码吗?

能。每节 Machine Learning Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 项目范围界定:定义问题与成功标准
  2. 数据整理与探索性数据分析
  3. 模型选择竞赛:比较五种算法
  4. 打包、记录与展示最终模型
← 返回 Machine Learning Academy