从Pandas DataFrame删除许多索引范围

时间:2018-11-19 16:31:00

标签: python pandas

问题+ 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
    

2 个答案:

答案 0 :(得分:2)

您可以创建一个新的索引列表,正如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

答案 1 :(得分:0)

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

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

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

您可以仅访问index中的DataFrame并检查它是否isin()元组列表。

df.index.isin(ranges)

要删除范围列表中的索引,请添加代字号,然后用作遮罩。

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