在 Pandas 中向量化条件更新操作

Vectorizing a Conditional Update Operation in Pandas

我的第一个问题在这里!我正在寻求有关如何矢量化 pandas 数据帧上的操作的帮助。我可以将问题简化为具有三列的数据框,一列具有将要更新的值,两列具有迭代编号,两列之间的迭代编号不同。

我想做的是针对其中一个迭代列,针对迭代列中的每个第一个值,然后引用另一个迭代列(在同一索引处)的相应值,然后最后用更新值向列填充一个值(零),但仅适用于第二个迭代列具有相同值的行。希望这个例子能更好地解释:

df = pd.DataFrame()
df['update_col'] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
df['iter2'] = [0, 1, 1, 2, 2, 3, 3, 4, 4]
df['iter1'] = [0, 0, 1, 1, 1, 2, 2, 2, 2]

print(df)
#     update_col    iter2     iter1
0              1        0         0
1              2        1         0
2              3        1         1
3              4        2         1
4              5        2         1
5              6        3         2
6              7        3         2
7              8        4         2
8              9        4         2

基本上,我想执行以下操作:

  1. 引用 iter1 列,以及它何时更改(即从 0 变为 1 或从 1 变为 2)
  2. 查看该索引处的 iter2 列
  3. 将第 2 步中从索引开始的所有行的 "update column" 中的值更改为零,直到 iter2 递增到新值

因此输出如下所示:

#     update_col    iter2     iter1
0              1        0         0
1              2        1         0
2              0        1         1
3              4        2         1
4              5        2         1
5              0        3         2
6              0        3         2
7              8        4         2
8              9        4         2

我认为一个正确构建的 groupby 可能是一个解决方案,但我仍然是一个有效使用它的新手。

我目前正在通过一个复杂的 for 循环实现我想要的,这使得 运行 时间对于我必须这样做的数据帧的大小和数量来说非常长。我认为另一个解决方案可能是 mapreplace 操作,但复杂的警告是我不想更新 iter2 的那个值的所有值,只更新那个索引的值iter 1 直到 iter2 中的最后一个值。

非常感谢任何帮助或见解!

这可能不是您已经定义的循环的巨大改进,但我认为它至少消除了使用嵌套循环的需要:

import pandas as pd

# creating data frame
df = pd.DataFrame()
df['update_col'] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
df['iter2'] = [0, 1, 1, 2, 2, 3, 3, 4, 4]
df['iter1'] = [0, 0, 1, 1, 1, 2, 2, 2, 2]

# computing difference from prev element by creating a shifted col 
# and subtracting from the original.
# (you could also use a rolling window function for this)
df['change1'] = df['iter1'] - df['iter1'].shift(1)
df['change2'] = df['iter2'] - df['iter2'].shift(1)

# creating boolean cols to flag if iter1 or iter2 have changed
df['start'] = df['change1'] == 1
df['stop'] = df['change2'] == 1

# list to store result: if True, you update value to 0
res = [False] * len(df['start'])

for i in range(0, len(df['start'])):
    if df['start'][i]:
        #print('start detected')
        res[i] = True
    elif i > 1 and (not df['stop'][i]) and res[i-1]: 
        #print('continuation detected')
        res[i] = True
    #print(f'set res[{i}] to ', res[i])

df['update_to_zero'] = res

这导致了这个 df:

   update_col  iter2  iter1  change1  change2  start   stop  update_to_zero
0           1      0      0      NaN      NaN  False  False           False
1           2      1      0      0.0      1.0  False   True           False
2           3      1      1      1.0      0.0   True  False            True
3           4      2      1      0.0      1.0  False   True           False
4           5      2      1      0.0      0.0  False  False           False
5           6      3      2      1.0      1.0   True   True            True
6           7      3      2      0.0      0.0  False  False            True
7           8      4      2      0.0      1.0  False   True           False
8           9      4      2      0.0      0.0  False  False           False

希望对您有所帮助!