从系列/列中查找第一个元素的索引(例如“True”)
Posted
技术标签:
【中文标题】从系列/列中查找第一个元素的索引(例如“True”)【英文标题】:Finding the index of the first element (e.g "True") from a series/column 【发布时间】:2018-07-15 23:59:50 【问题描述】:如何在系列或列中找到元素的索引(例如“True”)?
例如,我有一个列,我想在其中确定事件发生的第一个实例。所以我把它写成
Variable = df["Force"] < event
然后创建一个布尔系列的数据,它是假的,直到第一个实例它变成真。那么如何找到数据点的索引?
有没有更好的办法?
【问题讨论】:
【参考方案1】:这是一个全熊猫解决方案,我认为它比其他一些答案更简洁。它还能够处理输入序列的值不满足条件的极端情况。
def first_index_ordered(mask):
assert mask.index.is_monotonic_increasing
assert mask.dtype == bool
idx_min = mask[mask].index.min()
return None if pd.isna(idx_min) else idx_min
col = "foo"
thr = 42
mask = df[col] < thr
idx_first = first_index_ordered(mask)
以上假设mask
有一个按值排序的单调递增索引。如果不是这种情况,我们必须做更多的事情:
def first_index_unordered(mask):
assert mask.dtype == bool
index = mask.index
# This creates a RangeIndex, which is monotonic
mask = mask.reset_index(drop=True)
idx_min = mask[mask].index.min()
return None if pd.isna(idx_min) else index[idx_min]
当然,我们可以将这两种情况结合在一个函数中:
def first_index_where(mask):
if mask.index.is_monotonic_increasing:
return first_index_ordered(mask)
else:
return first_index_unordered(mask)
【讨论】:
【参考方案2】:下面是一个我觉得很容易适应的非熊猫解决方案:
import pandas as pd
df = pd.DataFrame(dict(Force=[5, 4, 3, 2, 1]), list('abcde'))
next(idx for idx, x in zip(df.index, df.Force) if x < 3) # d
它通过迭代生成器表达式的第一个结果来工作。
相比之下,熊猫似乎表现不佳:
df = pd.DataFrame(dict(Force=np.random.randint(0, 100000, 100000)))
n = 99900
%timeit df['Force'].lt(n).idxmin()
# 1000 loops, best of 3: 1.57 ms per loop
%timeit df.Force.where(df.Force > n).first_valid_index()
# 100 loops, best of 3: 1.61 ms per loop
%timeit next(idx for idx, x in zip(df.index, df.Force) if x > n)
# 10000 loops, best of 3: 100 µs per loop
【讨论】:
不错的方法,具有公平的性能评估。如果想在没有元素满足条件的情况下避免StopIteration
异常,只需使用带有默认值的next
,例如:next(gen, None)
【参考方案3】:
您也可以尝试first_valid_index
和where
。
df = pd.DataFrame([[5], [4], [3], [2], [1]], columns=["Force"])
df.Force.where(df.Force < 3).first_valid_index()
3
where
会将不满足条件的部分替换为np.nan
默认。然后,我们找到该系列中的第一个有效索引。
或者这个:选择您感兴趣的项目的一个子集,这里是Variable == 1
。然后找到其索引中的第一项。
df = pd.DataFrame([[5], [4], [3], [2], [1]], columns=["Force"])
v = (df["Force"] < 3)
v[v == 1].index[0]
奖励:如果您需要多种物品的首次出现索引,您可以使用drop_duplicates
。
df = pd.DataFrame([["yello"], ["yello"], ["blue"], ["red"], ["blue"], ["red"]], columns=["Force"])
df.Force.drop_duplicates().reset_index()
index Force
0 0 yello
1 2 blue
2 3 red
还有一些工作......
df.Force.drop_duplicates().reset_index().set_index("Force").to_dict()["index"]
'blue': 2, 'red': 3, 'yello': 0
【讨论】:
【参考方案4】:使用idxmax
查找最大值的第一个实例。在这种情况下,True
是最大值。
df['Force'].lt(event).idxmax()
考虑样本df
:
df = pd.DataFrame(dict(Force=[5, 4, 3, 2, 1]), list('abcde'))
df
Force
a 5
b 4
c 3
d 2
e 1
Force
小于3
的第一个实例位于索引'd'
。
df['Force'].lt(3).idxmax()
'd'
请注意,如果 Force
的任何值都不小于 3,则最大值将为 False
,第一个实例将是第一个实例。
同时考虑替代argmax
df.Force.lt(3).values.argmax()
3
它返回最大值的第一个实例的位置。然后你可以使用它来找到对应的index
值:
df.index[df.Force.lt(3).values.argmax()]
'd'
另外,在未来,argmax
将是一个 Series 方法。
【讨论】:
您好,谢谢。这比编写循环要容易得多。效果很好。以上是关于从系列/列中查找第一个元素的索引(例如“True”)的主要内容,如果未能解决你的问题,请参考以下文章