【问题标题】:is there efficient way for pandas to get tail rows with a condition熊猫有没有有效的方法来获得有条件的尾行
【发布时间】:2022-01-19 12:36:38
【问题描述】:

我想得到有条件的尾行

例如: 我想从“A”列中获取所有负尾行,例如:

    test = pd.DataFrame({'A':[-8, -9, -10, 1, 2, 3, 0, -1,-2,-3]})

我希望有一个“方法”来获得新的框架,例如:

        A
    0  -1
    1  -2
    2  -3

请注意,不确定尾部有多少“负”数。所以我不能运行 test.tail(3)

看起来 pandas 提供的 'tail()' 函数只能以给定的数字运行。

但是我的输入数据框可能太大了,我不想运行一个简单的循环来一一检查

有没有聪明的方法来做到这一点?

【问题讨论】:

    标签: pandas conditional-statements tail


    【解决方案1】:

    尾巴是干什么用的?看来您只需要负数

    test.query("A < 0")
    

    更新:查找符号变化的地方,拆分数组并选择最后一个

    split_points = (test.A.shift(1)<0) == (test.A<0) 
    np.split(test, split_points.loc[lambda x: x==False].index.tolist())[-1]
    

    输出:

        A
    7   -1
    8   -2
    9   -3
    

    【讨论】:

    • 嗨,谢谢,但我只想要尾行,我刚刚更新了描述中的示例,请检查:)
    • 更新了答案
    • 这看起来很优雅,我担心性能,因为它适用于所有数据框
    • 您可以使用 %%timeit 对其进行测试并告诉我们:) @Marco_CH 解决方案也是正确的,而且可能更快
    • 我测试并比较了@Macro_CH 和您的代码,是的,Macro_CH 的答案表现更好
    【解决方案2】:

    只需分享一张比较以上两个给定答案的性能图片 感谢 Patry 和 Macro

    【讨论】:

    • 感谢您提供此比较。不过,很棒的解决方案 Patryk,感谢分享这种方法!
    【解决方案3】:

    这是你想要的吗?

    test = pd.DataFrame({'A':[-8, -9, -10, 1, 2, 3, 0, -1,-2,-3]})
    
    test = test.iloc[::-1]
    
    test.loc[test.index.max():test[test['A'].ge(0)].index[0]+1]
    

    输出:

        A
    9   -3
    8   -2
    7   -1
    

    编辑,如果你想恢复到原来的顺序:

    test.loc[test.index.max():test[test['A'].ge(0)].index[0]+1].iloc[::-1]
    
        A
    7   -1
    8   -2
    9   -3
    

    如果您需要从 0 开始的索引,也可以选择 .reset_index(drop=True)

    【讨论】:

    • 不,你不能假设你知道第一个负数是-1
    • 它不假定第一个数字是-1。这个-1 用于反转数据集。它适用于最后的每个组合,如果没有负数(那么它将返回一个空结果)。
    • 我测试过,正确,性能不错!
    • HI @Marco_CH,经过我的第二轮测试,令我惊讶的是,实际上很多时候,Patryk 的代码可以执行得稍好一些,或者至少两种方法非常相似。由于 Patryk 的代码更容易阅读,所以我最终选择了那个。我只能选择一个解决方案,所以请亲手写下谢谢!
    【解决方案4】:

    我改进了上面的测试,又做了一轮测试,因为我觉得旧的“测试样本”太小了,担心%%time的测量可能不准确。

    我的新测试使用一个非常大的头数,大小为 10000000,尾数为 3 个负数

    因此新测试可以证明整个数据帧大小如何影响整体性能。

    代码如下:

        %%time
        arr = np.arange(1,10000000,1)
        arr = np.concatenate((arr, [-2,-3,-4]))
        test = pd.DataFrame({'A':arr})
        test = test.iloc[::-1]
        test.loc[test.index.max():test[test['A'].ge(0)].index[0]+1].iloc[::-1]
    
        %%time
        arr = np.arange(1,10000000,1)
        arr = np.concatenate((arr, [-2,-3,-4]))
        test = pd.DataFrame({'A':arr})
        split_points = (test.A.shift(1)<0) == (test.A<0) 
        np.split(test, split_points.loc[lambda x: x==False].index.tolist())[-1]
    

    由于系统影响,我测试了 10 次,以上两种方法的性能非常相似。在大约 50% 的情况下,Patryk 的代码甚至执行得更快

    看看下面这张图片

    【讨论】:

    • 感谢您的仔细检查!使用 %%timeit 而不是 %%time 可能会更好 - 它从等式中消除了系统过程。无论如何-在这种情况下,正如您所说,解决方案非常相似。如果你想减少更多时间,而不是使用 np.split 和 split_points 你可以只使用最后一个分割点手动索引:如test[split_points[-1]:] 或类似
    • 哦,是的,这是个好主意
    猜你喜欢
    • 2016-09-18
    • 2019-09-22
    • 2017-08-23
    • 2017-05-08
    • 2017-08-28
    • 2018-11-24
    • 2019-12-10
    • 2021-12-13
    • 1970-01-01
    相关资源
    最近更新 更多