为衰减变量优化以下python代码部分

Posted

技术标签:

【中文标题】为衰减变量优化以下python代码部分【英文标题】:Optimize the following section of python code for decaying variables 【发布时间】:2019-03-01 21:22:02 【问题描述】:

我正在对包含多个 ID 的时间序列数据集的排序数据集“df_pre_decay”执行以下操作,并且我想以不同的速率衰减每个 ID 的“tactic”变量(来自@987654323 @)。

为衰减的策略变量“xyz”创建的变量将与第 1 mnth 中的策略变量具有相同的值,而对于所有其他 mnth,它将是 ((衰减的策略变量 'xyz 的值' 在前 mnth) 乘以 rate) 和 ((当前 mnth 中的策略变量 'tactic' 的值) 乘以 (1-rate))

time_col = 'mnth'
tactic =['overall_details','speaker_total','overall_samples_eu','copay_redemption_count','voucher_redemption_count','dtc']
tactic_decay_dict = dict.fromkeys(tactic,(60,70))

uniq = len(df_pre_decay[time_col].unique())

## Loops for variables and decay rate
for a in tactic_decay_dict:
    for b in tactic_decay_dict[a]:
        xyz = a+'_s'+str(b)
## Loops for iterating over each row in the dataset
        for i in range(len(df_pre_decay)):
            df_pre_decay[xyz] = np.where((i%uniq)!=0,
                                         (df_pre_decay[xyz].iloc[i-1])*b/100+
                                         (df_pre_decay[a].iloc[i])*(100-b)/100,
                                         df_pre_decay[a].iloc[i])

我想优化这部分代码,因为我的数据集中超过 500 万行需要 30 多分钟。

编辑:请找到数据集的样本

ID  mnth    overall_details speaker_total   overall_samples_eu  copay_redemption_count  voucher_redemption_count    dtc
1   201701  3   1   10  9   3   6
1   201702  6   1   0   7   7   10
1   201703  10  8   7   8   9   10
1   201704  3   9   3   0   1   1
1   201705  9   0   8   9   6   4
1   201706  8   3   2   10  8   9
1   201707  3   10  3   0   5   6
1   201708  2   10  3   9   6   2
1   201709  1   3   7   10  8   0
1   201710  3   8   2   8   0   10
1   201711  6   7   4   8   5   6
1   201712  3   8   2   9   4   10
2   201701  7   4   7   4   10  2
2   201702  10  0   2   2   10  5
2   201703  10  6   4   10  5   3
2   201704  4   3   6   4   0   8
2   201705  7   8   9   10  6   10
2   201706  8   0   2   7   1   8
2   201707  10  2   8   1   9   4
2   201708  10  6   7   0   3   5
2   201709  10  10  3   8   9   0
2   201710  2   0   3   5   5   8
2   201711  1   8   0   7   3   4
2   201712  8   5   1   0   7   9
3   201701  2   2   7   7   1   2
3   201702  2   8   10  9   6   9
3   201703  10  5   8   5   9   4
3   201704  6   1   2   4   6   2
3   201705  6   9   4   4   3   0
3   201706  5   1   6   4   1   7
3   201707  0   7   6   9   5   6
3   201708  10  3   2   0   4   5
3   201709  5   8   6   4   10  4
3   201710  8   3   10  6   7   0
3   201711  7   5   6   3   1   10
3   201712  3   9   8   4   10  0

【问题讨论】:

您能发布一些示例数据框吗? (一些小样本,只是为了让算法起作用)。这将非常有帮助 能否分享一个示例输入数据框和输出数据框。 我已经按照你的要求添加了数据集样本 【参考方案1】:

我认为您的代码不会按预期工作,因为您在循环的每一轮中有效地将整列 df_pre_decay[xyz] 设置为单个值。您需要 either 循环遍历数据帧的每一行 (for i in range(len(df_pre_decay))),或将列视为向量(如 np.where 和其他 numpy 函数所做的那样),但您将两者混为一谈。矢量化方法通常会快得多。

对于非矢量化版本,将列 xyz 设置为与列 a 相同,然后遍历行,在需要的地方设置累积值。

for a in tactic_decay_dict:
    for b in tactic_decay_dict[a]:
        xyz = a+'_s'+str(b)
## Loops for iterating over each row in the dataset
        df_pre_decay[xyz] = df_pre_decay[a]
        for i in range(len(df_pre_decay)):
            if i % uniq != 0:
                df_pre_decay[xyz].iloc[i] = (df_pre_decay[xyz].iloc[i-1] * b/100
                     + df_pre_decay[a].iloc[i] * (100 - b)/100)

或替代版本 - 不确定哪个会更快:

for a in tactic_decay_dict:
    for b in tactic_decay_dict[a]:
        xyz = a+'_s'+str(b)
        column = []
        for i, x in enumerate(df_pre_decay[a]):
            if i % uniq == 0:
                current = x
            else:
                current = x * b/100 + current * (100-b)/100
            column.append(current)
        df[xyz] = column

要进行矢量化,您可以使用numpy.ufunc.accumulate 将列分成块并对每个块应用累积衰减函数。

for a in tactic_decay_dict:
    for b in tactic_decay_dict[a]:
        xyz = a+'_s'+str(b)
        decay_func = np.frompyfunc(lambda u, v: u * b / 100.0 + v * (100-b) / 100.0, 2, 1)
        decayed = np.array([])
        for top in range(0, len(df_pre_decay), uniq):
            chunk = df_pre_decay[a][top:top+uniq]
            decayed = np.concatenate((decayed, 
                                  decay_func.accumulate(chunk, dtype=np.object).astype(np.float)))
        df_pre_decay[xyz] = decayed

另一种方法是在不同 ID 之间插入具有空值的空白行。然后,您可以将单个累加函数应用于整个列:

# insert blank rows in the data
df.index = df.index + df.index // uniq
df.reindex(index=range(len(df) + len(df) // uniq))   

def get_decay_func(b):
    def inner(u, v):
        if pd.isnull(u) or pd.isnull(v):
            return v
        else:
            return u * b/100.0 + v * (100-b)/100.0
    return inner

for a in tactic_decay_dict:
   for b in tactic_decay_dict[a]:
        decay = get_decay_func(b).accumulate
        xyz = a+'_s'+str(b)
        df_pre_decay[xyz] = decay(df_pre_decay[a], dtype=np.object).astype(df.float)

【讨论】:

以上是关于为衰减变量优化以下python代码部分的主要内容,如果未能解决你的问题,请参考以下文章

Python中的高效记忆

python基础

Python - 根据记录值拟合指数衰减曲线

39.Python模板结构优化-引入模板include标签模板继承使用详解

python-机器学习-数据标签转化

优化Python编程的4个妙招