Skip to content

Python Pandas - Panel

使用 Pandas 处理 3D+ 数据(Panel 的替代方案)

Section titled “使用 Pandas 处理 3D+ 数据(Panel 的替代方案)”

历史上,Pandas 提供 Panel 对象作为处理三维数据的主要容器。然而,Panel 自 Pandas 0.25.0 版本以来已被弃用,并随后被移除。

在 Pandas 中处理三维或更高维度数据的现代推荐方法是使用 DataFrame,并在其行或列上使用 MultiIndex(多级索引)。这种方法更灵活,与 Pandas 的其他功能更一致,并且通常更节省内存。

尽管“Panel data”(面板数据,在计量经济学中常用于多实体时间序列)这个术语仍然存在,但 Pandas 中用于表示此类数据的数据结构现在通常是带有 MultiIndex 的 DataFrame。下面我们将探讨如何表示和处理这类数据:

理解用于 3D+ 数据的 MultiIndex DataFrame

Section titled “理解用于 3D+ 数据的 MultiIndex DataFrame”

MultiIndex(或称分层索引 Hierarchical Index)允许您在一个轴上拥有多个索引级别。要表示三维数据,您可以概念上将其视为:

  • Items(类似于原始 Panel 的 axis 0): 由行或列 MultiIndex 的外层级别表示。
  • Major Axis(类似于原始 Panel 的 axis 1): 由行 MultiIndex 的内层级别表示(通常代表时间或观测值)。
  • Minor Axis(类似于原始 Panel 的 axis 2): 由 DataFrame 的列表示(对于 4D+ 数据,列本身也可以是 MultiIndex)。

关键优势在于灵活性:您可以根据分析需求,将这些维度分布在行索引和列索引上。

创建用于 3D 数据的 MultiIndex DataFrame

Section titled “创建用于 3D 数据的 MultiIndex DataFrame”

您可以通过几种方式创建 MultiIndex DataFrame:

使用 pd.concat 从多个 DataFrame 创建

Section titled “使用 pd.concat 从多个 DataFrame 创建”

这类似于从 DataFrame 字典创建 Panel。使用 pd.concat 并指定 keys 参数会自动创建一个 MultiIndex。

import pandas as pd
import numpy as np
# Create sample DataFrames
df1 = pd.DataFrame(np.random.randn(4, 3), columns=['A', 'B', 'C'])
df2 = pd.DataFrame(np.random.randn(4, 3), columns=['A', 'B', 'C'])
# Combine them, creating a MultiIndex on the rows
data_dict = {'Item1': df1, 'Item2': df2}
multi_df_rows = pd.concat(data_dict)
print("MultiIndex on Rows:")
print(multi_df_rows)
print("\nDataFrame Index:")
print(multi_df_rows.index)
# Alternative: Combine them creating a MultiIndex on the columns
multi_df_cols = pd.concat(data_dict, axis=1)
print("\nMultiIndex on Columns:")
print(multi_df_cols)
print("\nDataFrame Columns:")
print(multi_df_cols.columns)

输出(结构和值将因随机数据而异):

MultiIndex on Rows:
A B C
Item1 0 0.123456 -0.567890 1.234567
1 -0.987654 0.112233 -0.445566
2 1.505050 -0.202020 0.303030
3 -0.606060 1.707070 -0.808080
Item2 0 0.909090 -1.111111 0.222222
1 -0.333333 1.444444 -0.555555
2 0.666667 -0.777777 1.888888
3 -0.999999 0.000000 -1.010101
DataFrame Index:
MultiIndex([('Item1', 0),
('Item1', 1),
('Item1', 2),
('Item1', 3),
('Item2', 0),
('Item2', 1),
('Item2', 2),
('Item2', 3)],
)
MultiIndex on Columns:
Item1 Item2
A B C A B C
0 0.123456 -0.567890 1.234567 0.909090 -1.111111 0.222222
1 -0.987654 0.112233 -0.445566 -0.333333 1.444444 -0.555555
2 1.505050 -0.202020 0.303030 0.666667 -0.777777 1.888888
3 -0.606060 1.707070 -0.808080 -0.999999 0.000000 -1.010101
DataFrame Columns:
MultiIndex([('Item1', 'A'),
('Item1', 'B'),
('Item1', 'C'),
('Item2', 'A'),
('Item2', 'B'),
('Item2', 'C')],
)

注意 pd.concat 如何自动创建 MultiIndex 对象。keys=[‘Item1’, ‘Item2’] 参数指定了外层索引的名称。

使用显式 MultiIndex 从 NumPy 数组创建

Section titled “使用显式 MultiIndex 从 NumPy 数组创建”

您可以使用 MultiIndex.from_product 或 MultiIndex.from_tuples 等方法显式构造 MultiIndex,然后将其分配给从重塑 (reshaped) 的 NumPy 数组创建的 DataFrame。

import pandas as pd
import numpy as np
# Simulate 3D data: 2 items, 4 time points, 3 variables
np_data = np.random.randn(2, 4, 3)
# Create the MultiIndex for rows (Items x Time)
row_index = pd.MultiIndex.from_product(
[['Item1', 'Item2'], pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04'])],
names=['Item', 'Time']
)
# Reshape the 3D array to 2D ( (2*4) rows, 3 columns )
reshaped_data = np_data.reshape(-1, 3)
# Create the DataFrame
multi_df = pd.DataFrame(reshaped_data, index=row_index, columns=['VarA', 'VarB', 'VarC'])
print(multi_df)
print("\nDataFrame Index:")
print(multi_df.index)

输出(结构和值将因随机数据而异):

VarA VarB VarC
Item Time
Item1 2023-01-01 -0.123456 0.567890 -1.234567
2023-01-02 0.987654 -0.112233 0.445566
2023-01-03 -1.505050 0.202020 -0.303030
2023-01-04 0.606060 -1.707070 0.808080
Item2 2023-01-01 -0.909090 1.111111 -0.222222
2023-01-02 0.333333 -1.444444 0.555555
2023-01-03 -0.666667 0.777777 -1.888888
2023-01-04 0.999999 0.000000 1.010101
DataFrame Index:
MultiIndex([('Item1', '2023-01-01'),
('Item1', '2023-01-02'),
('Item1', '2023-01-03'),
('Item1', '2023-01-04'),
('Item2', '2023-01-01'),
('Item2', '2023-01-02'),
('Item2', '2023-01-03'),
('Item2', '2023-01-04')],
names=['Item', 'Time'])

您可以创建一个空的 DataFrame,稍后再分配 MultiIndex,或者创建一个具有预定义 MultiIndex 但没有数据的 DataFrame。

import pandas as pd
# Empty DataFrame
empty_df = pd.DataFrame()
print("Empty DataFrame:")
print(empty_df)
# Define a MultiIndex
index = pd.MultiIndex.from_product([['A', 'B'], [1, 2]], names=['Level1', 'Level2'])
# DataFrame with MultiIndex but no data
empty_multi_df = pd.DataFrame(index=index, columns=['DataCol1', 'DataCol2'])
print("\nEmpty DataFrame with MultiIndex:")
print(empty_multi_df)

输出:

Empty DataFrame:
Empty DataFrame
Columns: []
Index: []
Empty DataFrame with MultiIndex:
DataCol1 DataCol2
Level1 Level2
A 1 NaN NaN
2 NaN NaN
B 1 NaN NaN
2 NaN NaN

选取操作使用标准的 Pandas 索引方法,如 .loc、.iloc 和 [],但需要使用元组 (tuples) 或切片 (slices) 来访问不同的索引级别。

我们使用前面 NumPy 示例中的 multi_df(MultiIndex 在行上):

# Recreate the DataFrame for selection examples
np_data = np.arange(24).reshape(2, 4, 3) # Use predictable data
row_index = pd.MultiIndex.from_product(
[['Item1', 'Item2'], pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04'])],
names=['Item', 'Time']
)
reshaped_data = np_data.reshape(-1, 3)
multi_df = pd.DataFrame(reshaped_data, index=row_index, columns=['VarA', 'VarB', 'VarC'])
print("Original DataFrame:")
print(multi_df)

按外层索引级别选取(类似于 Panel 的 ‘Items’)

Section titled “按外层索引级别选取(类似于 Panel 的 ‘Items’)”

使用 .loc 加上外层索引的名称。

# Select all data for 'Item1'
item1_data = multi_df.loc['Item1']
print("\nData for Item1:")
print(item1_data)

输出:

Data for Item1:
VarA VarB VarC
Time
2023-01-01 0 1 2
2023-01-02 3 4 5
2023-01-03 6 7 8
2023-01-04 9 10 11

结果是一个 DataFrame,其中索引的 ‘Item’ 级别已被移除。

按特定行索引组合选取(类似于 Panel 的 ‘major_axis’)

Section titled “按特定行索引组合选取(类似于 Panel 的 ‘major_axis’)”

使用 .loc 加上代表完整索引的元组,或使用 .xs 进行横截面 (cross-section) 选取。

# Select data for Item1 at a specific time
item1_time2 = multi_df.loc[('Item1', '2023-01-02')]
print("\nData for Item1 at 2023-01-02:")
print(item1_time2)
# Select data for a specific time across all items using xs
all_items_time3 = multi_df.xs('2023-01-03', level='Time')
print("\nData for 2023-01-03 across all Items:")
print(all_items_time3)

输出:

Data for Item1 at 2023-01-02:
VarA 3
VarB 4
VarC 5
Name: (Item1, 2023-01-02 00:00:00), dtype: int64
Data for 2023-01-03 across all Items:
VarA VarB VarC
Item
Item1 6 7 8
Item2 18 19 20

选取列(类似于 Panel 的 ‘minor_axis’)

Section titled “选取列(类似于 Panel 的 ‘minor_axis’)”

这与标准的 DataFrame 列选取方式相同。

# Select a single column
col_b = multi_df['VarB']
print("\nColumn 'VarB':")
print(col_b)
# Select multiple columns
cols_ac = multi_df[['VarA', 'VarC']]
print("\nColumns 'VarA' and 'VarC':")
print(ncols_ac)

输出:

Column 'VarB':
Item Time
Item1 2023-01-01 1
2023-01-02 4
2023-01-03 7
2023-01-04 10
Item2 2023-01-01 13
2023-01-02 16
2023-01-03 19
2023-01-04 22
Name: VarB, dtype: int64
Columns 'VarA' and 'VarC':
VarA VarC
Item Time
Item1 2023-01-01 0 2
2023-01-02 3 5
2023-01-03 6 8
2023-01-04 9 11
Item2 2023-01-01 12 14
2023-01-02 15 17
2023-01-03 18 20
2023-01-04 21 23

使用 MultiIndex DataFrame 是掌握 Pandas 高级用法的基本技能。请参考官方 Pandas 文档以获取更多详细信息:

尽管 Panel 已被弃用,但理解如何使用 MultiIndex 表示类似的数据结构对于使用 Pandas 进行现代数据分析至关重要。