【问题标题】:Is there an alternative, faster approach than idxmax? [duplicate]有没有比 idxmax 更快的替代方法? [复制]
【发布时间】:2018-12-05 07:58:38
【问题描述】:
import time
np.random.seed(0)
df = pd.DataFrame({'gr': np.random.choice(7000, 500000),
              'col': np.random.choice(1000, 500000)})
groups = df.groupby('gr')
t1 = time.time()
idx = groups.col.idxmax()
print(round(time.time() - t1,1))
0.7

有没有办法比使用 idxmax() 更快地获得这些 indeces?

注意,我对idx.values 感兴趣,我不介意丢失idxidx.index() series

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    在我看来,使用 drop_duplicatesgroupby idxmax 快,大约快 8 倍

    %timeit df.sort_values(['gr','col']).drop_duplicates('gr',keep='last').index
    10 loops, best of 3: 67.3 ms per loop
    %timeit df.groupby('gr').col.idxmax()
    1 loop, best of 3: 491 ms per loop
    

    【讨论】:

    • @jezrael 是的,你是对的,这是 dup man :-),谢谢你的发现,也从接受的答案中学习
    • 感谢您的回答。实际上,您的方法更快,因为我的示例有许多较小的组。但是,您的解决方案不会返回与我的代码相同的结果。你能查一下吗?
    • @jezrael 要我删除它吗?
    • @jezrael 我试过了,在我转换 com viki 后,他接受了,我现在无法删除它......
    • 为了得到正确的结果,需要尊重排序的稳定性。使用稳定的排序,对于具有相同排序值的事物,顺序不会改变。如果你按升序排序然后最后一个,这会搞砸。因此,您希望降序排序使用稳定的排序算法,如mergesort。使用df.sort_values(['gr', 'col'], ascending=False, kind='mergesort').drop_duplicates('gr').index
    【解决方案2】:

    Numba 即时编译

    from numba import njit
    
    @njit
    def idxmax_(bins, k, weights):
        out = np.zeros(k, np.int64)
        trk = np.zeros(k)
        for i, w in enumerate(weights - (weights.min() - 1)):
            b = bins[i]
            if w > trk[b]:
                trk[b] = w
                out[b] = i
        return np.sort(out)
    
    def idxmax(df):
        f, u = pd.factorize(df.gr)
        return idxmax_(f, len(u), df.col.values)
    
    idxmax(df)
    
    array([   156,    220,    258, ..., 499945, 499967, 499982])
    

    为了编译它,请确保初始化函数

    idxmax(df.head())
    

    那就计时

    %timeit idxmax(df)
    %timeit df.sort_values(['gr', 'col'], ascending=False).drop_duplicates('gr').index
    
    6.07 ms ± 15.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    152 ms ± 498 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    比较相等

    idx0 = df.groupby('gr').col.idxmax().sort_values().values
    idx1 = idxmax(df)
    idx2 = df.sort_values(
        ['gr', 'col'],
        ascending=False
    ).drop_duplicates('gr').index.sort_values().values
    
    print((idx0 == idx1).all(), (idx0 == idx2).all(), sep='\n')
    
    True
    True
    

    【讨论】:

    • 非常感谢您的回答。几点。出于某种原因,idxmax() 不会返回与groups.col.idxmax() 相同的结果。此外,您正在计时的drop_duplicates 方法也不会返回与idxmax() 相同的结果。它需要ascending=True 中的sort_valueskeep='last' 中的drop_duplicates。最后,至少在我的版本中,即使您正在计时的 2 种方法似乎也不会返回相同的结果(python 3.5.0pandas '0.18.1'
    • 您可能没有排序。我更新了我的帖子验证平等。
    • 哦,我明白了,好吧,你是 100% 正确的。但如果我可能会问,为什么需要按索引号排序?按组 id (gr) 对索引进行排序不是更有意义吗,这就是在没有idxmax() 中的.sort_values() 位的情况下返回结果的方式?我是否很难相应地调整您的解决方案?非常感谢
    • 您可以通过返回 out 而不是 np.sort(out) 来调整我的解决方案。
    猜你喜欢
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2021-12-19
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    相关资源
    最近更新 更多