引言:为什么需要进阶Python数据分析?

Python作为数据科学领域的首选语言,其生态系统已经发展得非常成熟。对于已经掌握基础数据分析技能的学习者来说,进阶到精通水平意味着能够更高效地处理复杂数据、构建自动化分析流程,并通过实际项目解决真实世界的问题。

本课程将带你从基础的Pandas操作进阶到高级数据处理技巧,从简单的可视化到构建交互式仪表板,从单机分析到大数据处理。我们将通过详尽的代码示例和完整的实战项目,帮助你真正掌握Python数据分析的核心技巧。

第一部分:Pandas高级数据处理技巧

1.1 高效的数据读取与内存优化

在处理大型数据集时,内存优化是首要考虑的问题。让我们看看如何通过优化数据类型来显著减少内存占用。

import pandas as pd
import numpy as np

# 创建一个示例数据集
def create_large_dataset(rows=1000000):
    return pd.DataFrame({
        'id': range(rows),
        'category': np.random.choice(['A', 'B', 'C', 'D'], rows),
        'value': np.random.randn(rows),
        'timestamp': pd.date_range('2020-01-01', periods=rows, freq='T')
    })

# 原始数据类型检查
df = create_large_dataset()
print("原始内存使用:")
print(df.info(memory_usage='deep'))

# 优化数据类型
def optimize_memory(df):
    # 优化整数类型
    for col in df.select_dtypes(include=['int64']).columns:
        df[col] = pd.to_numeric(df[col], downcast='integer')
    
    # 优化浮点数类型
    for col in df.select_dtypes(include=['float64']).columns:
        df[col] = pd.to_numeric(df[col], downcast='float')
    
    # 优化对象类型(分类数据)
    for col in df.select_dtypes(include=['object']).columns:
        if len(df[col].unique()) / len(df[col]) < 0.5:  # 如果唯一值少于50%
            df[col] = df[col].astype('category')
    
    return df

df_optimized = optimize_memory(df.copy())
print("\n优化后内存使用:")
print(df_optimized.info(memory_usage='deep'))

1.2 高效的分组与聚合操作

在处理大规模数据时,groupby操作可能会非常耗时。以下是一些优化技巧:

# 创建一个包含多个分组键的大数据集
np.random.seed(42)
large_df = pd.DataFrame({
    'region': np.random.choice(['North', 'South', 'East', 'West'], 1000000),
    'product': np.random.choice(['P1', 'P2', 'P3', 'P4', 'P5'], 1000000),
    'sales': np.random.exponential(scale=100, size=1000000),
    'quantity': np.random.randint(1, 100, 1000000)
})

# 方法1: 基础groupby
result1 = large_df.groupby(['region', 'product']).agg({
    'sales': ['sum', 'mean', 'count'],
    'quantity': ['mean', 'sum']
})

# 方法2: 使用numba加速(需要安装numba)
from numba import jit

@jit(nopython=True)
def compute_metrics(sales, quantity):
    total_sales = np.sum(sales)
    avg_sales = np.mean(sales)
    total_qty = np.sum(quantity)
    avg_qty = np.mean(quantity)
    count = len(sales)
    return total_sales, avg_sales, total_qty, avg_qty, count

# 方法3: 使用pandas的transform进行高效计算
large_df['sales_rank'] = large_df.groupby('region')['sales'].rank(ascending=False)
large_df['regional_avg_sales'] = large_df.groupby('region')['sales'].transform('mean')

# 性能比较
import time

start = time.time()
result_method1 = large_df.groupby(['region', 'product']).agg({
    'sales': ['sum', 'mean'],
    'quantity': ['mean']
})
time_method1 = time.time() - start

print(f"方法1耗时: {time_method1:.4f}秒")
print("方法1结果形状:", result_method1.shape)

1.3 复杂索引操作与多级索引处理

多级索引(MultiIndex)是Pandas中强大但常被忽视的功能,特别适合处理高维数据。

# 创建多级索引数据
arrays = [
    ['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
    ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']
]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df_multi = pd.DataFrame(np.random.randn(8, 4), index=index, columns=['A', 'B', 'C', 'D'])

# 多级索引的切片操作
print("选择第一层为'bar'的数据:")
print(df_multi.loc['bar'])

print("\n选择第一层为'bar'且第二层为'one'的数据:")
print(df_multi.loc[('bar', 'one')])

# 多级索引的交换层级
df_swapped = df_multi.swaplevel(0, 1)
print("\n交换层级后的数据:")
print(df_swapped.sort_index())

# 多级索引的聚合
print("\n按第一层索引求和:")
print(df_multi.groupby(level=0).sum())

# 创建透视表(多级索引的另一种形式)
pivot_df = pd.DataFrame({
    'A': ['one', 'one', 'two', 'two'],
    'B': ['x', 'y', 'x', 'y'],
    'C': [1, 2, 3, 4],
    'D': [5, 6, 7, 8]
})
pivot_table = pivot_df.pivot_table(index='A', columns='B', values=['C', 'D'])
print("\n透视表结果:")
print(pivot_table)

第二部分:高级数据可视化

2.1 Matplotlib高级定制

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib.patches import Rectangle

# 创建复杂子图布局
fig = plt.figure(figsize=(15, 10))
gs = gridspec.GridSpec(2, 3, figure=fig)

ax1 = fig.add_subplot(gs[0, :2])  # 第一行,前两列
ax2 = fig.add_subplot(gs[0, 2])   # 第一行,第三列
ax3 = fig.add_subplot(gs[1, :])   # 第二行,所有列

# 数据准备
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.exp(-x/5) * np.sin(x)

# 绘制第一个子图:带标注的线图
ax1.plot(x, y1, 'b-', linewidth=2, label='sin(x)')
ax1.plot(x, y2, 'r--', linewidth=2, label='cos(x)')
ax1.axhline(y=0, color='k', linestyle=':', alpha=0.3)
ax1.axvline(x=np.pi, color='g', linestyle=':', alpha=0.3)
ax1.text(np.pi, 0.5, 'π', fontsize=12, ha='center')
ax1.set_title('Trigonometric Functions', fontsize=14, fontweight='bold')
ax1.legend()
ax1.grid(True, alpha=0.3)

# 绘制第二个子图:散点图
np.random.seed(42)
x_scatter = np.random.normal(0, 1, 200)
y_scatter = np.random.normal(0, 1, 200)
colors = np.random.rand(200)
sizes = 100 * np.random.rand(200)

scatter = ax2.scatter(x_scatter, y_scatter, c=colors, s=sizes, 
                     alpha=0.6, cmap='viridis')
ax2.set_title('Scatter Plot with Colorbar', fontsize=14, fontweight='bold')
plt.colorbar(scatter, ax=ax2, label='Color Value')

# 绘制第三个子图:柱状图与误差线
categories = ['A', 'B', 'C', 'D', 'E']
values = [25, 40, 30, 35, 28]
errors = [2, 3, 2.5, 2, 3]

bars = ax3.bar(categories, values, yerr=errors, capsize=5, 
               color='skyblue', edgecolor='navy', linewidth=1.5)
ax3.set_title('Bar Chart with Error Bars', fontsize=14, fontweight='bold')
ax3.set_ylabel('Value', fontsize=12)

# 在柱子上添加数值标签
for bar, value in zip(bars, values):
    height = bar.get_height()
    ax3.text(bar.get_x() + bar.get_width()/2., height + 1,
             f'{value}', ha='center', va='bottom', fontsize=10)

plt.tight_layout()
plt.show()

2.2 交互式可视化:Plotly高级应用

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

# 创建复杂的交互式图表
def create_interactive_dashboard():
    # 准备数据
    np.random.seed(42)
    dates = pd.date_range('2023-01-01', periods=100, freq='D')
    stock_data = pd.DataFrame({
        'Date': dates,
        'Stock_A': 100 + np.cumsum(np.random.randn(100) * 0.5),
        'Stock_B': 150 + np.cumsum(np.random.randn(100) * 0.8),
        'Stock_C': 80 + np.cumsum(np.random.randn(100) * 0.3)
    })
    
    # 创建子图
    fig = make_subplots(
        rows=2, cols=2,
        subplot_titles=('Stock A Performance', 'Stock B Performance', 
                       'Stock C Performance', 'Volume Comparison'),
        specs=[[{"secondary_y": False}, {"secondary_y": False}],
               [{"secondary_y": False}, {"type": "bar"}]]
    )
    
    # 添加折线图
    fig.add_trace(
        go.Scatter(x=stock_data['Date'], y=stock_data['Stock_A'],
                  mode='lines+markers', name='Stock A',
                  line=dict(color='blue', width=2),
                  marker=dict(size=4)),
        row=1, col=1
    )
    
    fig.add_trace(
        go.Scatter(x=stock_data['Date'], y=stock_data['Stock_B'],
                  mode='lines', name='Stock B',
                  line=dict(color='green', width=2)),
        row=1, col=2
    )
    
    fig.add_trace(
        go.Scatter(x=stock_data['Date'], y=stock_data['Stock_C'],
                  mode='lines', name='Stock C',
                  line=dict(color='red', width=2)),
        row=2, col=1
    )
    
    # 添加柱状图
    volumes = np.random.randint(1000, 5000, 100)
    fig.add_trace(
        go.Bar(x=stock_data['Date'], y=volumes,
               name='Volume', marker_color='purple'),
        row=2, col=2
    )
    
    # 更新布局
    fig.update_layout(
        height=800,
        title_text="Interactive Stock Dashboard",
        showlegend=True,
        hovermode='x unified'
    )
    
    # 添加范围滑块
    fig.update_xaxes(rangeslider_visible=True)
    
    return fig

# 创建并显示仪表板
dashboard = create_interactive_dashboard()
dashboard.show()

2.3 Seaborn统计可视化高级技巧

import seaborn as sns
from scipy import stats

# 设置风格
sns.set_style("whitegrid")

# 创建复杂的统计可视化
def create_statistical_plots():
    # 生成示例数据
    np.random.seed(42)
    data = pd.DataFrame({
        'group': np.repeat(['A', 'B', 'C', 'D'], 100),
        'value': np.concatenate([
            np.random.normal(0, 1, 100),
            np.random.normal(1, 1.5, 100),
            np.random.normal(2, 2, 100),
            np.random.normal(0.5, 1, 100)
        ]),
        'category': np.random.choice(['X', 'Y'], 400)
    })

    # 创建复杂图表布局
    fig, axes = plt.subplots(2, 2, figsize=(16, 12))
    
    # 1. 小提琴图 + 散点图
    sns.violinplot(data=data, x='group', y='value', ax=axes[0,0], 
                   palette="Set2", inner="quartile")
    sns.stripplot(data=data, x='group', y='value', ax=axes[0,0],
                  color='black', alpha=0.3, size=3)
    axes[0,0].set_title('Violin Plot with Strip Overlay')
    
    # 2. 箱线图 + 箱线图
    sns.boxplot(data=data, x='group', y='value', hue='category',
                ax=axes[0,1], palette="Set3")
    axes[0,1].set_title('Box Plot by Group and Category')
    
    # 3. 联合分布图
    sns.jointplot(data=data, x='value', y='group', kind='reg',
                  height=6, ax=axes[1,0])
    axes[1,0].set_title('Joint Distribution')
    
    # 4. 热力图(相关性矩阵)
    corr_data = np.random.randn(100, 5)
    corr_matrix = np.corrcoef(corr_data.T)
    sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0,
                ax=axes[1,1], xticklabels=['Var1', 'Var2', 'Var3', 'Var4', 'Var5'],
                yticklabels=['Var1', 'Var2', '3', 'Var4', 'Var5'])
    axes[1,1].set_title('Correlation Heatmap')
    
    plt.tight_layout()
    plt.show()

create_statistical_plots()

第三部分:时间序列分析进阶

3.1 时间序列数据处理与重采样

# 创建复杂的时间序列数据
def create_time_series_data():
    np.random.seed(42)
    dates = pd.date_range('2023-01-01', '2023-12-31', freq='H')
    
    # 创建基础趋势
    trend = np.linspace(100, 150, len(dates))
    
    # 添加季节性成分
    seasonal = 10 * np.sin(2 * np.pi * np.arange(len(dates)) / 24)
    
    # 添加周期性成分(每周模式)
    weekly = 5 * np.sin(2 * np.pi * np.arange(len(dates)) / (24 * 7))
    
    # 添加随机噪声
    noise = np.random.normal(0, 2, len(dates))
    
    # 组合成分
    values = trend + seasonal + weekly + noise
    
    return pd.DataFrame({
        'timestamp': dates,
        'value': values,
        'hour': dates.hour,
        'day_of_week': dates.dayofweek,
        'month': dates.month
    })

ts_data = create_time_series_data()

# 高级重采样操作
def advanced_resampling(df):
    # 1. 小时到日均值(包含多种统计量)
    daily_stats = df.resample('D', on='timestamp').agg({
        'value': ['mean', 'std', 'min', 'max', 'count']
    })
    
    # 2. 小时到周均值,保留周几的信息
    df['week_number'] = df['timestamp'].dt.isocalendar().week
    df['year'] = df['timestamp'].dt.year
    
    weekly_pattern = df.groupby(['year', 'week_number', 'hour']).agg({
        'value': 'mean'
    }).reset_index()
    
    # 3. 计算移动窗口统计量
    df['rolling_mean_24h'] = df['value'].rolling(window=24).mean()
    df['rolling_std_24h'] = df['value'].rolling(window=24).std()
    df['rolling_min_24h'] = df['value'].rolling(window=24).min()
    df['rolling_max_24h'] = df['value'].rolling(window=24).max()
    
    # 4. 指数加权移动平均
    df['ewm_24h'] = df['value'].ewm(span=24).mean()
    
    # 5. 计算变化率
    df['pct_change'] = df['value'].pct_change()
    df['diff'] = df['value'].diff()
    
    return df, daily_stats, weekly_pattern

ts_advanced, daily_stats, weekly_pattern = advanced_resampling(ts_data.copy())

print("时间序列数据高级处理结果:")
print(ts_advanced.head(10))
print("\n日均统计:")
print(daily_stats.head())

3.2 时间序列分解与预测

from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings('ignore')

def time_series_decomposition_forecast():
    # 使用更短的时间序列用于演示
    dates = pd.date_range('2023-01-01', periods=365, freq='D')
    np.random.seed(42)
    
    # 创建时间序列
    trend = np.linspace(100, 150, 365)
    seasonal = 10 * np.sin(2 * np.pi * np.arange(365) / 30)
    noise = np.random.normal(0, 3, 365)
    series = trend + seasonal + noise
    
    ts = pd.Series(series, index=dates)
    
    # 时间序列分解
    decomposition = seasonal_decompose(ts, model='additive', period=30)
    
    # 绘制分解结果
    fig, axes = plt.subplots(4, 1, figsize=(12, 10))
    decomposition.observed.plot(ax=axes[0], legend=False)
    axes[0].set_title('Observed')
    decomposition.trend.plot(ax=axes[1], legend=False)
    axes[1].set_title('Trend')
    decomposition.seasonal.plot(ax=axes[2], legend=False)
    axes[2].set_title('Seasonal')
    decomposition.resid.plot(ax=axes[3], legend=False)
    axes[3].set_title('Residual')
    plt.tight_layout()
    plt.show()
    
    # ARIMA预测
    # 简单示例:使用最后100个数据点进行预测
    train_data = ts[-100:]
    
    # 自动选择ARIMA参数(简化版)
    best_aic = np.inf
    best_order = None
    
    for p in range(3):
        for d in range(2):
            for q in range(3):
                try:
                    model = ARIMA(train_data, order=(p, d, q))
                    model_fit = model.fit()
                    if model_fit.aic < best_aic:
                        best_aic = model_fit.aic
                        best_order = (p, d, q)
                except:
                    continue
    
    print(f"Best ARIMA order: {best_order} with AIC: {best_aic:.2f}")
    
    # 使用最佳参数拟合模型
    if best_order:
        model = ARIMA(train_data, order=best_order)
        model_fit = model.fit()
        
        # 预测未来30天
        forecast = model_fit.forecast(steps=30)
        forecast_index = pd.date_range(train_data.index[-1] + pd.Timedelta(days=1), periods=30, freq='D')
        forecast_series = pd.Series(forecast, index=forecast_index)
        
        # 绘制预测结果
        plt.figure(figsize=(12, 6))
        plt.plot(train_data.index, train_data.values, label='Historical Data', color='blue')
        plt.plot(forecast_series.index, forecast_series.values, label='Forecast', color='red', linestyle='--')
        plt.title('ARIMA Time Series Forecast')
        plt.xlabel('Date')
        plt.ylabel('Value')
        plt.legend()
        plt.grid(True, alpha=0.3)
        plt.show()
        
        return model_fit, forecast_series
    
    return None, None

model, forecast = time_series_decomposition_forecast()

第四部分:大数据处理与性能优化

4.1 使用Dask处理超出内存的数据

# 注意:Dask需要单独安装:pip install dask[complete]
import dask.dataframe as dd
import os

def dask_large_data_processing():
    # 创建一个大型CSV文件用于演示
    def create_large_csv(filename, rows=5000000):
        if not os.path.exists(filename):
            print(f"Creating large CSV file with {rows} rows...")
            chunk_size = 100000
            for i in range(0, rows, chunk_size):
                chunk = pd.DataFrame({
                    'id': range(i, min(i + chunk_size, rows)),
                    'category': np.random.choice(['A', 'B', 'C', 'D', 'E'], min(chunk_size, rows - i)),
                    'value': np.random.randn(min(chunk_size, rows - i)),
                    'timestamp': pd.date_range('2020-01-01', periods=min(chunk_size, rows - i), freq='T')
                })
                chunk.to_csv(filename, mode='a', header=i==0, index=False)
            print("CSV file created.")
    
    filename = 'large_dataset.csv'
    create_large_csv(filename, rows=5000000)
    
    # 使用Dask读取和处理大数据
    print("Loading data with Dask...")
    ddf = dd.read_csv(filename, parse_dates=['timestamp'])
    
    # Dask的延迟计算特性
    # 这些操作不会立即执行,只是构建计算图
    result = ddf.groupby('category').agg({
        'value': ['mean', 'sum', 'count']
    })
    
    # 执行计算并获取结果
    print("Computing results...")
    computed_result = result.compute()
    print("Dask computation result:")
    print(computed_result)
    
    # 复杂操作:按时间窗口聚合
    ddf['hour'] = ddf['timestamp'].dt.hour
    hourly_stats = ddf.groupby(['category', 'hour']).value.mean().compute()
    print("\nHourly statistics by category:")
    print(hourly_stats.head(10))
    
    # 清理大文件
    # os.remove(filename)
    
    return computed_result, hourly_stats

# dask_result, hourly_stats = dask_large_data_processing()
# print("Dask processing completed.")

4.2 并行处理与多进程优化

import multiprocessing as mp
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import time

def parallel_processing_demo():
    # 模拟一个耗时的计算任务
    def heavy_computation(data_chunk):
        # 模拟复杂计算
        result = np.linalg.eigvals(np.random.rand(100, 100))
        return np.sum(result) + data_chunk
    
    # 单进程版本
    def single_process(data):
        results = []
        for item in data:
            results.append(heavy_computation(item))
        return results
    
    # 多进程版本
    def multi_process(data, n_workers=4):
        with ProcessPoolExecutor(max_workers=n_workers) as executor:
            results = list(executor.map(heavy_computation, data))
        return results
    
    # 多线程版本(适用于I/O密集型任务)
    def multi_thread(data, n_workers=4):
        with ThreadPoolExecutor(max_workers=n_workers) as executor:
            results = list(executor.map(heavy_computation, data))
        return results
    
    # 生成测试数据
    test_data = list(range(100))
    
    # 性能比较
    print("性能测试开始...")
    
    start = time.time()
    result_single = single_process(test_data)
    time_single = time.time() - start
    print(f"单进程耗时: {time_single:.2f}秒")
    
    start = time.time()
    result_multi = multi_process(test_data, n_workers=4)
    time_multi = time.time() - start
    print(f"多进程(4核)耗时: {time_multi:.2f}秒")
    
    start = time.time()
    result_thread = multi_thread(test_data, n_workers=4)
    time_thread = time.time() - start
    print(f"多线程(4线程)耗时: {时间_thread:.2f}秒")
    
    print(f"\n加速比: {time_single/time_multi:.2f}x")
    
    return {
        'single': time_single,
        'multi': time_multi,
        'thread': time_thread
    }

# parallel_results = parallel_processing_demo()

第五部分:实战项目 - 构建完整的数据分析管道

5.1 项目1:电商销售分析仪表板

def ecommerce_analysis_project():
    """
    完整的电商销售分析项目
    包括数据加载、清洗、分析、可视化和报告生成
    """
    
    # 1. 数据生成与加载
    np.random.seed(42)
    n_rows = 10000
    
    ecommerce_data = pd.DataFrame({
        'order_id': range(1, n_rows + 1),
        'customer_id': np.random.randint(1, 2000, n_rows),
        'product_id': np.random.randint(1, 100, n_rows),
        'category': np.random.choice(['Electronics', 'Clothing', 'Books', 'Home', 'Sports'], n_rows),
        'price': np.random.uniform(10, 500, n_rows).round(2),
        'quantity': np.random.randint(1, 10, n_rows),
        'order_date': pd.date_range('2023-01-01', periods=n_rows, freq='H'),
        'region': np.random.choice(['North', 'South', 'East', 'West'], n_rows),
        'customer_type': np.random.choice(['New', 'Returning'], n_rows, p=[0.3, 0.7])
    })
    
    # 计算总价
    ecommerce_data['total_price'] = ecommerce_data['price'] * ecommerce_data['quantity']
    
    # 2. 数据清洗
    print("原始数据形状:", ecommerce_data.shape)
    print("缺失值检查:")
    print(ecommerce_data.isnull().sum())
    
    # 3. 核心分析
    # 3.1 销售趋势分析
    monthly_sales = ecommerce_data.groupby(
        ecommerce_data['order_date'].dt.to_period('M')
    )['total_price'].sum()
    
    # 3.2 品类分析
    category_analysis = ecommerce_data.groupby('category').agg({
        'total_price': ['sum', 'mean', 'count'],
        'quantity': 'sum'
    }).round(2)
    
    # 3.3 区域分析
    region_analysis = ecommerce_data.groupby('region').agg({
        'total_price': 'sum',
        'order_id': 'count'
    })
    region_analysis['avg_order_value'] = region_analysis['total_price'] / region_analysis['order_id']
    
    # 3.4 客户价值分析(RFM分析)
    # 最近购买时间(Recency)
    max_date = ecommerce_data['order_date'].max()
    recency = ecommerce_data.groupby('customer_id')['order_date'].max()
    recency = (max_date - recency).dt.days
    
    # 购买频率(Frequency)
    frequency = ecommerce_data.groupby('customer_id')['order_id'].count()
    
    # 消费金额(Monetary)
    monetary = ecommerce_data.groupby('customer_id')['total_price'].sum()
    
    rfm = pd.DataFrame({
        'recency': recency,
        'frequency': frequency,
        'monetary': monetary
    })
    
    # RFM评分
    rfm['R_score'] = pd.qcut(rfm['recency'], 4, labels=[4, 3, 2, 1])  # 越小越好
    rfm['F_score'] = pd.qcut(rfm['frequency'].rank(method='first'), 4, labels=[1, 2, 3, 4])
    rfm['M_score'] = pd.qcut(rfm['monetary'], 4, labels=[1, 2, 3, 4])
    
    rfm['RFM_score'] = rfm['R_score'].astype(str) + rfm['F_score'].astype(str) + rfm['M_score'].astype(str)
    
    # 4. 可视化
    fig = plt.figure(figsize=(20, 15))
    gs = fig.add_gridspec(3, 3)
    
    # 4.1 月度销售趋势
    ax1 = fig.add_subplot(gs[0, :2])
    monthly_sales.plot(ax=ax1, marker='o', linewidth=2, markersize=6)
    ax1.set_title('Monthly Sales Trend', fontsize=14, fontweight='bold')
    ax1.set_ylabel('Total Sales ($)')
    ax1.grid(True, alpha=0.3)
    
    # 4.2 品类销售占比
    ax2 = fig.add_subplot(gs[0, 2])
    category_sum = category_analysis[('total_price', 'sum')]
    ax2.pie(category_sum.values, labels=category_sum.index, autopct='%1.1f%%')
    ax2.set_title('Sales by Category')
    
    # 4.3 区域销售对比
    ax3 = fig.add_subplot(gs[1, 0])
    region_analysis['total_price'].plot(ax=ax3, kind='bar', color='skyblue')
    ax3.set_title('Sales by Region')
    ax3.set_ylabel('Total Sales ($)')
    
    # 4.4 客户类型分布
    ax4 = fig.add_subplot(gs[1, 1])
    customer_type_dist = ecommerce_data['customer_type'].value_counts()
    ax4.pie(customer_type_dist.values, labels=customer_type_dist.index, 
            autopct='%1.1f%%', colors=['lightcoral', 'lightgreen'])
    ax4.set_title('Customer Type Distribution')
    
    # 4.5 RFM分布
    ax5 = fig.add_subplot(gs[1, 2])
    rfm['RFM_score'].value_counts().head(10).plot(ax=ax5, kind='bar')
    ax5.set_title('Top 10 RFM Segments')
    ax5.tick_params(axis='x', rotation=45)
    
    # 4.6 价格与数量的关系
    ax6 = fig.add_subplot(gs[2, :])
    scatter = ax6.scatter(ecommerce_data['price'], ecommerce_data['quantity'], 
                         c=ecommerce_data['total_price'], cmap='viridis', alpha=0.6)
    ax6.set_xlabel('Price ($)')
    ax6.set_ylabel('Quantity')
    ax6.set_title('Price vs Quantity (color = Total Price)')
    plt.colorbar(scatter, ax=ax6, label='Total Price')
    
    plt.tight_layout()
    plt.show()
    
    # 5. 生成分析报告
    report = {
        'total_revenue': ecommerce_data['total_price'].sum(),
        'total_orders': len(ecommerce_data),
        'avg_order_value': ecommerce_data['total_price'].mean(),
        'top_category': category_analysis[('total_price', 'sum')].idxmax(),
        'best_region': region_analysis['total_price'].idxmax(),
        'unique_customers': ecommerce_data['customer_id'].nunique(),
        'top_rfm_segment': rfm['RFM_score'].value_counts().index[0]
    }
    
    print("\n=== 电商销售分析报告 ===")
    for key, value in report.items():
        print(f"{key.replace('_', ' ').title()}: {value:,.2f}" if isinstance(value, (int, float)) else f"{key.replace('_', ' ').title()}: {value}")
    
    return ecommerce_data, report

# 执行项目
ecommerce_data, analysis_report = ecommerce_analysis_project()

5.2 项目2:时间序列预测与异常检测

def time_series_anomaly_detection():
    """
    时间序列异常检测项目
    包括趋势分析、季节性分解、异常点识别
    """
    
    # 1. 创建带有异常的时间序列数据
    np.random.seed(42)
    dates = pd.date_range('2023-01-01', periods=500, freq='D')
    
    # 基础趋势 + 季节性 + 噪声
    trend = np.linspace(100, 200, 500)
    seasonal = 20 * np.sin(2 * np.pi * np.arange(500) / 50)
    noise = np.random.normal(0, 5, 500)
    
    # 添加异常点
    ts_values = trend + seasonal + noise
    anomaly_indices = [50, 150, 250, 350, 450]
    ts_values[anomaly_indices] += [50, -60, 80, -40, 70]  # 添加异常值
    
    ts_data = pd.DataFrame({
        'date': dates,
        'value': ts_values
    }).set_index('date')
    
    # 2. 异常检测算法
    def detect_anomalies_zscore(data, threshold=3):
        """基于Z-score的异常检测"""
        mean = data.mean()
        std = data.std()
        z_scores = (data - mean) / std
        anomalies = np.abs(z_scores) > threshold
        return anomalies, z_scores
    
    def detect_anomalies_iqr(data):
        """基于IQR的异常检测"""
        Q1 = data.quantile(0.25)
        Q3 = data.quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        anomalies = (data < lower_bound) | (data > upper_bound)
        return anomalies
    
    def detect_anomalies_rolling(data, window=30, threshold=3):
        """基于滚动统计的异常检测"""
        rolling_mean = data.rolling(window=window).mean()
        rolling_std = data.rolling(window=window).std()
        
        # 避免窗口期的NaN值
        valid_idx = ~rolling_mean.isna()
        
        z_scores = (data[valid_idx] - rolling_mean[valid_idx]) / rolling_std[valid_idx]
        anomalies = np.abs(z_scores) > threshold
        
        return anomalies, rolling_mean, rolling_std
    
    # 3. 应用检测算法
    anomalies_z, z_scores = detect_anomalies_zscore(ts_data['value'])
    anomalies_iqr = detect_anomalies_iqr(ts_data['value'])
    anomalies_rolling, rolling_mean, rolling_std = detect_anomalies_rolling(ts_data['value'])
    
    # 4. 可视化结果
    fig, axes = plt.subplots(2, 2, figsize=(16, 10))
    
    # 原始数据与Z-score检测
    ax1 = axes[0, 0]
    ax1.plot(ts_data.index, ts_data['value'], 'b-', label='Original', alpha=0.7)
    ax1.scatter(ts_data.index[anomalies_z], ts_data['value'][anomalies_z], 
               color='red', s=50, label='Anomalies (Z-score)')
    ax1.set_title('Anomaly Detection: Z-Score Method')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 原始数据与IQR检测
    ax2 = axes[0, 1]
    ax2.plot(ts_data.index, ts_data['value'], 'b-', label='Original', alpha=0.7)
    ax2.scatter(ts_data.index[anomalies_iqr], ts_data['value'][anomalies_iqr], 
               color='orange', s=50, label='Anomalies (IQR)')
    ax2.set_title('Anomaly Detection: IQR Method')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 滚动窗口检测
    ax3 = axes[1, 0]
    ax3.plot(ts_data.index, ts_data['value'], 'b-', label='Original', alpha=0.5)
    ax3.plot(rolling_mean.index, rolling_mean, 'g--', label='Rolling Mean')
    ax3.fill_between(rolling_mean.index, 
                     rolling_mean - 3 * rolling_std,
                     rolling_mean + 3 * rolling_std,
                     alpha=0.2, color='gray', label='±3σ Range')
    ax3.scatter(ts_data.index[anomalies_rolling], ts_data['value'][anomalies_rolling], 
               color='red', s=50, label='Anomalies')
    ax3.set_title('Anomaly Detection: Rolling Window Method')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # Z-score分布
    ax4 = axes[1, 1]
    ax4.hist(z_scores, bins=30, alpha=0.7, color='purple')
    ax4.axvline(x=3, color='red', linestyle='--', label='Threshold = 3')
    ax4.axvline(x=-3, color='red', linestyle='--')
    ax4.set_title('Z-Score Distribution')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
    # 5. 生成异常报告
    anomaly_report = pd.DataFrame({
        'Date': ts_data.index[anomalies_z],
        'Value': ts_data['value'][anomalies_z].values,
        'Z_Score': z_scores[anomalies_z].values,
        'Severity': ['High' if abs(z) > 4 else 'Medium' for z in z_scores[anomalies_z]]
    })
    
    print("\n=== 异常检测报告 ===")
    print(f"检测到的异常点数量: {len(anomaly_report)}")
    print("\n异常点详情:")
    print(anomaly_report.to_string(index=False))
    
    return ts_data, anomaly_report

# 执行时间序列异常检测项目
ts_data, anomaly_report = time_series_anomaly_detection()

第六部分:高级技巧与最佳实践

6.1 内存优化技巧

def advanced_memory_optimization():
    """
    深入的内存优化技巧
    """
    
    # 1. 使用category类型优化分类数据
    df = pd.DataFrame({
        'id': range(1000000),
        'country': np.random.choice(['USA', 'China', 'India', 'Germany', 'Brazil'], 1000000),
        'city': np.random.choice(['New York', 'Beijing', 'Mumbai', 'Berlin', 'São Paulo'], 1000000),
        'status': np.random.choice(['Active', 'Inactive', 'Pending'], 1000000),
        'value': np.random.randn(1000000)
    })
    
    print("原始内存使用:")
    print(df.info(memory_usage='deep'))
    
    # 优化前
    df_original = df.copy()
    
    # 优化后
    df_optimized = df.copy()
    df_optimized['country'] = df_optimized['country'].astype('category')
    df_optimized['city'] = df_optimized['city'].astype('category')
    df_optimized['status'] = df_optimized['status'].astype('category')
    
    print("\n优化后内存使用:")
    print(df_optimized.info(memory_usage='deep'))
    
    # 2. 使用稀疏矩阵处理大量零值
    from scipy import sparse
    
    # 创建稀疏矩阵
    dense_matrix = np.random.choice([0, 1, 2], size=(1000, 1000), p=[0.9, 0.05, 0.05])
    sparse_matrix = sparse.csr_matrix(dense_matrix)
    
    print(f"\n稀疏矩阵内存节省: {dense_matrix.nbytes / sparse_matrix.data.nbytes:.1f}x")
    
    # 3. 分块处理大数据
    def process_large_file_in_chunks(filename, chunk_size=100000):
        results = []
        for chunk in pd.read_csv(filename, chunksize=chunk_size):
            # 处理每个chunk
            processed = chunk.groupby('category')['value'].sum()
            results.append(processed)
        
        # 合并结果
        final_result = pd.concat(results).groupby(level=0).sum()
        return final_result
    
    return df_optimized, sparse_matrix

# advanced_memory_optimization()

6.2 代码性能分析与优化

import cProfile
import pstats
from functools import wraps

def performance_analysis_demo():
    """
    性能分析与优化演示
    """
    
    # 装饰器:用于测量函数执行时间
    def timer(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(f"{func.__name__} executed in {end - start:.4f} seconds")
            return result
        return wrapper
    
    # 慢速版本
    @timer
    def slow_version():
        result = []
        for i in range(100000):
            result.append(i ** 2)
        return result
    
    # 快速版本(向量化)
    @timer
    def fast_version():
        return [i ** 2 for i in range(100000)]
    
    # 最快版本(numpy向量化)
    @timer
    def fastest_version():
        return np.arange(100000) ** 2
    
    # 比较性能
    print("性能比较测试:")
    slow_result = slow_version()
    fast_result = fast_version()
    fastest_result = fastest_version()
    
    # 使用cProfile进行详细分析
    print("\n详细性能分析 (cProfile):")
    profiler = cProfile.Profile()
    profiler.enable()
    
    # 执行需要分析的代码
    for _ in range(1000):
        np.random.randn(100, 100).sum()
    
    profiler.disable()
    stats = pstats.Stats(profiler)
    stats.sort_stats('cumulative')
    stats.print_stats(10)  # 显示前10个最耗时的函数
    
    return fastest_result

# performance_analysis_demo()

结论

通过本课程的学习,你已经掌握了Python数据分析的核心进阶技巧。从Pandas高级操作到复杂可视化,从时间序列分析到大数据处理,再到实战项目,这些技能将帮助你在实际工作中更高效地解决问题。

记住以下关键要点:

  1. 内存优化:始终关注数据类型的优化,使用category类型处理分类数据
  2. 向量化操作:避免使用循环,尽可能使用NumPy和Pandas的向量化函数
  3. 分块处理:对于超出内存的数据,使用分块读取或Dask
  4. 并行计算:合理使用多进程和多线程提升计算效率
  5. 可视化:选择合适的图表类型,清晰传达数据洞察
  6. 项目实践:将技能应用到实际项目中,不断积累经验

持续学习和实践是掌握数据分析的关键。建议你:

  • 定期阅读Pandas和NumPy的官方文档
  • 参与开源数据分析项目
  • 在Kaggle等平台练习真实数据集
  • 关注数据科学领域的最新发展

祝你在数据分析的道路上越走越远!