在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/

10-12 21:27