0Pricing
Pandas & NumPy Academy · 课时

数据清洗与特征工程

应用高级清洗检查清单,构造日期特征和比率列,并使用断言验证清洗后的数据集

数据清洗与特征工程 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Loading the Audited Dataset

Continuing the capstone project, load the clean Parquet checkpoint saved in the previous step. This decouples the cleaning stage from ingestion — you can iterate on cleaning logic without re-running the slow merge and parse operations. Read the clean_orders Parquet and verify the row count and dtypes match expectations from the audit summary. The Parquet file preserves all dtypes including categorical columns, so no re-casting is needed.

import pandas as pd

# Load from checkpoint
df = pd.read_parquet('output/clean_orders.parquet')
print(f'Loaded: {df.shape}')
print(df.dtypes)
print(f'Date range: {df["order_date"].min().date()} to {df["order_date"].max().date()}')

Applying the Advanced Cleaning Checklist

With the merged dataset loaded, apply the advanced cleaning checklist: remove exact and partial duplicates on order_id, cap outliers in unit_price using IQR fencing, standardise inconsistent category values (e.g., 'Electronics' vs 'electronics' vs 'ELECTRONIC'), and validate that quantity × unit_price is always positive for normal orders. Each step is a function that accepts and returns a DataFrame, making the pipeline testable and reversible.

import pandas as pd
import numpy as np

def remove_duplicates(df):
    n_before = len(df)
    df = df.drop_duplicates(subset=['order_id'], keep='first')
    print(f'Duplicates removed: {n_before - len(df)}')
    return df

def standardise_categories(df):
    df['category'] = (df['category']
                      .astype(str)
                      .str.strip()
                      .str.title())
    return df

def cap_price_outliers(df):
    q1, q3 = df['unit_price'].quantile([0.25, 0.75])
    iqr = q3 - q1
    upper = q3 + 3 * iqr
    df['unit_price'] = df['unit_price'].clip(upper=upper)
    return df

df = remove_duplicates(df)
df = standardise_categories(df)
df = cap_price_outliers(df)
print('Cleaning complete.')

Engineering Date Features

Extract temporal features from the order date using the .dt accessor. Create year, month, quarter, day_of_week, and week_of_year columns. These features power groupby analyses (monthly revenue), time-based filters (Q3 only), and visualisations. Also create a year_month string column (e.g., '2024-06') as a human-readable period label for chart axes.

import pandas as pd

df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['quarter'] = df['order_date'].dt.quarter
df['day_of_week'] = df['order_date'].dt.dayofweek  # 0=Monday
df['week'] = df['order_date'].dt.isocalendar().week.astype('int32')
df['year_month'] = df['order_date'].dt.to_period('M').astype(str)

print('Date features created:')
print(df[['order_date', 'year', 'month', 'quarter', 'year_month']].head())

Computing Line-Item Revenue

The most fundamental feature in a sales dataset is line-item revenue: revenue = quantity × unit_price. Create this as a new column. Also create a gross_margin column if cost data is available: margin = (price - cost) / price. These derived columns are the building blocks of all revenue KPIs. Always use vectorised column operations rather than loops — a single assignment on the full column is orders of magnitude faster than iterating row by row.

import pandas as pd

# Line-item revenue
df['revenue'] = (df['quantity'] * df['unit_price']).astype('float32')

# Gross margin (if unit_cost column exists)
if 'unit_cost' in df.columns:
    df['gross_margin'] = (df['unit_price'] - df['unit_cost']) / df['unit_price']

# Discount flag: orders with more than 20% off list price
if 'list_price' in df.columns:
    df['is_discounted'] = df['unit_price'] < df['list_price'] * 0.8

print('Revenue stats:')
print(df['revenue'].describe().round(2))

Customer Cohort Assignment

A cohort is a group of customers who share a characteristic — typically the time period they first made a purchase. Assign each customer to their acquisition cohort by finding their first order date. Use groupby('customer_id')['order_date'].min() to compute the first order date per customer, then create a cohort_month column by converting it to a year-month period. This cohort label is the foundation of the retention matrix in the next lesson.

import pandas as pd

# First purchase date per customer
first_purchase = (
    df.groupby('customer_id')['order_date']
    .min()
    .dt.to_period('M')
    .astype(str)
    .rename('cohort_month')
)

# Merge back onto orders
df = df.merge(first_purchase, on='customer_id', how='left')
print('Cohort distribution (top 5):')
print(df['cohort_month'].value_counts().head())
print(f'Distinct cohorts: {df["cohort_month"].nunique()}')

Customer Lifetime Value Features

Compute customer-level summary features: total orders, total revenue, average order value, days since first/last purchase, and number of distinct categories purchased. Merge these back onto the main DataFrame as customer-level enrichment columns. These features are used for segmentation (e.g., high-value vs. low-value customers) and as inputs to machine learning models predicting churn or upsell probability.

import pandas as pd

customer_stats = df.groupby('customer_id').agg(
    total_orders=('order_id', 'nunique'),
    total_revenue=('revenue', 'sum'),
    avg_order_value=('revenue', 'mean'),
    categories_purchased=('category', 'nunique'),
    first_order=('order_date', 'min'),
    last_order=('order_date', 'max')
).reset_index()

customer_stats['days_as_customer'] = (
    (customer_stats['last_order'] - customer_stats['first_order'])
    .dt.days
)

print(customer_stats.describe().round(2))

Schema Validation with Assertions

After engineering features, run schema validation assertions to confirm the data meets expectations before passing it to the analysis stage. Check that all expected columns exist, revenue is non-negative for normal orders, cohort_month is non-null, and year_month matches the analysis year. These assertions act as a contract: if any fails, the pipeline stops immediately with a clear error message rather than silently producing wrong results.

import pandas as pd

def validate_clean_df(df):
    required_cols = ['order_id', 'customer_id', 'revenue', 'year_month',
                     'cohort_month', 'category', 'region', 'order_date']
    missing = [c for c in required_cols if c not in df.columns]
    assert not missing, f'Missing columns: {missing}'

    assert (df['revenue'] >= 0).all(), 'Negative revenue found'
    assert df['cohort_month'].notna().all(), 'Null cohort_month values'
    assert df['order_date'].notna().all(), 'Null order dates'
    print(f'Validation passed: {len(df):,} rows, {len(df.columns)} columns')

validate_clean_df(df)

Handling Low-Frequency Categories

In real datasets, some categories or regions appear only a handful of times — too few for meaningful analysis. Replace low-frequency values with 'Other' to avoid charts cluttered with dozens of single-order categories. A practical threshold: values appearing in fewer than 0.5% of rows are collapsed. This is also important for machine learning: one-hot encoding 200 rare categories wastes memory and adds noise.

import pandas as pd

def collapse_rare_values(df, col, min_pct=0.005):
    threshold = len(df) * min_pct
    counts = df[col].value_counts()
    rare = counts[counts < threshold].index
    n_rare = len(rare)
    df[col] = df[col].apply(lambda x: 'Other' if x in rare else x)
    print(f'{col}: collapsed {n_rare} rare values into "Other"')
    return df

df = collapse_rare_values(df, 'category', min_pct=0.005)
df = collapse_rare_values(df, 'region', min_pct=0.005)
print('Category distribution after collapsing:')
print(df['category'].value_counts())

Saving the Feature-Engineered Dataset

Save the fully cleaned and feature-engineered DataFrame as a Parquet checkpoint. This is the analysis-ready dataset — the output of all ingestion, cleaning, and feature engineering steps. Subsequent pipeline stages (KPI computation, visualisation, reporting) read from this checkpoint. The checkpoint also serves as a deliverable: it can be shared with team members or uploaded to a data lake for others to query with SQL or Pandas.

import pandas as pd

# Convert category columns back to Categorical for memory efficiency
for col in ['category', 'region', 'acquisition_channel']:
    if col in df.columns:
        df[col] = df[col].astype('category')

# Save analysis-ready dataset
df.to_parquet('output/analysis_ready.parquet', index=False)

# Also save customer stats for segmentation
customer_stats.to_parquet('output/customer_stats.parquet', index=False)

print(f'Analysis-ready dataset: {df.shape}')
print(f'Memory usage: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')

Feature Engineering Summary

Good feature engineering balances adding predictive signal with keeping the pipeline interpretable and testable. The features created in this stage — revenue, date parts, cohort_month, customer stats, collapsed categories — were all driven by the analysis goals defined in the project setup. Resist the temptation to create dozens of features speculatively. For each feature, ask: will this be used in at least one KPI or visualisation? If not, defer it. Keep the analysis-ready dataset lean and purposeful.

import pandas as pd

# Summary of engineered features
df = pd.read_parquet('output/analysis_ready.parquet')

original_cols = ['order_id', 'customer_id', 'order_date', 'quantity', 'unit_price']
engineered_cols = [c for c in df.columns if c not in original_cols]

print('Original columns:', original_cols)
print('Engineered features:', engineered_cols)
print(f'Total columns: {len(df.columns)}')
print(f'Total rows: {len(df):,}')

Documenting Decisions in Code

For every non-obvious cleaning or engineering decision, add a comment explaining the why. Future you (or a team member) will not remember why you set the IQR multiplier to 3 instead of 1.5, or why you used 0.5% as the rare-category threshold. Inline comments and a decisions log (a simple list in the project README or a markdown file) make the pipeline maintainable and auditable. Clean, documented code is the true deliverable — the output files are just its consequence.

# Engineering decisions log
DECISIONS = '''
# Data Cleaning & Feature Engineering Decisions

## Duplicate handling
Kept first occurrence of duplicate order_id (most likely the original order).

## Outlier capping
Unit price capped at Q3 + 3*IQR (not 1.5*IQR) because price distribution
has legitimate high-value enterprise orders that should not be removed.

## Rare category threshold: 0.5%
Values below 0.5% of total orders collapsed to "Other" to keep charts readable
and avoid spurious significance in category-level tests.

## Cohort assignment
Cohort = first purchase calendar month (not signup month), because many users
sign up but do not purchase until months later.
'''
print(DECISIONS)

Quick Check

Test your understanding of Data Analysis concepts from this lesson.

Lesson Recap

In this lesson you learned: modular cleaning functions (remove duplicates, cap outliers, standardise categories) each accept and return a DataFrame for easy testing, feature engineering created date parts, line-item revenue, customer cohorts, and summary statistics, and schema validation assertions guard the transition from cleaning to analysis. Next up we compute the project's core KPIs: monthly cohort retention, product revenue, and rolling active users.

常见问题解答

「数据清洗与特征工程」课时是免费的吗?

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

「数据清洗与特征工程」这节课中我会学到什么?

应用高级清洗检查清单,构造日期特征和比率列,并使用断言验证清洗后的数据集 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Pandas & NumPy Academy 需要有经验吗?

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

「数据清洗与特征工程」课时需要多长时间?

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

我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?

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

此课程中的所有课时

  1. 项目设置与数据导入
  2. 数据清洗与特征工程
  3. 分析与 KPI 计算
  4. 最终可视化与报告导出
← 返回 Pandas & NumPy Academy