【问题标题】:Find index of last true value in pandas Series or DataFrame在 pandas Series 或 DataFrame 中查找最后一个真值的索引
【发布时间】:2015-12-21 05:52:01
【问题描述】:

我正在尝试查找 pandas 布尔系列中最后一个 True 值的索引。我当前的代码如下所示。有没有更快或更清洁的方法?

import numpy as np
import pandas as pd
import string

index = np.random.choice(list(string.ascii_lowercase), size=1000)
df = pd.DataFrame(np.random.randn(1000, 2), index=index)
s = pd.Series(np.random.choice([True, False], size=1000), index=index)

last_true_idx_s = s.index[s][-1]
last_true_idx_df = df[s].iloc[-1].name

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    你可以使用 idxmax 和 Andy Hayden answerargmax 一样的东西:

    print s[::-1].idxmax()
    

    比较:

    这些时间将在很大程度上取决于 s 的大小以及 Trues 的数量(和位置) - thanks.

    In [2]: %timeit s.index[s][-1]
    The slowest run took 6.92 times longer than the fastest. This could mean that an intermediate result is being cached 
    10000 loops, best of 3: 35 µs per loop
    
    In [3]: %timeit s[::-1].argmax()
    The slowest run took 6.67 times longer than the fastest. This could mean that an intermediate result is being cached 
    10000 loops, best of 3: 126 µs per loop
    
    In [4]: %timeit s[::-1].idxmax()
    The slowest run took 6.55 times longer than the fastest. This could mean that an intermediate result is being cached 
    10000 loops, best of 3: 127 µs per loop
    
    In [5]: %timeit s[s==True].last_valid_index()
    The slowest run took 8.10 times longer than the fastest. This could mean that an intermediate result is being cached 
    1000 loops, best of 3: 261 µs per loop
    
    In [6]: %timeit (s[s==True].index.tolist()[-1])
    The slowest run took 6.11 times longer than the fastest. This could mean that an intermediate result is being cached 
    1000 loops, best of 3: 239 µs per loop
    
    In [7]: %timeit (s[s==True].index[-1])
    The slowest run took 5.75 times longer than the fastest. This could mean that an intermediate result is being cached 
    1000 loops, best of 3: 227 µs per loop
    

    编辑:

    下一个解决方案:

    print s[s==True].index[-1]
    

    EDIT1:解决方案

    (s[s==True].index.tolist()[-1])
    

    在已删除的答案中。

    【讨论】:

    • idxmax不是同一种方法吗?
    • 你怎么看?为什么其中一些没有从熊猫中删除?我很好奇。
    • 我认为 used 的情况是np.argmax(因此.argmax)会落入pandas .values numpy 数组,即不返回系列.现在np.argmax 返回一个系列。
    • 由你决定,但我会说未来的答案:你应该分开你的 timeit 电话(这样更容易看出哪个答案是哪个电话的)。 :) 也就是说,这些时间将非常依赖于 s 的大小以及 True 的数量(和位置)。
    • 请注意,如果您的系列不包含任何 True,则使用 idxmax 的结果是不正确的。
    【解决方案2】:

    使用last_valid_index:

    In [9]:
    s.tail(10)
    
    Out[9]:
    h    False
    w     True
    h    False
    r     True
    q    False
    b    False
    p    False
    e    False
    q    False
    d    False
    dtype: bool
    
    In [8]:
    s[s==True].last_valid_index()
    
    Out[8]:
    'r'
    

    【讨论】:

    • 这是最好的解决方案。我认为last_valid_indexidxmax 更清晰。
    • 我认为这种行为不是有意的:“如果所有元素都是非 NA/null,则返回 None。” False 不为空。
    【解决方案3】:

    argmax 获得第一个 True。在 reversed 系列上使用 argmax:

    In [11]: s[::-1].argmax()
    Out[11]: 'e'
    

    这里:

    In [12]: s.tail()
    Out[12]:
    n     True
    e     True
    k    False
    d    False
    l    False
    dtype: bool
    

    【讨论】:

    • 我得到1000 loops, best of 3: 638 µs per loop 1000 loops, best of 3: 284 µs per loop 的时间,将我的方法与你的方法进行比较+1
    • @EdChum 有一件事有点烦人,那就是反转会创建一个副本(IIUC)......你可以降到值并使用可能会稍微快一点的 numpy 反转视图(但 IMO 少得多可读)本质上是 O(1)。
    • @AndyHayden 我猜argmax 在这里工作的原因还不是很明显,但它仍然更快,这通常很重要
    • 是的,最坏的情况是 O(n) 和短路。但它确实看起来更神奇(描述性更少)。
    • 请注意,如果您的系列不包含任何 True,则使用此解决方案的结果是不正确的。
    猜你喜欢
    • 2014-11-26
    • 2016-02-28
    • 2017-04-30
    • 1970-01-01
    • 2016-10-06
    • 2017-07-12
    • 2019-12-09
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多