在Pandas面板中,轴顺序似乎真的让我感到困惑。为什么这样呢?
这就是我的意思:
In [120]: import pandas as pd
In [121]: import numpy as np
In [122]: pnl = pd.Panel(np.random.randn(33, 55, 77))
In [123]: pnl.shape
Out[123]: (33, 55, 77)
In [124]: pnl[0].shape
Out[124]: (55, 77)
In [125]: pnl[0][0].shape
Out[125]: (55,)
因此,它分别以轴0、1、2的形状(33、55、77)开始。大。如果我用
pnl[0]
取下一个索引,它取下第一个轴(长度33)并留下形状(55、77)。仍然很棒。但是,当我用pnl[0][0]
取下另一个索引时,它并没有取下前两个轴(长度33、55)并使形状(77)保持我的合理预期。不。它决定这次要离开最后一个轴,而不是第一个轴,并留下形状(55,)。 ??!?!为什么这么乱呢?有人可以向我解释其背后的设计逻辑。PS。我真的很想使用Panel,但是由于这个轴问题,我现在不使用它。这有时会使代码不必要地造成混淆。
更新:
F先生在下面给出了一个答案,该答案基本上建议始终使用
pnl.ix[...]
而不是使用pnl[...]
。因此,我尝试了一下。但是,我仍然遇到真正奇怪/令人困惑的行为。这是一个示例,使用与上面定义的相同的
pnl
对象:In [220]: pnl.shape
Out[220]: (33, 55, 77)
In [221]: pnl.ix[:, 0, 0].shape
Out[221]: (33,)
In [222]: pnl.ix[0, :, 0].shape
Out[222]: (55,)
In [223]: pnl.ix[0, 0, :].shape
Out[223]: (77,)
In [224]: pnl.ix[:, :, 0].shape
Out[224]: (55, 33)
In [225]: pnl.ix[:, 0, :].shape
Out[225]: (77, 33)
In [226]: pnl.ix[0, :, :].shape
Out[226]: (55, 77)
当我取下2个轴并仅保留1个轴时,一切看起来都很好(上面的命令221-223)。但是,当我从1根轴离开而剩下2根轴时(上面的命令224-226),得到的形状再次变得毫无意义。很难理解和习惯所产生的形状如何神奇地交换轴的顺序,但是只是有时! (具体来说,命令226的结果形状(55,77)与我的期望相符。但是,在命令224中,我希望结果形状(33,55)不(55,33);在命令225中,我期望结果形状(33,77)不是(77,33)。)
最佳答案
问题在于,项获取器语法(使用方括号[]
获取尺寸)不是您想要的那种东西。您需要确保沿指定的维度对数据进行子索引。
为此,您可以使用ix
:
pnl.ix[0, 0].shape
(77,)
通过查看您尝试过的每种方法的
type
,您可以对此有所了解:In [71]: type(pnl.ix[0, 0])
Out[71]: pandas.core.series.Series
In [72]: type(pnl.ix[0])
Out[72]: pandas.core.frame.DataFrame
In [73]: type(pnl[0])
Out[73]: pandas.core.frame.DataFrame
特别是最后两个对象正在看同一个sub-DataFrame,但请考虑以下两者之间的区别:
(pnl[0])[0]
# Or, (pnl.ix[0])[0]
和
pnl.ix[0, 0]
# Or, (pnl.ix[0]).ix[0]
在第一种情况下,您说的是“嘿,继续进行'
pnl[0]
'操作并返回任何内容,然后继续进行操作,然后再次获取第0个元素”。由于
pnl[0]
是一个DataFrame,因此对于任何旧的DataFrame,额外的[0]
项获取操作将与df[0]
相同,如果存在,它将尝试提取该列。列维将是结果DataFrame的第一维,这就是为什么它是长度55而不是行长77的原因。要点是在Python中说
foo[x]
只是意味着“以__getitem__
为参数调用foo
的特殊x
方法”,仅此而已。如果与DataFrame一样,它具有一个特殊的约定(例如,引用列),该约定与您在数学计数法中可能期望的约定不同(在这种情况下,它将沿第一轴引用一个项,而不管形状或结构如何) ,这只是一个实现细节。例如,对于纯NumPy数组,重复的项获取可以实现您所期望的:
In [90]: pnl.values[0][0].shape
Out[90]: (77,)
但这并不能使它成为“正确”的方法或任何事情。这只是碰巧与数学线性代数的某些约定相对应的一种方式。由于DataFrame试图表示关系数据模型而不是纯粹的多维数组,因此没有理由期望Pandas在这种行为中必须模仿NumPy。
新增超过2个维度
与原始3D面板中的布局相比,这些切片操作具有2个以上的维度,表示数据的隐式转置。因此,Pandas必须做一些事情来解决子选择数据的布局,而且看起来这样做时,Pandas并没有以确保从左到右顺序排列的方式实现切片方法。轴被保留。
因此,当数据按块布局时,似乎可以独立于其从父面板数据存储的内容来确定新的主轴(索引)。
例如,我创建了一个具有相同形状的随机数据集,然后看到:
In [22]: pnl.ix[:, 0, :]._data
Out[22]:
BlockManager
Items: Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
dtype='int64')
Axis 1: Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76],
dtype='int64')
FloatBlock: slice(0, 33, 1), 33 x 77, dtype: float64
特别要注意最后一行,它说它确实知道它是33 x 77的块。但是,当我们查看该块的
DataFrame
表示形式时:In [23]: pnl.ix[:, 0, :].shape
Out[23]: (77, 33)
因此,您是对的,Pandas重新确定轴排序的过程是任意的,没有记录的过程是有问题的。该示例应正确地记录为错误,这是因为未保留轴顺序,或者因为未记录用于确定将产生哪个顺序的任何条件。熊猫团队应该提供其中一个。
关于python - Pandas 面板为什么会弄乱轴顺序?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32028995/