Попытка удалить несколько строк из кадра данных Pandas, но удаляется больше строк, чем предполагалось

У меня есть список, to_delete, индексов строк, которые я хочу удалить из обоих моих двух кадров данных Pandas, df1 и df2. У них по 500 рядов. to_delete имеет 50 записей. Я запускаю это:

df1.drop(df1.index[to_delete], inplace=True)
df2.drop(df2.index[to_delete], inplace=True) 

Но это приводит к тому, что df1 и df2 имеют по 250 строк каждая. Он удаляет 250 строк из каждой, а не 50 конкретных строк, которые я хочу...

to_delete упорядочено в порядке убывания.

Полный метод:

def method(results):
    #results is a 500 x 1 matrix of 1's and -1s
    global df1, df2
    deletions = []
    for i in xrange(len(results)-1, -1, -1):
        if results[i] == -1:
        deletions.append(i)
    df1.drop(df1.index[deletions], inplace=True)
    df2.drop(df2.index[deletions], inplace=True)

Любые предложения относительно того, что я делаю неправильно?

(Я также пытался использовать .iloc вместо .index и удаление в if statement вместо добавления в список первым.

1 ответ

Решение

Ваши значения индекса не являются уникальными, и когда вы используете drop он удаляет все строки с этими значениями индекса. to_delete может иметь длину 50, но было 250 строк, которые имели эти конкретные значения индекса.

Рассмотрим пример

df = pd.DataFrame(dict(A=range(10)), [0, 1, 2, 3, 4] * 2)

df

   A
0  0
1  1
2  2
3  3
4  4
0  5
1  6
2  7
3  8
4  9

Допустим, вы хотите удалить первый, третий и четвертый ряды.

to_del = [0, 2, 3]

Используя ваш метод

df.drop(df.index[to_del])

   A
1  1
4  4
1  6
4  9

Что является проблемой


Опция 1
использование np.in1d найти дополнение to_del
Это более понятно, чем другие. Я ищу в массиве из 0 в n и посмотреть, если это в to_del, Результатом будет логический массив той же длины, что и df, я использую ~ чтобы получить отрицание и использовать это, чтобы нарезать кадр данных.

df[~np.in1d(np.arange(len(df)), to_del)]

   A
1  1
4  4
0  5
1  6
2  7
3  8
4  9

Вариант 2
использование np.bincount найти дополнение to_del
Это выполняет то же самое, что и в варианте 1, путем подсчета позиций, определенных в to_del, Я заканчиваю с массивом 0 а также 1 с 1 в каждой позиции, определенной в to_del а также 0 еще где. Я хочу сохранить 0s, поэтому я делаю логический массив, находя, где он равен 0, Затем я использую это, чтобы разрезать фрейм данных.

df[np.bincount(to_del, minlength=len(df)) == 0]

   A
1  1
4  4
0  5
1  6
2  7
3  8
4  9

Вариант 3
использование np.setdiff1d найти позиции
При этом используется логика установки, чтобы найти разницу между полным массивом позиций и теми, которые я хочу удалить. Я тогда использую iloc выбирать.

df.iloc[np.setdiff1d(np.arange(len(df)), to_del)]

   A
1  1
4  4
0  5
1  6
2  7
3  8
4  9
Другие вопросы по тегам