针对衰减变量优化python代码的以下部分

时间:2018-09-26 07:11:03

标签: python pandas loops numpy data-science

我正在对包含多个ID的时间序列数据集的已排序数据集'df_pre_decay'进行以下操作,并且我希望以不同的速率衰减每个ID的'tactic'变量(来自tactic_decay_dict)。

为衰落的战术变量'xyz'创建的变量将与第1个月的战术变量具有相同的值,而对于所有其他mnth,它将是(((衰落的战术变量'{ (前一百万个{1}}'乘以rate)和(((当前mnth的战术变量'tactic'的值)乘以(1-rate))

xyz

我想优化此部分代码,因为我的数据集中的500万以上行花费了30分钟以上的时间。

编辑:请找到数据集示例

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])

1 个答案:

答案 0 :(得分:0)

我认为您的代码无法按预期工作,因为您在循环的每一轮中都将整个列df_pre_decay[xyz]有效地设置为单个值。您需要 遍历数据帧的每一行(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)