Python案例如何用Pandas做数据分组重采压测

wen python案例 7

本文目录导读:

Python案例如何用Pandas做数据分组重采压测

  1. 基础数据准备
  2. 不同重采样方法性能对比
  3. 压力测试框架
  4. 优化策略测试
  5. 内存使用监控
  6. 可视化结果
  7. 优化建议总结

我来详细说明如何使用Pandas进行数据分组重采样和压力测试。

基础数据准备

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import time
# 创建测试数据
def create_test_data(n_rows=10000):
    """生成测试数据集"""
    np.random.seed(42)
    # 生成时间序列
    base_time = datetime(2023, 1, 1)
    timestamps = [base_time + timedelta(minutes=i) for i in range(n_rows)]
    # 创建多组数据
    groups = ['A', 'B', 'C', 'D']
    data = {
        'timestamp': timestamps * (n_rows // len(timestamps)) + timestamps[:n_rows % len(timestamps)],
        'group': np.random.choice(groups, n_rows),
        'value1': np.random.randn(n_rows) * 100,
        'value2': np.random.randn(n_rows) * 50,
        'category': np.random.choice(['X', 'Y', 'Z'], n_rows)
    }
    df = pd.DataFrame(data)
    # 只保留前n_rows行
    df = df.head(n_rows)
    return df
# 创建100万行测试数据
df_large = create_test_data(1000000)
print(f"数据集大小: {df_large.shape}")

不同重采样方法性能对比

def benchmark_resampling_methods(df):
    """对比不同重采样方法的性能"""
    results = []
    # 方法1: 使用resample和groupby
    def method_1(df):
        return (df.set_index('timestamp')
                .groupby('group')
                .resample('1H')
                .agg({'value1': 'mean', 'value2': 'sum'})
                .reset_index())
    # 方法2: 先分组再重采样
    def method_2(df):
        def resample_group(group):
            return (group.set_index('timestamp')
                   .resample('1H')
                   .agg({'value1': 'mean', 'value2': 'sum'}))
        return df.groupby('group').apply(resample_group).reset_index()
    # 方法3: 使用Grouper
    def method_3(df):
        return (df.set_index('timestamp')
                .groupby(['group', pd.Grouper(freq='1H')])
                .agg({'value1': 'mean', 'value2': 'sum'})
                .reset_index())
    # 方法4: 先排序再重采样
    def method_4(df):
        df_sorted = df.sort_values(['group', 'timestamp'])
        return (df_sorted.set_index('timestamp')
                .groupby('group')
                .resample('1H')
                .agg({'value1': 'mean', 'value2': 'sum'})
                .reset_index())
    methods = [
        ('Method 1: GroupBy + Resample', method_1),
        ('Method 2: GroupBy + Apply', method_2),
        ('Method 3: Grouper', method_3),
        ('Method 4: Sort + Resample', method_4)
    ]
    for name, method in methods:
        # 使用小样本测试
        df_sample = df.head(100000)
        start_time = time.time()
        try:
            result = method(df_sample)
            elapsed = time.time() - start_time
            results.append({
                'method': name,
                'time': elapsed,
                'rows': len(result),
                'success': True
            })
        except Exception as e:
            results.append({
                'method': name,
                'time': None,
                'rows': 0,
                'success': False,
                'error': str(e)
            })
        print(f"{name}: {elapsed:.3f}s")
    return pd.DataFrame(results)
# 运行性能测试
perf_results = benchmark_resampling_methods(df_large)
print("\n性能测试结果:")
print(perf_results)

压力测试框架

class ResampleStressTest:
    """重采样压力测试类"""
    def __init__(self):
        self.results = []
    def test_different_sizes(self, sizes=[100000, 500000, 1000000]):
        """测试不同数据量"""
        for size in sizes:
            print(f"\n=== 测试数据量: {size:,} 行 ===")
            df = create_test_data(size)
            start_time = time.time()
            result = self._perform_resampling(df)
            elapsed = time.time() - start_time
            self.results.append({
                'data_size': size,
                'time_seconds': elapsed,
                'rows_per_second': size / elapsed,
                'result_rows': len(result)
            })
            print(f"耗时: {elapsed:.3f}s")
            print(f"处理速度: {size/elapsed:,.0f} 行/秒")
    def test_different_frequencies(self, df, frequencies=['10T', '30T', '1H', '6H', '1D']):
        """测试不同重采样频率"""
        print("\n=== 测试不同重采样频率 ===")
        for freq in frequencies:
            start_time = time.time()
            result = self._perform_resampling(df, freq)
            elapsed = time.time() - start_time
            self.results.append({
                'frequency': freq,
                'time_seconds': elapsed,
                'result_rows': len(result)
            })
            print(f"频率 {freq}: {elapsed:.3f}s, 结果行数: {len(result):,}")
    def test_different_aggregations(self, df, agg_functions=['mean', 'sum', 'count', 'std', 'min', 'max']):
        """测试不同聚合函数"""
        print("\n=== 测试不同聚合函数 ===")
        for agg_func in agg_functions:
            start_time = time.time()
            result = self._perform_resampling_with_agg(df, agg_func)
            elapsed = time.time() - start_time
            self.results.append({
                'aggregation': agg_func,
                'time_seconds': elapsed,
                'result_rows': len(result)
            })
            print(f"聚合函数 {agg_func}: {elapsed:.3f}s")
    def _perform_resampling(self, df, freq='1H'):
        """执行重采样"""
        return (df.set_index('timestamp')
                .groupby('group')
                .resample(freq)
                .agg({'value1': ['mean', 'std'], 'value2': ['sum', 'count']})
                .reset_index())
    def _perform_resampling_with_agg(self, df, agg_func):
        """执行带特定聚合的重采样"""
        return (df.set_index('timestamp')
                .groupby('group')
                .resample('1H')
                .agg({'value1': agg_func, 'value2': agg_func})
                .reset_index())
    def run_comprehensive_test(self):
        """运行综合测试"""
        print("=" * 50)
        print("重采样压力测试 - 综合测试")
        print("=" * 50)
        # 测试不同数据量
        self.test_different_sizes([50000, 100000, 200000])
        # 测试不同频率
        df = create_test_data(200000)
        self.test_different_frequencies(df)
        # 测试不同聚合函数
        self.test_different_aggregations(df)
        return pd.DataFrame(self.results)
# 运行压力测试
tester = ResampleStressTest()
results_df = tester.run_comprehensive_test()

优化策略测试

def optimization_strategies():
    """测试不同优化策略"""
    print("\n=== 优化策略测试 ===")
    df = create_test_data(500000)
    strategies = {
        'Base': lambda df: (df.set_index('timestamp')
                           .groupby('group')
                           .resample('1H')
                           .agg({'value1': 'mean', 'value2': 'sum'})),
        'Sorted': lambda df: (df.sort_values(['group', 'timestamp'])
                             .set_index('timestamp')
                             .groupby('group')
                             .resample('1H')
                             .agg({'value1': 'mean', 'value2': 'sum'})),
        'Pivot': lambda df: (df.pivot_table(
                            index='group', 
                            columns=pd.Grouper(key='timestamp', freq='1H'),
                            values='value1',
                            aggfunc='mean')),
        'Dask': lambda df: (df.set_index('timestamp')
                           .groupby('group')
                           .resample('1H')
                           .agg('mean')
                           .dropna())
    }
    results = []
    for name, func in strategies.items():
        start_time = time.time()
        try:
            result = func(df)
            elapsed = time.time() - start_time
            results.append({'strategy': name, 'time': elapsed, 'status': 'OK'})
        except Exception as e:
            elapsed = time.time() - start_time
            results.append({'strategy': name, 'time': elapsed, 'status': f'Error: {str(e)}'})
        print(f"{name}: {elapsed:.3f}s")
    return pd.DataFrame(results)
# 运行优化测试
opt_results = optimization_strategies()

内存使用监控

import psutil
import os
def monitor_memory_usage():
    """监控内存使用情况"""
    process = psutil.Process(os.getpid())
    print("\n=== 内存使用监控 ===")
    # 创建大数据集
    df = create_test_data(1000000)
    initial_memory = process.memory_info().rss / 1024 / 1024
    print(f"初始内存使用: {initial_memory:.2f} MB")
    # 执行重采样并监控内存
    memory_log = []
    for i in range(5):
        start_time = time.time()
        # 执行重采样
        result = (df.set_index('timestamp')
                  .groupby('group')
                  .resample('1H')
                  .agg('mean'))
        elapsed = time.time() - start_time
        current_memory = process.memory_info().rss / 1024 / 1024
        memory_log.append({
            'iteration': i + 1,
            'time_seconds': elapsed,
            'memory_mb': current_memory,
            'memory_increase': current_memory - initial_memory
        })
        print(f"迭代 {i+1}: 耗时={elapsed:.3f}s, 内存={current_memory:.2f}MB")
    return pd.DataFrame(memory_log)
# 运行内存监控
memory_df = monitor_memory_usage()

可视化结果

import matplotlib.pyplot as plt
import seaborn as sns
def plot_stress_test_results(results_df):
    """可视化压力测试结果"""
    # 创建图表
    fig, axes = plt.subplots(2, 2, figsize=(14, 10))
    # 1. 数据量 vs 耗时
    if 'data_size' in results_df.columns:
        ax1 = axes[0, 0]
        ax1.plot(results_df['data_size'], results_df['time_seconds'], 'bo-')
        ax1.set_xlabel('数据量 (行)')
        ax1.set_ylabel('耗时 (秒)')
        ax1.set_title('数据量 vs 耗时')
        ax1.grid(True)
    # 2. 处理速度
    if 'rows_per_second' in results_df.columns:
        ax2 = axes[0, 1]
        ax2.bar(range(len(results_df)), results_df['rows_per_second'])
        ax2.set_xlabel('测试序号')
        ax2.set_ylabel('处理速度 (行/秒)')
        ax2.set_title('处理速度对比')
    # 3. 频率 vs 结果行数
    if 'frequency' in results_df.columns:
        ax3 = axes[1, 0]
        ax3.bar(results_df['frequency'], results_df['result_rows'])
        ax3.set_xlabel('重采样频率')
        ax3.set_ylabel('结果行数')
        ax3.set_title('重采样频率 vs 结果行数')
    # 4. 聚合函数性能
    if 'aggregation' in results_df.columns:
        ax4 = axes[1, 1]
        ax4.bar(results_df['aggregation'], results_df['time_seconds'])
        ax4.set_xlabel('聚合函数')
        ax4.set_ylabel('耗时 (秒)')
        ax4.set_title('聚合函数性能对比')
        plt.setp(ax4.xaxis.get_majorticklabels(), rotation=45)
    plt.tight_layout()
    plt.show()
# 绘制压力测试结果
plot_stress_test_results(results_df)

优化建议总结

def generate_optimization_tips():
    """生成优化建议"""
    tips = """
=== Pandas分组重采样优化建议 ===
1. **数据预处理优化**
   - 确保时间索引唯一且排序
   - 使用category类型处理分组列
   - 提前过滤不需要的数据
2. **索引优化**
   - 优先使用set_index('timestamp')设置时间索引
   - 使用sort_index()对时间索引排序
   - 避免在groupby后重复设置索引
3. **重采样策略**
   - 使用pd.Grouper进行分组重采样
   - 选择合适的重采样频率
   - 避免过细的重采样粒度
4. **聚合优化**
   - 使用字典指定不同列的聚合函数
   - 优先使用内置聚合函数
   - 减少链式操作
5. **内存优化**
   - 使用chunksize分批处理大数据集
   - 及时释放不用的DataFrame
   - 使用copy=False避免不必要的数据复制
6. **并行处理**
   - 使用swifter或dask进行并行重采样
   - 按group分块并行处理
   - 利用多核CPU优势
7. **最佳实践**
   - 先排序再分组重采样
   - 避免使用apply方法
   - 使用agg替代apply进行聚合
   """
    print(tips)
# 输出优化建议
generate_optimization_tips()

这个完整的案例展示了:

  1. 数据准备和基础重采样
  2. 多种重采样方法的性能对比
  3. 全面的压力测试框架
  4. 不同维度的性能测试(数据量、频率、聚合函数)
  5. 内存使用监控
  6. 结果可视化
  7. 优化建议

通过这些测试,你可以找出最适合你数据规模和业务场景的重采样策略。

抱歉,评论功能暂时关闭!