Удалить множество диапазонов индексов из Pandas DataFrame - PullRequest
0 голосов
/ 19 ноября 2018

Вопрос + 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   ...
...     ...   | ...         ...

Диапазоны дляdrop / remove в настоящее время находятся в списке, подобном следующему:

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 млн записей)

  1. @ ALollz + @Ben.Объединенное решение T ( ~ 19 сек. )

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

    или без создания MultiIndex объекта

    df.drop(idx)
    
  2. @ Первое решение ALollz ( ~ 75 сек. )

    df.loc[list(set(df.index.values) - set(idx))]
    
  3. @ решение user3471881 (~ 95 сек. )

    df.loc[~df.index.isin(ranges)]
    
  4. мой уродливый раствор ( ~ 350 сек. )

    see above
    

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Список диапазонов, который вы используете, вынуждает нас использовать несколько срезов, что может быть хорошо, но, похоже, не то, что вы хотите.

Если вы вместо этого заполните свой список всеми индексами, которые вы хотите удалить (вы сказали в комментарии, что можете это сделать):

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)]
0 голосов
/ 19 ноября 2018

Вы можете создать новый список индексов и, как указывает 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...