Python Pandas 中多层索引(MultiIndex)可以在 DataFrame 或 Series 中创建多个层次的标签。多层索引可以帮助我们更有效地组织和管理数据,并进行更复杂的分析。多层索引(也称为分层索引)提供了在一个轴上拥有多个(两个以上)索引级别的能力。这使得数据表示更加灵活,可以处理更复杂的数据形式。多层索引对于数据的分组、重塑和高级聚合操作特别有用。

1、创建多层索引

可以使用pd.MultiIndexset_index()创建多层索引。

1)set_index()

使用set_index()可以使用多个参数来实现不同的多层索引(层次化索引)操作。

参考说明:

参数

描述

keys

用于创建索引的列名或列名列表,可以是单个列名或多个列名。

drop

布尔值,指定设置索引后是否删除原来的列,默认为 True(删除)。

append

布尔值,指定是否将新索引添加到现有索引,默认为 False。

verify_integrity

布尔值,用于检查新生成的索引是否有重复项,默认为 False。

level

用于从多层索引中删除级别的整数或级别名。

inplace

布尔值,指定是否在原地修改 DataFrame,默认为 False。

col_level

用于确定将列插入到多层索引的哪个级别,

适用于具有多层列的 DataFrame。

col_fill

创建多层索引时,用于填充其他级别的名称。

使用示例:

import pandas as pd


# 创建示例 DataFrame
df = pd.DataFrame({
    'A': ['foo', 'bar', 'baz', 'foo'],
    'B': ['one', 'one', 'two', 'two'],
    'C': ['x', 'y', 'x', 'y'],
    'D': [1, 3, 2, 4]
})

# 使用 set_index() 示例
# 设置单列为索引
single_index_df = df.set_index('A')

# 设置多列为多层索引
multi_index_df = df.set_index(['A', 'B'])

# 设置索引并保留原始列
index_with_original_df = df.set_index('A', drop=False)

# 添加到现有索引
append_index_df = df.set_index('C', append=True)

# 打印创建的 DataFrame 示例
print(single_index_df, multi_index_df, index_with_original_df, append_index_df)

2)pd.MultiIndex

pd.MultiIndex 用于创建多层(层次化)索引,它提供了几个参数来定制索引。使用 pd.MultiIndex 可以创建强大的多层索引结构,这在处理和分析具有复杂层次结构的数据时非常有用。

参数说明:

参数

描述

levels

列表的列表,每个内部列表包含索引的唯一值,

代表不同的索引层级。

codes

列表的列表,每个内部列表包含整数代码,

这些代码指向 levels 中相应级别的值。

labels

(已弃用)与 codes 类似,

但已在新版本的 Pandas 中弃用。

names

索引层级的名称列表,

有助于标识每个层级。

sortorder

一个整数,用于确定多索引级别的排序顺序。

copy

布尔值,用于指定是否复制 levels 和 codes,

默认为 False

verify_integrity

布尔值,用于检查新的 MultiIndex 是否有效,默认为 True

dtype

设置索引数据类型。

使用示例:

import pandas as pd

# 通过列表的列表创建 MultiIndex
multi_index_from_arrays = pd.MultiIndex.from_arrays([['A', 'A', 'B', 'B'], [1, 2, 1, 2]], names=['letter', 'number'])

# 通过元组的列表创建 MultiIndex
multi_index_from_tuples = pd.MultiIndex.from_tuples([('A', 1), ('A', 2), ('B', 1), ('B', 2)], names=['letter', 'number'])

# 通过产品创建 MultiIndex
multi_index_from_product = pd.MultiIndex.from_product([['A', 'B'], [1, 2]], names=['letter', 'number'])

# 直接使用 pd.MultiIndex 构造函数创建 MultiIndex
multi_index_direct = pd.MultiIndex(levels=[['A', 'B'], [1, 2]], codes=[[0, 0, 1, 1], [0, 1, 0, 1]], names=['letter', 'number'])

# 创建一个示例 DataFrame 使用 MultiIndex
df = pd.DataFrame({'data': range(4)}, index=multi_index_from_arrays)

# 打印创建的 MultiIndex 和 DataFrame 示例
print(multi_index_from_arrays, multi_index_from_tuples, multi_index_from_product, multi_index_direct, df)

2、选择数据

当使用多层索引(MultiIndex)时,lociloc 方法都可以用于选择和切片数据,但它们的使用方式略有不同。loc 主要用于基于标签的索引。当处理多层索引时,可以传递一个元组来指定每层的索引值。iloc 用于基于整数的位置索引,它忽略索引的实际标签。

参考文档Python pandas dataframe iloc 和 loc 的用法及区别

import pandas as pd

index = pd.MultiIndex.from_tuples(
    [('A', 1), ('A', 2), ('B', 1), ('B', 2)],
    names=['letter', 'number']
)
df = pd.DataFrame({'data': [10, 20, 30, 40]}, index=index)

# 使用 loc 方法进行选择和切片
single_element_loc = df.loc[('A', 1)]
slice_loc = df.loc['A']
specific_column_loc = df.loc[('A', 1), 'data']
multiple_index_loc = df.loc[[('A', 1), ('B', 2)]]

# 使用 iloc 方法进行选择和切片
single_element_iloc = df.iloc[0]
slice_iloc = df.iloc[0:2]
specific_column_iloc = df.iloc[0, 0]
# 布尔索引和 iloc 一起使用不太常见,通常使用 loc


print(single_element_loc, slice_loc, specific_column_loc, multiple_index_loc, single_element_iloc, slice_iloc, specific_column_iloc)

3、交叉切片

Pandas 中,交叉切片(cross-section)是一种高级的数据操作技术,特别适用于多层索引的场景。它允许你选择特定层级的特定键值,而不考虑其他层级。pd.IndexSlice用于对多层索引进行更复杂的切片。pd.IndexSlice 的强大之处在于它提供了一种更为直观和灵活的方式来切片多层索引的 Pandas 对象。通过使用它,可以更精确地选择数据的子集,特别是在处理复杂的数据结构时。pd.IndexSlice经常与.loc.iloc索引器结合使用。

import pandas as pd
import numpy as np

# 创建示例多层索引DataFrame
arrays = [np.array(['bar', 'bar', 'baz', 'baz']),
          np.array(['one', 'two', 'one', 'two'])]
index = pd.MultiIndex.from_arrays(arrays, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(4, 2), index=index, columns=['A', 'B'])

# 使用IndexSlice选择数据
idx = pd.IndexSlice
slice_data1 = df.loc[idx['bar', 'one'], :]
slice_data2 = df.loc[idx[['bar', 'baz'], ['one']], :]
slice_data3 = df.loc[idx['bar':'baz', 'one'], :]
slice_data4 = df.loc[idx[:, 'one':'two'], :]

# 打印原始DataFrame和使用IndexSlice的结果
print("原始DataFrame:\n", df)
print("\nIndexSlice选择 - 'bar', 'one':\n", slice_data1)
print("\nIndexSlice选择 - ['bar', 'baz'], ['one']:\n", slice_data2)
print("\nIndexSlice选择 - 'bar':'baz', 'one':\n", slice_data3)
print("\nIndexSlice选择 - :, 'one':'two':\n", slice_data4)

4、重塑数据

Pandas 中,处理具有多层索引的 DataFrame 时,你可能需要重塑数据。这可以通过多种方式实现,重塑数据常使用用stackunstackpivotmelt 方法。

参数文档:

Python pandas.DataFrame.stack函数方法的使用

Python pandas.DataFrame.unstack函数方法的使用

Python pandas.DataFrame.pivot函数方法的使用

Python pandas.DataFrame.pivot_table函数方法的使用

Python pandas.DataFrame.melt函数方法的使用

使用示例:

import numpy as np
import pandas as pd

# 示例 DataFrame
df = pd.DataFrame({
    'A': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'],
    'B': ['one', 'one', 'two', 'two', 'one', 'one'],
    'C': ['small', 'large', 'large', 'small', 'small', 'large'],
    'D': [1, 2, 2, 3, 3, 4],
    'E': [2, 4, 5, 5, 6, 6]
})

# 使用 stack 方法
stacked = df.set_index(['A', 'B', 'C']).stack()

# 使用 unstack 方法
unstacked = stacked.unstack()

# 使用 pivot 方法
df1 = pd.DataFrame({
    'date': ['2021-01-01', '2021-01-01', '2021-01-02', '2021-01-02'],
    'city': ['New York', 'Los Angeles', 'New York', 'Los Angeles'],
    'temperature': [32, 75, 30, 77],
    'humidity': [80, 40, 82, 43]
})

# 使用 pivot 方法重塑数据
pivot_df = df1.pivot(index='date', columns='city', values='temperature')
print(pivot_df)

# 使用 pivot_table 方法
pivot_table = df.pivot_table(values='D', index=['A', 'B'], columns=['C'], aggfunc=np.sum)

# 使用 melt 方法
melted = df.melt(id_vars=['A', 'B'], value_vars=['D', 'E'])

# 打印结果
print(stacked, unstacked, pivot_table, melted)

5、聚合操作

Pandas 中,当使用多层索引(MultiIndex)的 DataFrameSeries 进行聚合操作时,可以对数据的不同层级进行分组和汇总。Pandas 提供了多种方法来执行这些聚合操作,常使用groupbyaggtransform方法进行聚合操作。

参数文档:

Python pandas.DataFrame.groupby函数方法的使用

Python pandas.DataFrame.agg函数方法的使用

Python pandas.DataFrame.transform函数方法的使用

使用示例:

import pandas as pd
import numpy as np

# 示例 DataFrame
df = pd.DataFrame({
    'A': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'],
    'B': ['one', 'one', 'two', 'two', 'one', 'one'],
    'C': [1, 2, 3, 4, 5, 6],
    'D': [7, 8, 9, 10, 11, 12]
}).set_index(['A', 'B'])

# 使用 groupby 进行聚合
grouped_sum = df.groupby(level='A').sum()
grouped_agg = df.groupby(level='A').agg({'C': 'sum', 'D': 'mean'})

# 使用 agg 方法进行多函数聚合
agg_functions = df.agg(['sum', 'mean'])

# 使用 transform 方法进行数据转换
transformed = df.groupby(level='A').transform('mean')

# 打印结果
print(grouped_sum, grouped_agg, agg_functions, transformed)

推荐文档