【问题标题】:Remove many index ranges from Pandas DataFrame从 Pandas DataFrame 中删除许多索引范围
【发布时间】:2019-04-22 01:38:49
【问题描述】:

问题 + MWE

如何从 Pandas DataFrame 中删除/删除多个范围的行,其(两级)多索引如下所示:

idx1    idx2  |  value(s)   ...
------------------------------------------
4       0     |  1.123456   ...
        1     |  2.234567   ...
        2     |  0.012345   ...
8       0     | -1.123456   ...
        1     | -0.973915   ...
        2     |  1.285553   ...
        3     | -0.194625   ...
        4     | -0.144112   ...
...     ...   | ...         ...

要删除/删除的范围当前位于如下列表中:

ranges = [[(4, 1), (4, 2)],          # range (4,1):(4,2)
          [(8, 0), (8, 3)],          # range (8,0):(8,3)
          [(8, 5), (8, 10)], ...]    # range (8,5):(8,10)

主要问题是,我发现的大多数方法都不支持多索引或切片或多个切片/范围。

最好/最快的方法是什么。

当前丑陋的解决方案

for range in ranges:
    df = df.drop(df.loc[range[0]:range[1]].index)

又慢又丑,但它是我发现的唯一可行的解​​决方案,它结合了多索引、切片和多个范围(通过循环遍历范围)。

方案比较

所有三个提议的解决方案都有效。他们都通过将切片列表转换为这些切片中所有单个元组的列表来解决问题。

切片以完成一组元组

最快的方法是@ALollz 解决方案:

idx = [(x, z) for (x, i), (_, j) in ranges for z in np.arange(i,j+1,1)]

性能

关于行的删除,所有解决方案都有效,但性能差异很大(所有性能数据基于我的数据集,大约 10 个 Mio. 条目)

  1. @ALollz + @Ben. T's combined solution~19 秒

    df.drop(pd.MultiIndex.from_tuples(idx))
    

    或者不创建MultiIndex对象

    df.drop(idx)
    
  2. @ALollz first solution~75 秒

    df.loc[list(set(df.index.values) - set(idx))]
    
  3. @user3471881's solution~95 秒

    df.loc[~df.index.isin(ranges)]
    
  4. 我的丑陋解决方案(~350 秒

    see above
    

【问题讨论】:

  • 使用loc 有用吗?喜欢this question
  • 它有效,它是我目前工作的丑陋解决方案的一部分,但它一次只适用于一个范围,如下所示:df.drop(df.loc[(4,1):(4,2)].index) 我还没有找到一种方法来获取多个范围,并且它也很慢......我还将我目前的丑陋解决方案添加到帖子中。
  • 你有没有联系过pd.slice,或者更好的是indexslice
  • 是的,它们只是为切片提供了一个更好的界面,并且某些功能要求切片采用(4, slice(1,2)) 而不是(4,1):(4,2) 的形式,但它们无法让我规避多范围问题.
  • 您如何构建您的范围列表,它是否需要包含元组列表(成为可切片“范围”的对)或者您是否以这种方式设计它以便使用loc

标签: python pandas


【解决方案1】:

您可以创建一个新的索引列表,正如 Ben.T 指出的那样,只需删除它们。

import numpy as np
import pandas as pd

idx = [(x, z) for (x, i), (_, j) in ranges for z in np.arange(i,j+1,1)]
df.drop(pd.MultiIndex.from_tuples(idx))

输出:

           value(s)
idx1 idx2          
4    0            4
8    4           11

【讨论】:

  • 对我来说,您的解决方案会删除除范围之外的所有内容,我想删除。所以它基本上与我想做的相反。
  • 您也可以将drop 与您的idx 一起使用,例如df.drop(pd.MultiIndex.from_tuples(idx))
  • 谢谢大家!创建完整的索引列表而不是范围是诀窍:)。我尝试了所有三种解决方案:你的第一个@ALollz,你的 + @Ben.T s 和@user3471881 提出的下面的一个。基于将切片转换为完整的元组列表,它们都可以做到这一点。性能方面,您可以在顶部看到比较:)!再次感谢。顺便提一句。您的组合解决方案是最快的,您也可以拨打df.drop(idx),它与您的解决方案在相同的速度范围内。
【解决方案2】:

您使用的范围列表迫使我们使用多个切片,这可能很好,但似乎不是您想要的。

如果你用你想要删除的所有索引填充你的列表(你在评论中说你可以这样做):

ranges = [(4, 1), (4, 2), (8, 0), (8, 1), (8, 2), (8, 3) ... ]

您可以访问DataFrameindex 并检查isin() 是否是您的元组列表。

df.index.isin(ranges)

要删除范围列表中的索引,请添加波浪号,然后用作掩码。

df[~df.index.isin(ranges)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-25
    • 2021-03-07
    • 2023-04-05
    • 2021-08-25
    • 1970-01-01
    • 2019-02-06
    • 2019-04-13
    • 2017-09-25
    相关资源
    最近更新 更多