Срез Dataframe не удаляет значения индекса

python pandas

1346 просмотра

3 ответа

1934 Репутация автора

У меня недавно была эта проблема с большим фреймом данных и связанным с ним мультииндексом. Этот упрощенный пример продемонстрирует проблему.

import pandas as pd
import numpy as np

np.random.seed(1)
idx = pd.MultiIndex.from_product([['A','B'],[5,6]])


df = pd.DataFrame(data= np.random.randint(1,100,(4)),index= idx,columns =['P'])
print df

Который дает:

      P
A 5  38
  6  13
B 5  73
  6  10

Теперь взглянем на индекс

print df.index

MultiIndex(levels=[[u'A', u'B'], [5, 6]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]])

Если я нарежу этот фрейм данных, я замечу, что мультииндекс никогда не сгущается. Даже с глубокой копией.

Каков наилучший способ уменьшить объем памяти индекса в операции среза?

df_slice = df[df['P']>20]
print df_slice
print df_slice.index

      P
A 5  38
B 5  73

Посмотрите, как уменьшился размер информационного кадра, а индекс - нет.

MultiIndex(levels=[[u'A', u'B'], [5, 6]],
           labels=[[0, 1], [0, 0]])

Даже с копией (глубокий = True)

df_slice = df[df['P']>20].copy(deep=True)
print df_slice.index


MultiIndex(levels=[[u'A', u'B'], [5, 6]]
    ,labels=[[0, 1], [0, 0]])

Я бы ожидал, что MultiIndex удалит 6, как показано:

MultiIndex(levels=[[u'A', u'B'], [5]]
    ,labels=[[0, 1], [0, 0]])

Проблема возникает на практике, когда размер кадра данных велик.

Автор: Dickster Источник Размещён: 15.09.2015 11:34

Ответы (3)


1 плюс

624 Репутация автора

Вы можете сделать MultiIndex уникальным путем

df_slice.index = pd.MultiIndex.from_tuples(df_slice.index.unique(), names=idx.names)

который дает индекс

MultiIndex(levels=[[u'A', u'B'], [5]],
           labels=[[0, 1], [0, 0]])
Автор: desiato Размещён: 15.09.2015 11:49

4 плюса

548 Репутация автора

Решение

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

Во-первых, мы должны объявить, что индексы должны быть неизменными. Вы можете проверить больше документации здесь -> http://pandas.pydata.org/pandas-docs/stable/indexing.html#setting-metadata

Когда вы создаете объект dataframe, давайте назовем его, dfи вы захотите получить доступ к его строкам, в основном все, что вы делаете, это передаете логический ряд, который Pandas будет сопоставлять с соответствующим индексом.

Следуйте этому примеру:

index = pd.MultiIndex.from_product([['A','B'],[5,6]])
df = pd.DataFrame(data=np.random.randint(1,100,(4)), index=index, columns=["P"])

      P
A 5   5
  6  51
B 5  93
  6  76

Теперь предположим, что мы хотим выбрать строки с P> 90 . Как бы Вы это сделали? df[df["P"] > 90], правильно? Но посмотрите, что на самом деле возвращает df ["P"]> 90.

A  5     True
   6     True
B  5     True
   6    False
Name: P, dtype: bool

Как видите, он возвращает логический ряд, соответствующий исходному индексу. Почему? Поскольку Pandas необходимо отобразить, какие значения индекса имеют эквивалентное истинное значение, он может выбрать правильный результат. Таким образом, в основном, во время операций над слайсом вы всегда будете нести этот индекс, потому что это элемент отображения для объекта.

Однако надежда не ушла. В зависимости от вашего приложения, если вы считаете, что оно на самом деле занимает огромную часть вашей памяти, вы можете потратить немного времени на выполнение следующих действий:

def df_sliced_index(df):
    new_index = []
    rows = []
    for ind, row in df.iterrows():
        new_index.append(ind)
        rows.append(row)
    return pd.DataFrame(data=rows, index=pd.MultiIndex.from_tuples(new_index))

df_sliced_index(df[df['P'] > 90]).index

Что дает то, что я считаю, это желаемый результат:

MultiIndex(levels=[[u'B'], [5]], labels=[[0], [0]])

Но если данные слишком велики, чтобы беспокоить вас о размере индекса, мне интересно, сколько это может стоить вам с точки зрения времени.

Автор: Ricardo Silveira Размещён: 15.09.2015 12:48

0 плюса

183992 Репутация автора

Мой предпочтительный способ сделать это

old_idx = df_slice.index
new_idx = pd.MultiIndex.from_tuples(old_idx.to_series(), names=old_idx.names)
Автор: piRSquared Размещён: 02.09.2016 06:59
Вопросы из категории :
32x32