从 Pandas DataFrame 中删除许多索引范围

Ich*_*xgo 5 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   ...
...     ...   | ...         ...
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

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

当前丑陋的解决方案

for range in ranges:
    df = df.drop(df.loc[range[0]:range[1]].index)
Run Code Online (Sandbox Code Playgroud)

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

方案对比

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

切片以完成一组元组

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

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

表现

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

  1. @ALollz + @Ben。T 的组合解决方案~19 秒

    df.drop(pd.MultiIndex.from_tuples(idx))
    
    Run Code Online (Sandbox Code Playgroud)

    或不创建MultiIndex对象

    df.drop(idx)
    
    Run Code Online (Sandbox Code Playgroud)
  2. @ALollz 第一个解决方案~75 秒

    df.loc[list(set(df.index.values) - set(idx))]
    
    Run Code Online (Sandbox Code Playgroud)
  3. @user3471881 的解决方案~95 秒

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

    see above
    
    Run Code Online (Sandbox Code Playgroud)

ALo*_*llz 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))
Run Code Online (Sandbox Code Playgroud)

输出:

           value(s)
idx1 idx2          
4    0            4
8    4           11
Run Code Online (Sandbox Code Playgroud)

  • 多谢你们!创建完整的索引列表而不是范围就成功了:)。我尝试了所有三种解决方案:您的第一个解决方案@ALollz,您的+ @Ben.T s以及@user3471881提出的以下解决方案。它们都通过将切片转换为完整的元组列表来实现这一点。就性能而言,您可以在顶部看到比较:)!再次感谢。顺便提一句。您的组合解决方案是最快的,您也可以调用“df.drop(idx)”,它与您的解决方案处于相同的速度范围。 (2认同)