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

如何避免循环:用移位求和优化Awaken时长截断及转移逻辑?

向量化处理Awaken时长截断与超出值转移问题

问题分析

你的循环代码逻辑是:

  • 截断Awaken活动时长至0.048秒,超出部分存入临时变量threshold
  • 遇到下一个非Awaken活动时,将threshold加到该活动时长,然后清零threshold
  • 若连续遇到Awaken活动,后续的超出值会覆盖之前的threshold,导致前序超出值丢失

向量化代码出错的原因:

  1. 变量名笔误:awaken_mask未定义,应为awaken_cond
  2. 逻辑缺陷:直接将超出值移至下一行,未处理连续Awaken的场景,且shift产生的NaN会污染目标行数据

解决方案1:严格匹配循环逻辑

该实现完全复刻循环代码的行为(连续Awaken仅保留最后一个的超出值),适合200万行数据的高效处理:

import numpy as np
import pandas as pd

# 配置参数
THRESHOLD = 0.048

# 1. 预处理:标记Awaken活动,保存原始时长
df['original_duration'] = df['Duration'].copy()
awaken = df['Activity'] == 'Awaken'
df.loc[awaken, 'Duration'] = np.minimum(df.loc[awaken, 'original_duration'], THRESHOLD)
df['excess'] = np.where(awaken, df['original_duration'] - df['Duration'], 0)

# 2. 分组标记连续Awaken块,仅保留每组最后一个的超出值
df['group'] = (~awaken).cumsum()
df['excess_to_pass'] = df.groupby('group')['excess'].transform(
    lambda x: x.iloc[-1] if x.any() else 0
)

# 3. 映射超出值到下一个非Awaken活动
# 建立group到下一个非Awaken索引的映射
next_non_awaken_map = {}
current_non_awaken_idx = None
# 倒序遍历,记录每个group对应的下一个非Awaken索引
for idx in reversed(df.index):
    if not awaken.loc[idx]:
        current_non_awaken_idx = idx
    else:
        group = df.loc[idx, 'group']
        next_non_awaken_map[group] = current_non_awaken_idx

# 4. 将超出值累加到目标行
df['target_idx'] = df['group'].map(next_non_awaken_map)
excess_total = df.groupby('target_idx')['excess_to_pass'].sum()
df.loc[excess_total.index, 'Duration'] += excess_total

# 清理临时列
df.drop(['original_duration', 'excess', 'group', 'excess_to_pass', 'target_idx'], axis=1, inplace=True)

解决方案2:累积所有连续Awaken的超出值(更符合原始需求)

如果你的真实需求是将所有连续Awaken的超出值累积到下一个非Awaken活动,而非仅保留最后一个,以下实现更高效且合理:

import numpy as np
import pandas as pd

THRESHOLD = 0.048

# 1. 保存原始时长,截断Awaken时长
df['original_duration'] = df['Duration'].copy()
awaken = df['Activity'] == 'Awaken'
df.loc[awaken, 'Duration'] = df.loc[awaken, 'original_duration'].clip(upper=THRESHOLD)
df['excess'] = np.where(awaken, df['original_duration'] - df['Duration'], 0)

# 2. 从后往前填充每个位置对应的下一个非Awaken活动索引
df['next_non_awaken'] = np.where(~awaken, df.index, np.nan)
df['next_non_awaken'] = df['next_non_awaken'].bfill()

# 3. 按目标索引分组求和超出值,累加到对应时长
excess_total = df.groupby('next_non_awaken')['excess'].sum()
df['Duration'] += df['next_non_awaken'].map(excess_total).fillna(0)

# 清理临时列
df.drop(['original_duration', 'excess', 'next_non_awaken'], axis=1, inplace=True)

效果验证

以你的示例数据测试,两种方案都会得到以下结果:

Duration Activity
2157    2.02120    Twitch
2158    2.21839     Sleep
2159    0.04800    Awaken
2160    1.03649       Dig

(注:0.44367 + (0.64086 - 0.048) = 1.03649)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 12:47:02