Dataframe Slice不会删除索引值

时间:2015-09-15 11:34:26

标签: python pandas

我最近遇到了一个大型数据帧及其相关多索引的问题。 这个简化的例子将证明这个问题。

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]])

即使使用.copy(深度=真)

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]])

当数据框很大时,问题就出现了。

3 个答案:

答案 0 :(得分:4)

我理解你的担忧,但我相信你必须看看熊猫低级应用程序中发生了什么。

首先,我们必须声明索引应该是不可变的。您可以在此处查看更多文档 - > http://pandas.pydata.org/pandas-docs/stable/indexing.html#setting-metadata

当你创建一个数据框对象时,让它命名为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]])

但如果数据太大而无法担心索引的大小,我想知道在时间方面可能会花多少钱。

答案 1 :(得分:1)

您可以通过

使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]])

答案 2 :(得分:0)

我首选的方法是

old_idx = df_slice.index
new_idx = pd.MultiIndex.from_tuples(old_idx.to_series(), names=old_idx.names)