提问人:x_Amir_x 提问时间:11/5/2023 最后编辑:cottontailx_Amir_x 更新时间:11/6/2023 访问量:167
查找满足掩码条件的最后一行
Finding the last row that meets conditions of a mask
问:
这是我的数据帧:
df = pd.DataFrame({'a': [20, 21, 333, 444], 'b': [20, 20, 20, 20]})
我想使用这个掩码创建列:c
mask = (df.a >= df.b)
我想获取满足此条件的最后一行并创建列。我想要的输出如下所示:c
a b c
0 20 20 NaN
1 21 20 NaN
2 333 20 NaN
3 444 20 x
我尝试了下面的代码,但没有用:
df.loc[mask.cumsum().gt(1) & mask, 'c'] = 'x'
答:
2赞
mandy8055
11/5/2023
#1
与其检查累积总和是否大于 1,不如检查累积总和是否等于最大累积总和值,这相当于获得 [@Onyambu建议]。mask.sum()
df.loc[(mask.cumsum() == mask.sum()) & mask, 'c'] = 'x'
评论
1赞
Onyambu
11/5/2023
mask.cumsum() == mask.sum()
1赞
mandy8055
11/5/2023
@Onyambu哇,谢谢。所以基本上使用它的原因是它直接给了我们掩码中的值总数。如果我对你的观点的理解是错误的,请纠正我。我没想过。mask.sum()
True
1赞
Nick
11/5/2023
这个答案是错误的。看看如果出现以下情况会发生什么df.loc[3, 'a'] = 8
2赞
Nick
11/5/2023
请注意,这是一个相当简单的修复程序:df.loc[(mask.cumsum() == mask.sum()) & mask, 'c'] = 'x'
2赞
cottontail
11/5/2023
#2
要使掩码标记满足条件的最后一个值,请使用 keep last。我们知道它最多由 2 个值 (True/False) 组成。如果我们可以创建另一个掩码,将这些值的最后一次出现标记为 True,那么我们可以将其与所需的掩码本身链接。这是通过以下方式实现的:因为除了最后一次出现之外,标记重复为 True,因此它的否定为我们提供了我们想要的东西。duplicated()
mask
mask
~mask.duplicated(keep='last')
mask.duplicated(keep='last')
df = pd.DataFrame({'a': [20, 21, 333, 444], 'b': [20, 20, 20, 20]})
mask = (df.a >= df.b)
df['c'] = pd.Series('x', df.index).where(mask & ~mask.duplicated(keep='last'))
如果要切片/分配,也可以使用此链接蒙版。
df.loc[mask & ~mask.duplicated(keep='last'), 'c'] = 'x'
@mandy8055 的答案的简短版本是调用以获取最高 cum sum 的索引(尽管这在 pandas 2.1.0 上显示 FutureWarning)。正如 @mozway 所指出的,只要 中至少有一个 True 值,这就可以工作。idxmax()
mask
df.loc[mask.cumsum().idxmax(), 'c'] = 'x'
评论
1赞
Nick
11/5/2023
@Amir不用担心;请注意,另一个答案有一个简单的修复,请参阅我的评论。
0赞
mozway
11/5/2023
但是如果没有匹配;)也会失败idxmax
0赞
mozway
11/5/2023
是的,这会在第一行放置一个“x”
0赞
mozway
11/5/2023
@cottontail是的,不确定在这种情况下需要什么(对我来说似乎没有必要一列 Nan),如果需要,您可以添加一个else
1赞
mozway
11/5/2023
#3
您可以在调用 idxmax
以获取最后一个值之前还原掩码:
mask = (df.a >= df.b)
m = mask[mask][::-1]
if len(m):
df.loc[m.idxmax(), 'c'] = 'x'
#else:
# df['c'] = float('nan')
输出:
a b c
0 20 20 NaN
1 21 20 NaN
2 333 20 NaN
3 444 20 x
评论
0赞
x_Amir_x
11/5/2023
我应该接受哪个答案?:)你是对的。我读了你的评论。
0赞
mozway
11/5/2023
接受你最喜欢的任何东西。我认为目前公认的答案中的第一种方法是完全可以的;)
0赞
x_Amir_x
11/5/2023
我想知道你的选择是什么:)
0赞
mozway
11/5/2023
这取决于您的真实数据。它有多大?“c”列是否预先存在?
1赞
mozway
11/5/2023
然后确定不同的方法,亲眼看看什么是最好的;)
2赞
Anna Andreeva Rogotulka
11/6/2023
#4
您可以使用 mask 的最后一个索引为 True,然后将此值更改为“x”at
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': [20, 21, 333, 444], 'b': [20, 20, 20, 20]})
mask = (df.a >= df.b)
df['c'] = np.nan
last_index = df[mask].index[-1]
df.at[last_index, 'c'] = 'x'
print(df)
评论