在 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
基本上,我想执行以下操作:
- 引用 iter1 列,以及它何时更改(即从 0 变为 1 或从 1 变为 2)
- 查看该索引处的 iter2 列
- 将第 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 循环实现我想要的,这使得 运行 时间对于我必须这样做的数据帧的大小和数量来说非常长。我认为另一个解决方案可能是 map
或 replace
操作,但复杂的警告是我不想更新 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
希望对您有所帮助!
我的第一个问题在这里!我正在寻求有关如何矢量化 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
基本上,我想执行以下操作:
- 引用 iter1 列,以及它何时更改(即从 0 变为 1 或从 1 变为 2)
- 查看该索引处的 iter2 列
- 将第 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 循环实现我想要的,这使得 运行 时间对于我必须这样做的数据帧的大小和数量来说非常长。我认为另一个解决方案可能是 map
或 replace
操作,但复杂的警告是我不想更新 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
希望对您有所帮助!