You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化Pandas Series相邻值平均迭代逻辑,解决大数据量性能问题

Optimizing Your Pandas Series Merging Function for Large Datasets

Hey there! Let's break down why your reshape_arr function is taking 7-10 minutes with 100k+ rows, and fix it with way faster, more efficient approaches.

First: Why Your Current Code Is So Slow

Your function has three critical performance bottlenecks that add up to those brutal runtimes:

  • Repeated sorting & deduplication: Every loop calls sort_values().unique()—an expensive O(n log n) operation. Doing this over and over wastes massive amounts of time.
  • Multiple global replacements: a.replace() scans the entire Series every time you call it. When you do this multiple times per loop, you’re looking at O(k*n) time (k = number of iterations), which is devastating for large datasets.
  • Inefficient iterative logic: You re-scan the entire array every loop to catch new merges from averages. This leads to redundant work, as you’re re-checking pairs you’ve already processed.

Optimized Approach 1: Single-Pass Group Merging (No Multiprocessing)

The core idea here is to group all consecutive values within close distance in one pass, compute their averages, then map those averages back to the original Series in a single vectorized operation. This eliminates repeated loops and global replacements entirely.

Here's the optimized code:

import pandas as pd
import numpy as np

def reshape_arr_optimized(a, close):
    """Merge values within 'close' distance into their average, returns unique values"""
    # Get sorted unique values once (no repeated sorting!)
    sorted_unique = np.sort(a.unique())
    n = len(sorted_unique)
    
    if n <= 1:
        return sorted_unique
    
    # Group consecutive values that are within 'close' range
    groups = []
    current_group = [sorted_unique[0]]
    
    for num in sorted_unique[1:]:
        if num - current_group[-1] < close:
            current_group.append(num)
        else:
            groups.append(current_group)
            current_group = [num]
    groups.append(current_group)
    
    # Create a mapping from original values to their group average
    value_map = {}
    for group in groups:
        avg = np.mean(group)
        for num in group:
            value_map[num] = avg
    
    # Replace all values in one vectorized pass (way faster than multiple replaces!)
    updated_a = a.map(value_map)
    return updated_a.unique()

Why This Works Faster

  • Single sort/deduplication: We only sort and deduplicate once, not every loop iteration.
  • Vectorized mapping: a.map() scans the Series once, instead of multiple replace() calls that each scan the whole Series.
  • No repeated loops: We catch all mergable groups in one pass, so we don’t need to keep looping until no changes happen.

For 100k+ rows, this should drop your runtime from minutes to seconds.

Optimized Approach 2: Multiprocessing with Chunk Overlap (For Extra Large Datasets)

If you’re dealing with 200k+ rows and want to leverage multiple CPU cores, you can split the data into chunks—but you need to handle chunk boundaries to avoid missing merges between chunks.

The fix is to add overlap to each chunk (keeping values near the boundary that might merge with adjacent chunks), process chunks in parallel, then do a final global merge to clean up any cross-chunk merges.

Here's the code:

from multiprocessing import Pool
import pandas as pd
import numpy as np

def process_chunk(chunk, close):
    """Process a single chunk using the optimized group merging logic"""
    sorted_unique = np.sort(chunk.unique())
    n = len(sorted_unique)
    
    if n <= 1:
        return chunk.map({sorted_unique[0]: sorted_unique[0]}) if n ==1 else chunk
    
    groups = []
    current_group = [sorted_unique[0]]
    for num in sorted_unique[1:]:
        if num - current_group[-1] < close:
            current_group.append(num)
        else:
            groups.append(current_group)
            current_group = [num]
    groups.append(current_group)
    
    value_map = {}
    for group in groups:
        avg = np.mean(group)
        for num in group:
            value_map[num] = avg
    
    return chunk.map(value_map)

def reshape_arr_multiprocess(a, close, num_processes=4):
    """Multiprocess version of the optimized function, handles chunk boundaries"""
    # Sort the Series first to make chunk overlap meaningful
    sorted_a = a.sort_values()
    total_len = len(sorted_a)
    chunk_size = total_len // num_processes
    
    # Create chunks with overlap (keep values within 'close' range of boundaries)
    chunks = []
    for i in range(num_processes):
        # Start a bit early to capture values that might merge with the previous chunk
        start = max(0, i * chunk_size - close)
        # End a bit late to capture values that might merge with the next chunk
        end = min(total_len, (i + 1) * chunk_size + close)
        chunks.append(sorted_a.iloc[start:end])
    
    # Process chunks in parallel
    with Pool(num_processes) as pool:
        processed_chunks = pool.starmap(process_chunk, [(chunk, close) for chunk in chunks])
    
    # Combine chunks and do a final global merge to fix cross-chunk merges
    combined_values = pd.concat(processed_chunks).unique()
    sorted_combined = np.sort(combined_values)
    
    n = len(sorted_combined)
    if n <=1:
        return sorted_combined
    
    # Final grouping to catch any merges between chunk boundaries
    groups = []
    current_group = [sorted_combined[0]]
    for num in sorted_combined[1:]:
        if num - current_group[-1] < close:
            current_group.append(num)
        else:
            groups.append(current_group)
            current_group = [num]
    groups.append(current_group)
    
    # Return the final unique averages
    return np.array([np.mean(group) for group in groups])

Key Fix for Chunk Boundaries

By adding overlap to each chunk (extending start/end by close), we ensure that values near chunk edges aren’t cut off from potential merges with adjacent chunks. The final global merge cleans up any remaining merges that span chunk boundaries.


内容的提问来源于stack exchange,提问作者Keven Scharaswak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:57:02