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

循环生成过滤Pandas DataFrame性能不佳,求优化方案

Optimizing Pandas Merging for Time-Windowed Fact Matching

Your core issue here is that looping through every single party_id and querying the DataFrames repeatedly is extremely inefficient—Pandas wasn't designed for row-by-row operations, especially with large datasets like 11M rows. Let's fix this with vectorized operations that leverage Pandas' optimized internals.

Step 1: Preprocess & Index for Speed

First, let's make sure our data is properly typed and indexed to speed up merges and filters:

import pandas as pd
from datetime import timedelta

# Convert date columns to datetime (do this once, not in the loop!)
app['date_st'] = pd.to_datetime(app['date_st'])
facts['fact_date'] = pd.to_datetime(facts['fact_date'])

# Add computed columns to app: the earliest allowed fact date for each party
window_days = 180
app['fact_start_date'] = app['date_st'] - timedelta(days=window_days)

# Add indexes to speed up merges and filters
app = app.set_index('client_id')
facts = facts.set_index('client_id')

Step 2: Vectorized Merge & Filter (No Loops!)

Instead of looping, we'll merge the two DataFrames on client_id first, then filter the rows that meet our time window criteria. This is way faster because Pandas handles the join in optimized C-level code.

# Merge app and facts on client_id (this aligns all facts with their client's parties)
merged = app.merge(facts, left_index=True, right_index=True, how='inner')

# Apply the time window filters
filtered = merged[
    (merged['fact_date'] < merged['date_st']) &
    (merged['fact_date'] >= merged['fact_start_date'])
]

# Keep only the columns we need, and reset index if needed
new_facts = filtered[['party_id', 'client_id', 'fact_date', 'fact_sum']].reset_index(drop=True)

Why This is Way Faster

  • No row-by-row loops: The merge and filter operations are vectorized, meaning they operate on entire columns at once instead of individual rows.
  • Indexing: By indexing on client_id, we speed up the merge operation significantly (Pandas uses hash tables for indexed joins).
  • Single pass over data: We only process the facts table once, instead of 50k times.

Optional: Memory Optimization (If Needed)

If even the merged DataFrame is too large for memory, you can process the data in chunks by client_id:

new_facts_list = []

# Iterate over unique client IDs (fewer iterations than party IDs!)
for clid in app.index.unique():
    # Get all parties for this client
    client_app = app.loc[clid]
    # Get all facts for this client
    client_facts = facts.loc[clid]
    # Merge and filter for this client
    merged = client_app.merge(client_facts, on='client_id', how='inner')
    filtered = merged[
        (merged['fact_date'] < merged['date_st']) &
        (merged['fact_date'] >= merged['fact_start_date'])
    ]
    new_facts_list.append(filtered)

# Combine all chunks
new_facts = pd.concat(new_facts_list, ignore_index=True)

This reduces the peak memory usage since we only process one client's data at a time.

Verify the Result

You can check if the output matches your expected result by comparing a sample of rows:

print(new_facts[new_facts['party_id'] == 'pid1'])

This should match the rows you listed for pid1 in your expected output.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 14:27:31