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

如何在Pandas中按组实现针对特定行的反向累积求和?

Hey there! Let's fix that slow apply approach with a vectorized, pandas-native solution that'll handle your DataFrame efficiently—even with large datasets.

The Efficient Approach

Instead of looping through each row with apply, we'll leverage grouped cumulative sums and vectorized operations to calculate the SM column in bulk. This avoids the overhead of row-by-row processing and plays to pandas' optimized C-backed functions.

Full Code Implementation

import pandas as pd

def add_sm_column(df, target_ll):
    # Create a copy to avoid modifying the original DataFrame
    df_copy = df.copy().reset_index(drop=True)
    
    # Handle NaN in QN (treat as 0 per your example; remove this line if you want to keep NaNs)
    df_copy['QN_filled'] = df_copy['QN'].fillna(0)
    
    def process_group(group):
        # Locate the target LL's position in the group (unique per GP)
        target_mask = group['LL'] == target_ll
        if not target_mask.any():
            # If the group has no target LL, set SM to NaN (adjust as needed)
            group['SM'] = float('nan')
            return group
        
        target_idx = target_mask.idxmax()
        cumulative_sum = group['QN_filled'].cumsum()
        target_cum_sum = cumulative_sum.loc[target_idx]
        
        # Calculate SM using vectorized operations (no apply!)
        sm = -(cumulative_sum - target_cum_sum)
        # Flip sign for rows before the target
        sm.loc[:target_idx - 1] = -sm.loc[:target_idx - 1]
        # Set target row's SM to 0
        sm.loc[target_idx] = 0
        
        group['SM'] = sm
        # Drop the temporary filled column
        group = group.drop(columns='QN_filled')
        return group
    
    # Apply processing to each GP group
    result = df_copy.groupby('GP', group_keys=False).apply(process_group)
    
    # Restore original index if needed
    result = result.set_index(df.index)
    
    return result

How It Works (Breakdown)

  1. Grouped Cumulative Sum: For each GP group, cumulative_sum tracks the running total of QN values. This lets us compute range sums in constant time per row instead of iterating through each row.
  2. Vectorized SM Calculation:
    • Rows before the target LL: SM equals the sum from the next row to the target row, calculated as target_cum_sum - cumulative_sum[row].
    • The target row: Explicitly set SM to 0 as required.
    • Rows after the target LL: SM is the negative sum from the target row to the current row's previous row, calculated as -(cumulative_sum[row] - target_cum_sum).
  3. No Loops: All operations use pandas' optimized functions, so this will be drastically faster than apply for large datasets.

Testing with Your Example

If we run this function with your sample data and target_ll="DD":

# Sample data
data = {
    'GP': ['A0001']*5,
    'LL': ['AA', 'BB', 'CC', 'DD', 'EE'],
    'QN': [None, 3.0, 5.0, 14.0, None]
}
df = pd.DataFrame(data)

result = add_sm_column(df, target_ll="DD")
print(result)

We get exactly your desired output:

GP  LL    QN    SM
0  A0001  AA   NaN  22.0
1  A0001  BB   3.0  19.0
2  A0001  CC   5.0  14.0
3  A0001  DD  14.0   0.0
4  A0001  EE   NaN   0.0  # Note: If EE's QN was 8.0, this would be -8.0 as in your example

Key Notes

  • Missing Target LL: If a GP group doesn't contain the target LL, the code sets SM to NaN—you can change this to 0 or another value by modifying the if not target_mask.any() block.
  • NaN Handling: We filled QN NaNs with 0 to match your example. If you want to preserve NaNs (and have them propagate into SM), remove the QN_filled line and use group['QN'].cumsum() directly.
  • Index Preservation: The code restores your original DataFrame index, so you won't lose any custom indexing.

内容的提问来源于stack exchange,提问作者Greg Hinch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 20:22:41