我最近遇到了一个大型数据框及其关联的多索引的问题。这个简化的例子将演示这个问题。
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
Run Code Online (Sandbox Code Playgroud)
其中产生:
P
A 5 38
6 13
B 5 73
6 10
Run Code Online (Sandbox Code Playgroud)
现在快速浏览一下索引
print df.index
MultiIndex(levels=[[u'A', u'B'], [5, 6]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
Run Code Online (Sandbox Code Playgroud)
如果我对这个数据框进行切片,我会注意到多索引永远不会压缩。即使是深拷贝。
在切片操作中减少索引内存占用的最佳方法是什么?
df_slice = df[df['P']>20]
print df_slice
print df_slice.index
P
A 5 38
B 5 73
Run Code Online (Sandbox Code Playgroud)
查看数据帧如何减少,但索引没有。
MultiIndex(levels=[[u'A', u'B'], [5, 6]],
labels=[[0, 1], [0, 0]])
Run Code Online (Sandbox Code Playgroud)
即使使用 .copy(deep=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]])
Run Code Online (Sandbox Code Playgroud)
我希望 MultiIndex 删除 6,如图所示:
MultiIndex(levels=[[u'A', u'B'], [5]]
,labels=[[0, 1], [0, 0]])
Run Code Online (Sandbox Code Playgroud)
当数据框很大时,问题就会出现。
我理解您的担忧,但我相信您必须了解 Pandas 低级应用程序中发生了什么。
首先,我们必须声明索引应该是不可变的。您可以在此处查看更多文档 -> 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
Run Code Online (Sandbox Code Playgroud)
现在,假设我们要选择P > 90的行。你会怎么做?df[df["P"] > 90], 对?但是看看 df["P"] > 90 实际返回的是什么。
A 5 True
6 True
B 5 True
6 False
Name: P, dtype: bool
Run Code Online (Sandbox Code Playgroud)
如您所见,它返回一个与原始索引匹配的布尔系列。为什么?因为 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
Run Code Online (Sandbox Code Playgroud)
这产生了我所相信的,是所需的输出:
MultiIndex(levels=[[u'B'], [5]], labels=[[0], [0]])
Run Code Online (Sandbox Code Playgroud)
但是如果数据太大而不必担心索引的大小,我想知道在时间方面可能会花费多少。
| 归档时间: |
|
| 查看次数: |
2210 次 |
| 最近记录: |