数据重塑stack 与unstack函数
stack()
- level:参数用于指定在多级列索引的情况下,要堆叠的列索引级别(level)。默认情况下,level 参数为 -1,表示堆叠最内层的列索引。
- dropna: 参数是一个布尔值,用于指定是否在堆叠过程中删除包含缺失值(NaN)的行。默认情况下,dropna 为 True,表示删除包含缺失值的行。
- name:参数用于指定生成的 Series 或 DataFrame 的列名称。可以指定一个字符串作为列名称,用于标识生成的 Series 或 DataFrame。
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
columns = pd.MultiIndex.from_product([['期中', '期末'], ['语文', '数学']])
index = [['一班', '一班', '一班', '二班', '二班','二班'],
['张三', '李四', '王五', '赵六', '田七', '孙八']]
data = np.random.randint(0, 150, size=(6, 4))
df = DataFrame(index=index, columns=columns, data=data)
df
期中 | 期末 | ||||
---|---|---|---|---|---|
语文 | 数学 | 语文 | 数学 | ||
一班 | 张三 | 3 | 67 | 56 | 101 |
李四 | 111 | 116 | 110 | 16 | |
王五 | 21 | 38 | 109 | 141 | |
二班 | 赵六 | 34 | 21 | 55 | 49 |
田七 | 116 | 73 | 26 | 148 | |
孙八 | 52 | 48 | 94 | 127 |
# 默认level = -1 将最内层的列索引旋转为最内层的行索引
df.stack()
期中 | 期末 | |||
---|---|---|---|---|
一班 | 张三 | 数学 | 67 | 101 |
语文 | 3 | 56 | ||
李四 | 数学 | 116 | 16 | |
语文 | 111 | 110 | ||
王五 | 数学 | 38 | 141 | |
语文 | 21 | 109 | ||
二班 | 赵六 | 数学 | 21 | 49 |
语文 | 34 | 55 | ||
田七 | 数学 | 73 | 148 | |
语文 | 116 | 26 | ||
孙八 | 数学 | 48 | 127 | |
语文 | 52 | 94 |
df.stack(level=0) # 将一级列索引旋转为最内层的行索引
数学 | 语文 | |||
---|---|---|---|---|
一班 | 张三 | 期中 | 67 | 3 |
期末 | 101 | 56 | ||
李四 | 期中 | 116 | 111 | |
期末 | 16 | 110 | ||
王五 | 期中 | 38 | 21 | |
期末 | 141 | 109 | ||
二班 | 赵六 | 期中 | 21 | 34 |
期末 | 49 | 55 | ||
田七 | 期中 | 73 | 116 | |
期末 | 148 | 26 | ||
孙八 | 期中 | 48 | 52 | |
期末 | 127 | 94 |
unstack()
用于将行索引转换为列索引
具有stack()相同的参数,此外还有一个特有的填充参数:
- fill_value:用于指定在数据重塑过程中填充缺失值的值。如果在转换过程中某些索引组合不存在,则会用 fill_value 指定的值填充这些缺失值。
# 默认level=-1,转换最内层的行索引
#给一个fill_value去填充NaN; 没有指定默认用NaN填充
df.unstack(fill_value=0)
期中 | ... | 期末 | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
语文 | 数学 | ... | 语文 | 数学 | |||||||||||||||||
孙八 | 张三 | 李四 | 王五 | 田七 | 赵六 | 孙八 | 张三 | 李四 | 王五 | ... | 李四 | 王五 | 田七 | 赵六 | 孙八 | 张三 | 李四 | 王五 | 田七 | 赵六 | |
一班 | 0 | 3 | 111 | 21 | 0 | 0 | 0 | 67 | 116 | 38 | ... | 110 | 109 | 0 | 0 | 0 | 101 | 16 | 141 | 0 | 0 |
二班 | 52 | 0 | 0 | 0 | 116 | 34 | 48 | 0 | 0 | 0 | ... | 0 | 0 | 26 | 55 | 127 | 0 | 0 | 0 | 148 | 49 |
2 rows × 24 columns
# df.unstack(fill_value=0) 将最内层行索引转换为最内层的列索引
# .stack(level=(0, 1)) 将 1 2层的索引转换为列索引
# .unstack(level=0) # 将最外层的行索引转换为内层的列索引
df1 = df.unstack(fill_value=0).stack(level=(0, 1)).unstack(level=0)
df1
孙八 | 张三 | 李四 | 王五 | 田七 | 赵六 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | ||
期中 | 数学 | 0 | 48 | 67 | 0 | 116 | 0 | 38 | 0 | 0 | 73 | 0 | 21 |
语文 | 0 | 52 | 3 | 0 | 111 | 0 | 21 | 0 | 0 | 116 | 0 | 34 | |
期末 | 数学 | 0 | 127 | 101 | 0 | 16 | 0 | 141 | 0 | 0 | 148 | 0 | 49 |
语文 | 0 | 94 | 56 | 0 | 110 | 0 | 109 | 0 | 0 | 26 | 0 | 55 |
思考:如果我们需要交换一下 列一二级索引,该怎么实现呢?
使用swaplevel函数
swaplevel(0, 1, axis=1)
用于在多层行索引和列索引之间交换级别
-
level0, level1:这两个参数用于指定要交换的级别的位置或名称;在多层索引中,级别从 0 开始计数。
-
axis:这个参数用于指定要在哪个轴上进行级别的交换。对于 DataFrame 对象,axis=0 表示在行索引上进行操作,axis=1 表示在列索引上进行操作。
# 交换列一,二级索引
df1.swaplevel(0, 1, axis=1)
一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | 一班 | 二班 | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
孙八 | 孙八 | 张三 | 张三 | 李四 | 李四 | 王五 | 王五 | 田七 | 田七 | 赵六 | 赵六 | ||
期中 | 数学 | 0 | 48 | 67 | 0 | 116 | 0 | 38 | 0 | 0 | 73 | 0 | 21 |
语文 | 0 | 52 | 3 | 0 | 111 | 0 | 21 | 0 | 0 | 116 | 0 | 34 | |
期末 | 数学 | 0 | 127 | 101 | 0 | 16 | 0 | 141 | 0 | 0 | 148 | 0 | 49 |
语文 | 0 | 94 | 56 | 0 | 110 | 0 | 109 | 0 | 0 | 26 | 0 | 55 |
聚合操作
df
期中 | 期末 | ||||
---|---|---|---|---|---|
语文 | 数学 | 语文 | 数学 | ||
一班 | 张三 | 3 | 67 | 56 | 101 |
李四 | 111 | 116 | 110 | 16 | |
王五 | 21 | 38 | 109 | 141 | |
二班 | 赵六 | 34 | 21 | 55 | 49 |
田七 | 116 | 73 | 26 | 148 | |
孙八 | 52 | 48 | 94 | 127 |
df_1 = df.loc['一班', '期中'].copy()
df_1
语文 | 数学 | |
---|---|---|
张三 | 3 | 67 |
李四 | 111 | 116 |
王五 | 21 | 38 |
# 默认axis=0对行聚合, 留下了列, 最后的效果就是求的每一列的和.
df_1.sum()
"""
语文 135
数学 221
dtype: int64
"""
# axis=1对列聚合,每一行的和.
df_1.sum(axis=1)
"""
张三 70
李四 227
王五 59
dtype: int64
"""
# 计算一班二班, 各科, 期中期末的平均成绩.
# axis=0, 意味着对行进行聚合.
# level=0表示要保留level0, 除此之外的行索引, 就会被聚合掉.
df.sum(level=0, axis=0)
期中 | 期末 | |||
---|---|---|---|---|
语文 | 数学 | 语文 | 数学 | |
一班 | 135 | 221 | 275 | 258 |
二班 | 202 | 142 | 175 | 324 |
groupby()
根据指定的条件将数据分组并对每个分组应用相应的操作
-
by:这是最重要的参数,用于指定分组依据的列名、列名列表、Series、索引级别等;用于只有一级索引的聚合。
-
axis:指定分组的方向,axis=0 表示按行分组(默认值),axis=1 表示按列分组。
-
level:如果数据是多层索引的 DataFrame,可以使用 level 参数指定要在哪个级别上进行分组。
-
sort:默认为 True,表示在分组过程中是否对结果进行排序。
-
as_index:默认为 True,表示分组的依据列会变成结果 DataFrame 的索引。如果设置为 False,则不会将分组列设置为索引。
其他参数:group_keys、squeeze、observed 等,用于控制分组的其他行为。
# 默认axix=0按行分组;level=0默认按第0级行索引聚合
df.groupby(level=0).sum()
期中 | 期末 | |||
---|---|---|---|---|
语文 | 数学 | 语文 | 数学 | |
一班 | 135 | 221 | 275 | 258 |
二班 | 202 | 142 | 175 | 324 |
# 求一班二班, 期中, 期末总成绩.
df.groupby(level=0).sum().stack().groupby(level=0).sum()
期中 | 期末 | |
---|---|---|
一班 | 356 | 533 |
二班 | 344 | 499 |
# 求期末和期中每科目的平均成绩;对列操作. 期中期末要平均掉.
df.groupby(axis=1, level=1).mean()
数学 | 语文 | ||
---|---|---|---|
一班 | 张三 | 84.0 | 29.5 |
李四 | 66.0 | 110.5 | |
王五 | 89.5 | 65.0 | |
二班 | 赵六 | 35.0 | 44.5 |
田七 | 110.5 | 71.0 | |
孙八 | 87.5 | 73.0 |
# 求期中与期末中每个同学各科目的最高分
df.groupby(axis=1, level=1).max()
数学 | 语文 | ||
---|---|---|---|
一班 | 张三 | 101 | 56 |
李四 | 116 | 111 | |
王五 | 141 | 109 | |
二班 | 赵六 | 49 | 55 |
田七 | 148 | 116 | |
孙八 | 127 | 94 |