Python 将具有n级层次索引的数据帧转换为n-D Numpy数组 问题:

Python 将具有n级层次索引的数据帧转换为n-D Numpy数组 问题:,python,pandas,multidimensional-array,multi-index,Python,Pandas,Multidimensional Array,Multi Index,有没有一种好方法可以将具有n级索引的数据帧转换为n-D Numpy数组(也称为n张量) 例子 假设我设置了一个数据帧,如 from pandas import DataFrame, MultiIndex index = range(2), range(3) value = range(2 * 3) frame = DataFrame(value, columns=['value'], index=MultiIndex.from_product(index)

有没有一种好方法可以将具有n级索引的数据帧转换为n-D Numpy数组(也称为n张量)


例子 假设我设置了一个数据帧,如

from pandas import DataFrame, MultiIndex

index = range(2), range(3)
value = range(2 * 3)
frame = DataFrame(value, columns=['value'],
                  index=MultiIndex.from_product(index)).drop((1, 0))
print frame
哪个输出

     value
0 0      0
  1      1
  2      3
1 1      5
  2      6
[[  0.   1.   2.]
 [ nan   4.   5.]]
       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
    1    NaN
  1 0      6
    1      7
[[[  0.   1.]
  [  2.   3.]]

 [[  4.  nan]
  [  6.   7.]]]
该索引是一个两级层次索引。我可以使用

print frame.unstack().values
哪个输出

     value
0 0      0
  1      1
  2      3
1 1      5
  2      6
[[  0.   1.   2.]
 [ nan   4.   5.]]
       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
    1    NaN
  1 0      6
    1      7
[[[  0.   1.]
  [  2.   3.]]

 [[  4.  nan]
  [  6.   7.]]]
这是如何推广到n级索引的?

使用
unstack()
,它似乎只能用于按摩数据帧的二维形状,而不能添加轴

我不能使用例如
frame.values.reformate(x,y,z)
,因为这将要求该框架正好包含
x*y*z
行,这是无法保证的。这就是我在上面的示例中通过
drop()
ing一行来演示的内容


非常感谢您的任何建议。

编辑。这种方法比我下面给出的方法更优雅(速度快两个数量级)

# create an empty array of NaN of the right dimensions
shape = map(len, frame.index.levels)
arr = np.full(shape, np.nan)

# fill it using Numpy's advanced indexing
arr[frame.index.codes] = frame.values.flat
# ...or in Pandas < 0.24.0, use
# arr[frame.index.labels] = frame.values.flat
我们有

       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
  1 0      6
    1      7
现在,我们继续使用
reformate()
路线,但需要进行一些预处理,以确保沿每个维度的长度保持一致

首先,使用所有维度的完全笛卡尔积重新索引数据帧<代码>NaN值将根据需要插入。此操作既慢又占用大量内存,具体取决于维度的数量和数据帧的大小

levels = map(tuple, frame.index.levels)
index = list(product(*levels))
frame = frame.reindex(index)
print(frame)
哪个输出

     value
0 0      0
  1      1
  2      3
1 1      5
  2      6
[[  0.   1.   2.]
 [ nan   4.   5.]]
       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
    1    NaN
  1 0      6
    1      7
[[[  0.   1.]
  [  2.   3.]]

 [[  4.  nan]
  [  6.   7.]]]
现在,
reformate()
将按预期工作

shape = map(len, frame.index.levels)
print(frame.values.reshape(shape))
哪个输出

     value
0 0      0
  1      1
  2      3
1 1      5
  2      6
[[  0.   1.   2.]
 [ nan   4.   5.]]
       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
    1    NaN
  1 0      6
    1      7
[[[  0.   1.]
  [  2.   3.]]

 [[  4.  nan]
  [  6.   7.]]]
(相当难看的)一行是

frame.reindex(list(product(*map(tuple, frame.index.levels)))).values\
     .reshape(map(len, frame.index.levels))

“它是如何概括的”的答案是它不是。数据帧基本上是一个二维对象。正如您的示例所示,它不会在索引“维度”之间强制执行相同的大小,因此如果您尝试将其扩展到更多维度,则可能存在间隙。我认为,如果你想得到一个n-D数组,你可能必须通过迭代索引级别并为每个级别创建一个单独的结果数组“切片”来自己创建它。熊猫不是针对那种结构。谢谢@Bren。我设法解决了缺少行的问题,并使用了
重塑()
(见下文)。这似乎在我的数据集上起作用,但如果出现阻塞的情况,我不会感到惊讶。效果很好!有一个小错误:
frame.reindex(levels)
应该是
frame.reindex(index)
;别忘了,在python3中,在任何一个都起作用之前,您需要将“map”的结果转换成一个列表。例如,
shape=list(map(len,frame.index.levels))
获取形状更直接:
frame.index.levshape
。这和给定的解决方案似乎都不适用于非唯一索引。执行
df.index.labels
I get
AttributeError:“多索引”对象没有属性“labels”
。这是怎么回事?@CrabMan反应很晚,但是
MultiIndex.labels
已经被弃用,取而代之的是
MultiIndex.code
——使用后者应该可以修复错误。()