将具有n级分层索引的Pandas DataFrame转换为nD Numpy数组

Igo*_*ush 6 python multidimensional-array multi-index pandas

有没有一种方法可以将带有n级索引的DataFrame 转换为n- D Numpy数组(又名n -tensor)?


假设我设置了一个像DataFrame

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
Run Code Online (Sandbox Code Playgroud)

哪个输出

     value
0 0      0
  1      1
  2      3
1 1      5
  2      6
Run Code Online (Sandbox Code Playgroud)

该索引是一个2级分层索引.我可以使用数据从数据中提取二维Numpy数组

print frame.unstack().values
Run Code Online (Sandbox Code Playgroud)

哪个输出

[[  0.   1.   2.]
 [ nan   4.   5.]]
Run Code Online (Sandbox Code Playgroud)

这如何推广到n级索引?

unstack(),似乎它只能用于按摩DataFrame的二维形状,但不能用于添加轴.

我不能使用eg frame.values.reshape(x, y, z),因为这将要求帧包含确切的x * y * z行,这是无法保证的.这是我试图drop()在上面的例子中通过一行来证明的.

任何建议都非常感谢.

Igo*_*ush 6

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

# 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.labels] = frame.values.flat
Run Code Online (Sandbox Code Playgroud)

原来的解决方案.给定类似于上面的设置,但是在3-D中,

from pandas import DataFrame, MultiIndex
from itertools import product

index = range(2), range(2), range(2)
value = range(2 * 2 * 2)
frame = DataFrame(value, columns=['value'],
                  index=MultiIndex.from_product(index)).drop((1, 0, 1))
print(frame)
Run Code Online (Sandbox Code Playgroud)

我们有

       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
  1 0      6
    1      7
Run Code Online (Sandbox Code Playgroud)

现在,我们继续使用reshape()路线,但进行一些预处理以确保沿每个维度的长度是一致的.

首先,使用所有维度的完整笛卡尔积重新索引数据框.NaN将根据需要插入值.此操作可能既慢又占用大量内存,具体取决于维度的数量和数据框的大小.

levels = map(tuple, frame.index.levels)
index = list(product(*levels))
frame = frame.reindex(index)
print(frame)
Run Code Online (Sandbox Code Playgroud)

哪个输出

       value
0 0 0      0
    1      1
  1 0      2
    1      3
1 0 0      4
    1    NaN
  1 0      6
    1      7
Run Code Online (Sandbox Code Playgroud)

现在,reshape()将按预期工作.

shape = map(len, frame.index.levels)
print(frame.values.reshape(shape))
Run Code Online (Sandbox Code Playgroud)

哪个输出

[[[  0.   1.]
  [  2.   3.]]

 [[  4.  nan]
  [  6.   7.]]]
Run Code Online (Sandbox Code Playgroud)

(相当难看的)单线是

frame.reindex(list(product(*map(tuple, frame.index.levels)))).values\
     .reshape(map(len, frame.index.levels))
Run Code Online (Sandbox Code Playgroud)

  • 对我们来说,诺比; 不要忘记在python3中你需要先将'map'的结果转换成一个列表,然后再进行任何操作.即.`shape = list(map(len,frame.index.levels))` (4认同)