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 pdimport numpy as np
# Create sample DataFramesdf1 = 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 rowsdata_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 columnsmulti_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 CItem1 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.808080Item2 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 C0 0.123456 -0.567890 1.234567 0.909090 -1.111111 0.2222221 -0.987654 0.112233 -0.445566 -0.333333 1.444444 -0.5555552 1.505050 -0.202020 0.303030 0.666667 -0.777777 1.8888883 -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 pdimport numpy as np
# Simulate 3D data: 2 items, 4 time points, 3 variablesnp_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 DataFramemulti_df = pd.DataFrame(reshaped_data, index=row_index, columns=['VarA', 'VarB', 'VarC'])
print(multi_df)print("\nDataFrame Index:")print(multi_df.index)输出(结构和值将因随机数据而异):
VarA VarB VarCItem TimeItem1 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.808080Item2 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'])创建一个空的 MultiIndex DataFrame
Section titled “创建一个空的 MultiIndex DataFrame”您可以创建一个空的 DataFrame,稍后再分配 MultiIndex,或者创建一个具有预定义 MultiIndex 但没有数据的 DataFrame。
import pandas as pd
# Empty DataFrameempty_df = pd.DataFrame()print("Empty DataFrame:")print(empty_df)
# Define a MultiIndexindex = pd.MultiIndex.from_product([['A', 'B'], [1, 2]], names=['Level1', 'Level2'])
# DataFrame with MultiIndex but no dataempty_multi_df = pd.DataFrame(index=index, columns=['DataCol1', 'DataCol2'])print("\nEmpty DataFrame with MultiIndex:")print(empty_multi_df)输出:
Empty DataFrame:Empty DataFrameColumns: []Index: []
Empty DataFrame with MultiIndex: DataCol1 DataCol2Level1 Level2A 1 NaN NaN 2 NaN NaNB 1 NaN NaN 2 NaN NaN从 MultiIndex DataFrame 中选取数据
Section titled “从 MultiIndex DataFrame 中选取数据”选取操作使用标准的 Pandas 索引方法,如 .loc、.iloc 和 [],但需要使用元组 (tuples) 或切片 (slices) 来访问不同的索引级别。
我们使用前面 NumPy 示例中的 multi_df(MultiIndex 在行上):
# Recreate the DataFrame for selection examplesnp_data = np.arange(24).reshape(2, 4, 3) # Use predictable datarow_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 VarCTime2023-01-01 0 1 22023-01-02 3 4 52023-01-03 6 7 82023-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 timeitem1_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 xsall_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 3VarB 4VarC 5Name: (Item1, 2023-01-02 00:00:00), dtype: int64
Data for 2023-01-03 across all Items: VarA VarB VarCItemItem1 6 7 8Item2 18 19 20选取列(类似于 Panel 的 ‘minor_axis’)
Section titled “选取列(类似于 Panel 的 ‘minor_axis’)”这与标准的 DataFrame 列选取方式相同。
# Select a single columncol_b = multi_df['VarB']print("\nColumn 'VarB':")print(col_b)
# Select multiple columnscols_ac = multi_df[['VarA', 'VarC']]print("\nColumns 'VarA' and 'VarC':")print(ncols_ac)输出:
Column 'VarB':Item TimeItem1 2023-01-01 1 2023-01-02 4 2023-01-03 7 2023-01-04 10Item2 2023-01-01 13 2023-01-02 16 2023-01-03 19 2023-01-04 22Name: VarB, dtype: int64
Columns 'VarA' and 'VarC': VarA VarCItem TimeItem1 2023-01-01 0 2 2023-01-02 3 5 2023-01-03 6 8 2023-01-04 9 11Item2 2023-01-01 12 14 2023-01-02 15 17 2023-01-03 18 20 2023-01-04 21 23使用 MultiIndex DataFrame 是掌握 Pandas 高级用法的基本技能。请参考官方 Pandas 文档以获取更多详细信息:
- MultiIndex / 高级索引 (Advanced Indexing):https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html
- pd.concat:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html
尽管 Panel 已被弃用,但理解如何使用 MultiIndex 表示类似的数据结构对于使用 Pandas 进行现代数据分析至关重要。