这是数据框:
import pandas as pd
import numpy as np
df = pd.DataFrame({
"node": np.repeat([0, 1, 2, 3], 3),
"type": np.tile(['A', 'B', 'C'], 4),
"flag": [True, True, True, True, True, False, True, True, True, False, True, True]
})
df.sort_values(by=['type', 'node'], ascending=True, inplace=True)
看起来像:
node type flag
0 0 A True
3 1 A True
6 2 A True
9 3 A False
1 0 B True
4 1 B True
7 2 B True
10 3 B True
2 0 C True
5 1 C False
8 2 C True
11 3 C True
我想要做的是查找任何类型中是否有
False
标志,如果有则获取最底部的节点,并将所有上层节点的标志设置为False
。结果会是这样的:
node type flag
0 0 A False
3 1 A False
6 2 A False
9 3 A False
1 0 B True
4 1 B True
7 2 B True
10 3 B True
2 0 C False
5 1 C False
8 2 C True
11 3 C True
在本例中,输入
A
在节点 False
处得到了 3
,因此节点 1, 2
都应设置为 False
;输入 B
没有 False
,跳过;输入 C
在节点 False
处得到了 1
,因此节点 0
应设置为 False
。
我现在所做的是
gp = df.groupby(['type'])
result_indices = []
for name, group in gp:
false_index = group[group['flag'] == False].index
if len(false_index) > 0:
result_indices.extend(group.index[group.index < false_index[-1]])
df.loc[result_indices, 'flag'] = False
有什么更好的解决方案可以避免for循环吗? (为了提高效率),我曾经尝试过像
mask
或where
这样的方法,但不知道如何编写如此复杂的过滤器。
我可以像这样提取 False
索引:
df.sort_values(by=['type', 'node'], ascending=[True, False], inplace=True)
gp = df[df['flag'] == False].groupby('type').head(1).index
但不知道如何转发。
您可以(错误)使用
cumsum()
进行传播:通过累积和,您可以从上到下传播 True
值;例如,np.cumsum([False, True, True, False]).astype(bool)
生成 [False, True, True, True]
。您的情况的不同之处在于您想要从下到上传播 False
值。不过我们仍然可以使用 cumsum()
:
cumsum()
。bool
并对结果求反。这可能如下所示:
import pandas as pd
import numpy as np
df = pd.DataFrame({
"node": np.repeat([0, 1, 2, 3], 3),
"type": np.tile(['A', 'B', 'C'], 4),
"flag": [True, True, True, True, True, False,
True, True, True, False, True, True]
})
df.sort_values(by=['type', 'node'], ascending=True, inplace=True)
# Reverse order of values
df_rev_neg = df.iloc[::-1]
# Negate values of interest
df_rev_neg["flag"] = ~df_rev_neg["flag"]
# Calculate grouped `cumsum()`, convert back to `bool`, negate values again
df["propagated"] = ~df_rev_neg.groupby("type")["flag"].cumsum().astype(bool)
print(df)
哪个打印:
node type flag propagated
0 0 A True False
3 1 A True False
6 2 A True False
9 3 A False False
1 0 B True True
4 1 B True True
7 2 B True True
10 3 B True True
2 0 C True False
5 1 C False False
8 2 C True True
11 3 C True True
这里我们没有明确需要重新反转值的顺序(步骤 4),因为我们始终携带帧的索引。
这是一种方法:
df
反转您的 [::-1]
,在“类型”上应用 df.groupby
,为“标记”应用 groupby.cummin
,然后反转回来。df['flag'] = df[::-1].groupby('type')['flag'].cummin()[::-1]
df
node type flag
0 0 A False
3 1 A False
6 2 A False
9 3 A False
1 0 B True
4 1 B True
7 2 B True
10 3 B True
2 0 C False
5 1 C False
8 2 C True
11 3 C True