将具有 n 级层次索引的 Pandas DataFrame 转换为 n-D Numpy 数组
Transform Pandas DataFrame with n-level hierarchical index into n-D Numpy array
问题
有没有什么好的方法可以将具有n级索引的DataFrame转换为n-D Numpy数组(a.k.a n-张量)?
例子
假设我设置了一个像
这样的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
输出
value
0 0 0
1 1
2 3
1 1 5
2 6
该索引是一个二级分层索引。我可以使用
从数据中提取二维 Numpy 数组
print frame.unstack().values
输出
[[ 0. 1. 2.]
[ nan 4. 5.]]
这如何推广到 n 级索引?
玩unstack()
,好像只能用来按摩DataFrame的二维形状,不能加轴
我不能使用例如frame.values.reshape(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
原解。给定与上述类似的设置,但在 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)
我们有
value
0 0 0 0
1 1
1 0 2
1 3
1 0 0 4
1 0 6
1 7
现在,我们继续使用 reshape()
路线,但进行一些预处理以确保沿每个维度的长度一致。
首先,使用所有维度的完整笛卡尔积重新索引数据框。 NaN
值将根据需要插入。此操作可能既慢又消耗大量内存,具体取决于维数和数据框的大小。
levels = map(tuple, frame.index.levels)
index = list(product(*levels))
frame = frame.reindex(index)
print(frame)
输出
value
0 0 0 0
1 1
1 0 2
1 3
1 0 0 4
1 NaN
1 0 6
1 7
现在,reshape()
将按预期工作。
shape = map(len, frame.index.levels)
print(frame.values.reshape(shape))
输出
[[[ 0. 1.]
[ 2. 3.]]
[[ 4. nan]
[ 6. 7.]]]
(相当难看)one-liner 是
frame.reindex(list(product(*map(tuple, frame.index.levels)))).values\
.reshape(map(len, frame.index.levels))
这可以使用 Python xarray 包很好地完成,可以在这里找到:http://xarray.pydata.org/en/stable/。它与 Pandas 有很好的集成,一旦你掌握了它就会非常直观。
如果您有一个多索引系列,您可以调用内置方法 multiindex_series.to_xarray() (https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_xarray.html)。这将生成一个 DataArray 对象,它本质上是一个名称索引的 numpy 数组,使用索引值和名称作为坐标。在此之后,您可以在 DataArray 对象上调用 .values 以获取底层的 numpy 数组。
如果你需要你的张量符合特定顺序的一组键,你也可以调用 .reindex(index_name = index_values_in_order) (http://xarray.pydata.org/en/stable/generated/xarray.DataArray.reindex.html)数据数组。这非常有用,可以更轻松地处理新生成的张量!
问题
有没有什么好的方法可以将具有n级索引的DataFrame转换为n-D Numpy数组(a.k.a n-张量)?
例子
假设我设置了一个像
这样的DataFramefrom 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
该索引是一个二级分层索引。我可以使用
从数据中提取二维 Numpy 数组print frame.unstack().values
输出
[[ 0. 1. 2.]
[ nan 4. 5.]]
这如何推广到 n 级索引?
玩unstack()
,好像只能用来按摩DataFrame的二维形状,不能加轴
我不能使用例如frame.values.reshape(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
原解。给定与上述类似的设置,但在 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)
我们有
value
0 0 0 0
1 1
1 0 2
1 3
1 0 0 4
1 0 6
1 7
现在,我们继续使用 reshape()
路线,但进行一些预处理以确保沿每个维度的长度一致。
首先,使用所有维度的完整笛卡尔积重新索引数据框。 NaN
值将根据需要插入。此操作可能既慢又消耗大量内存,具体取决于维数和数据框的大小。
levels = map(tuple, frame.index.levels)
index = list(product(*levels))
frame = frame.reindex(index)
print(frame)
输出
value
0 0 0 0
1 1
1 0 2
1 3
1 0 0 4
1 NaN
1 0 6
1 7
现在,reshape()
将按预期工作。
shape = map(len, frame.index.levels)
print(frame.values.reshape(shape))
输出
[[[ 0. 1.]
[ 2. 3.]]
[[ 4. nan]
[ 6. 7.]]]
(相当难看)one-liner 是
frame.reindex(list(product(*map(tuple, frame.index.levels)))).values\
.reshape(map(len, frame.index.levels))
这可以使用 Python xarray 包很好地完成,可以在这里找到:http://xarray.pydata.org/en/stable/。它与 Pandas 有很好的集成,一旦你掌握了它就会非常直观。
如果您有一个多索引系列,您可以调用内置方法 multiindex_series.to_xarray() (https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_xarray.html)。这将生成一个 DataArray 对象,它本质上是一个名称索引的 numpy 数组,使用索引值和名称作为坐标。在此之后,您可以在 DataArray 对象上调用 .values 以获取底层的 numpy 数组。
如果你需要你的张量符合特定顺序的一组键,你也可以调用 .reindex(index_name = index_values_in_order) (http://xarray.pydata.org/en/stable/generated/xarray.DataArray.reindex.html)数据数组。这非常有用,可以更轻松地处理新生成的张量!