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

如何为DataFrame逐行计算值?DAX转Python遇结果一致问题

解决DAX转Python时行级滚动聚合结果重复的问题

原DAX代码的核心逻辑是:对每一行数据,按Item_Number分组,计算该行Casting_Date往前推365天到该行日期前一天的Inclusion总和与Closed总和的比值。

你的Python代码出现每行结果相同的原因是:_item_number和_start_date都是Series类型,直接用df2['Item_Number'] == _item_number会触发广播机制,最终筛选出的是整个数据集里所有满足对应行条件的记录,求和后得到一个标量值并赋值给整列,导致所有行结果一致。

以下是三种可行的解决方向:


方法1:使用apply逐行计算(直观易理解)

对DataFrame的每一行单独执行计算逻辑,适合数据量不大的场景:

import pandas as pd

def calculate_scrap_rate(row, df):
    # 获取当前行的Item和日期范围
    item = row['Item_Number']
    end_date = row['Casting_Date']
    start_date = end_date - pd.DateOffset(days=365)
    
    # 筛选同Item且在日期范围内的记录
    mask = (df['Item_Number'] == item) & \
           (df['Casting_Date'] >= start_date) & \
           (df['Casting_Date'] < end_date)
    
    # 计算总和
    total_inclusions = df.loc[mask, 'Inclusion'].sum()
    total_closed = df.loc[mask, 'Closed'].sum()
    
    # 计算比值,处理除零情况
    return total_inclusions / total_closed if total_closed != 0 else None

# 应用到每一行
df2['expected_inclusion_scrap_rate'] = df2.apply(calculate_scrap_rate, axis=1, df=df2)

方法2:使用分组滚动窗口(高效,适合大数据集)

利用pandas的groupby结合rolling窗口,先按Item_Number分组,再基于时间窗口计算滚动聚合:

# 先确保Casting_Date是datetime类型
df2['Casting_Date'] = pd.to_datetime(df2['Casting_Date'])

# 按Item_Number分组,设置时间滚动窗口为365天,窗口不包含当前行日期
grouped = df2.groupby('Item_Number').rolling(
    window='365D',
    on='Casting_Date',
    closed='left'  # 对应DAX中<Casting_Date的逻辑
)

# 计算滚动总和
df2['inclusions_group'] = grouped['Inclusion'].sum().reset_index(level=0, drop=True)
df2['closed_group'] = grouped['Closed'].sum().reset_index(level=0, drop=True)

# 计算报废率,处理除零
df2['expected_inclusion_scrap_rate'] = df2['inclusions_group'].div(df2['closed_group']).fillna(None)

方法3:使用merge_asof(高效的时间匹配方式)

先按Item分组排序,再用merge_asof匹配时间范围内的记录,最后聚合:

# 排序(merge_asof要求左右表都按匹配键排序)
df_sorted = df2.sort_values(['Item_Number', 'Casting_Date'])

# 生成每个行的时间范围
df_sorted['start_date'] = df_sorted['Casting_Date'] - pd.DateOffset(days=365)

# 自连接,匹配同Item且日期在[start_date, Casting_Date)范围内的记录
merged = pd.merge_asof(
    df_sorted,
    df_sorted[['Item_Number', 'Casting_Date', 'Inclusion', 'Closed']],
    by='Item_Number',
    left_on='start_date',
    right_on='Casting_Date',
    direction='forward'
)

# 按原行的索引分组,计算总和
aggregated = merged.groupby(merged.index).agg(
    total_inclusions=('Inclusion_y', 'sum'),
    total_closed=('Closed_y', 'sum')
)

# 合并回原表
df2 = df2.join(aggregated)
df2['expected_inclusion_scrap_rate'] = df2['total_inclusions'].div(df2['total_closed']).fillna(None)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:05:31