如何将宽格式DataFrame按固定列数重塑为长格式

如何将宽格式DataFrame按固定列数重塑为长格式

本教程详细介绍了如何将一个具有大量列的宽格式pandas DataFrame重塑为更易读的垂直长格式。文章提供了两种核心方法:当总列数是目标列数的完美倍数时,可以使用numpy的`reshape`功能高效处理;当总列数不是目标列数的完美倍数时,则采用Pandas的`MultiIndex`和`stack`操作灵活应对。通过具体代码示例和注意事项,帮助读者掌握数据重塑技巧,提升数据处理效率和可读性。

数据重塑:将宽格式DataFrame转换为长格式

数据分析和处理中,我们经常会遇到包含大量列的“宽格式”DataFrame。这种格式在某些情况下可能难以阅读和分析,例如,当逻辑上相关的列被水平地分散在整个数据集中时。本教程将指导您如何将这类宽格式DataFrame,按照每N列一组的方式,重塑为一个更紧凑、更易于理解的“长格式”DataFrame。我们将探讨两种主要场景:当总列数是目标分组列数的完美倍数时,以及当它不是完美倍数时。

场景一:总列数是目标分组列数的完美倍数

当原始DataFrame的总列数能够被目标分组列数(例如,每6列一组)整除时,使用NumPy的reshape功能是最高效且简洁的方法。

1.1 方法概述

这种方法的核心是将DataFrame转换为NumPy数组,然后利用numpy.reshape()将其重塑为新的维度。由于我们希望最终的DataFrame有固定数量的列(例如6列),我们可以指定目标列数为6,并让NumPy自动推断行数。

1.2 示例代码

假设我们有一个包含606列的DataFrame,并且我们希望每6列为一组,将其转换为一个具有6列的新DataFrame。

import pandas as pd import numpy as np  # 模拟一个宽格式DataFrame # 实际应用中,这里会是 df = pd.read_csv("groups.csv") np.random.seed(123) # 假设原始DataFrame有3行12列,每6列一组,目标DataFrame有6列 df = pd.DataFrame(np.random.randint(10, size=(3, 12))) print("原始DataFrame:") print(df) # 预期输出列名 target_columns = ['GroupA', 'GroupB', 'GroupC', 'GroupD', 'GroupE', 'GroupF']  # 检查总列数是否为目标分组列数的倍数 print(f"n原始DataFrame列数: {len(df.columns)}") print(f"列数 % 6: {len(df.columns) % 6}")  if len(df.columns) % 6 == 0:     # 将DataFrame转换为NumPy数组,然后重塑     # -1 表示让NumPy自动计算行数,6 表示目标DataFrame的列数     df_target = pd.DataFrame(df.to_numpy().reshape(-1, 6),                              columns=target_columns)     print("n重塑后的DataFrame (使用 numpy.reshape):")     print(df_target) else:     print("n原始DataFrame的列数不是6的倍数,此方法不适用。") 

代码解析:

  1. df.to_numpy(): 将Pandas DataFrame转换为底层的NumPy数组。这会移除列名,只保留数据值。
  2. .reshape(-1, 6): 这是关键步骤。它将NumPy数组重塑为一个新的形状。
    • -1: 告诉NumPy根据数组中的元素总数和指定的其他维度(这里是6列)自动计算新的行数。
    • 6: 指定新DataFrame的列数。
  3. pd.DataFrame(…, columns=target_columns): 将重塑后的NumPy数组转换回Pandas DataFrame,并指定新的列名。

输出示例:

原始DataFrame:    0  1  2  3  4  5  6  7  8  9  10  11 0  2  2  6  1  3  9  6  1  0  1   9   0 1  0  9  3  4  0  0  4  1  7  3   2   4 2  7  2  4  8  0  7  9  3  4  6   1   5  原始DataFrame列数: 12 列数 % 6: 0  重塑后的DataFrame (使用 numpy.reshape):    GroupA  GroupB  GroupC  GroupD  GroupE  GroupF 0       2       2       6       1       3       9 1       6       1       0       1       9       0 2       0       9       3       4       0       0 3       4       1       7       3       2       4 4       7       2       4       8       0       7 5       9       3       4       6       1       5

注意事项:

  • 此方法要求原始DataFrame的所有数据类型都是兼容的,因为NumPy数组通常是同构的。如果DataFrame包含混合数据类型,to_numpy()可能会将其转换为Object类型。
  • 此方法不保留原始的行索引信息,如果需要,需在重塑前进行保存或后续处理。

场景二:总列数不是目标分组列数的完美倍数

当原始DataFrame的总列数不能被目标分组列数整除时(例如,有5252列,但我们仍想每6列一组),numpy.reshape将无法直接使用。此时,我们可以利用Pandas的MultiIndex和stack操作来灵活处理。

如何将宽格式DataFrame按固定列数重塑为长格式

比格设计

比格设计是135编辑器旗下一款一站式、多场景、智能化的在线图片编辑器

如何将宽格式DataFrame按固定列数重塑为长格式124

查看详情 如何将宽格式DataFrame按固定列数重塑为长格式

2.1 方法概述

这种方法通过创建一个多级列索引来逻辑地分组原始列,然后使用stack()方法将这些分组转换为行。对于不完整的最后一组,stack()会自动填充NaN。

2.2 示例代码

假设我们有一个包含10列的DataFrame,但我们仍然希望每6列为一组进行重塑。

import pandas as pd import numpy as np  # 模拟一个宽格式DataFrame np.random.seed(123) # 假设原始DataFrame有3行10列,每6列一组,目标DataFrame有6列 df_imperfect = pd.DataFrame(np.random.randint(10, size=(3, 10))) print("原始DataFrame (列数非6的倍数):") print(df_imperfect)  # 预期输出列名 target_columns = ['GroupA', 'GroupB', 'GroupC', 'GroupD', 'GroupE', 'GroupF'] group_size = 6  print(f"n原始DataFrame列数: {len(df_imperfect.columns)}") print(f"列数 % {group_size}: {len(df_imperfect.columns) % group_size}")  # 创建一个用于生成MultiIndex的数组 a = np.arange(len(df_imperfect.columns))  # 使用 set_axis 和 MultiIndex 进行重塑 # a % group_size: 生成第一级索引,表示组内位置 (0到5) # a // group_size: 生成第二级索引,表示是第几组 (0, 1, ...) df_target_imperfect = (df_imperfect.set_axis([a % group_size, a // group_size], axis=1)                                    .stack(level=0) # 将第一级索引(组内位置)叠为行                                    .set_axis(target_columns, axis=1) # 设置新的列名                                    .reset_index(drop=True)) # 重置索引,移除MultiIndex的层级 print("n重塑后的DataFrame (使用 Pandas MultiIndex 和 stack):") print(df_target_imperfect)

代码解析:

  1. a = np.arange(len(df_imperfect.columns)): 创建一个与列数等长的整数序列,用于生成索引。
  2. df_imperfect.set_axis([a % group_size, a // group_size], axis=1):
    • a % group_size: 计算每个原始列在目标组中的位置(0, 1, 2, 3, 4, 5, 0, 1, …)。这将成为MultiIndex的第一层。
    • a // group_size: 计算每个原始列属于哪一个目标组(0, 0, 0, 0, 0, 0, 1, 1, …)。这将成为MultiIndex的第二层。
    • set_axis(…, axis=1): 将生成的这两个数组作为新的列索引,创建多级列索引。
  3. .stack(level=0): 这是核心的重塑操作。它将MultiIndex的第一层(即组内位置)从列级别堆叠到行级别。这意味着每个原始行的数据,将根据其在组中的位置,被转换为多行。
  4. .set_axis(target_columns, axis=1): 堆叠后,列名会变成默认的数字索引,我们将其重新设置为目标列名。
  5. .reset_index(drop=True): stack()操作会引入新的索引层级。reset_index(drop=True)用于将这些层级移除,并生成一个干净的默认整数索引。

输出示例:

原始DataFrame (列数非6的倍数):    0  1  2  3  4  5  6  7  8  9 0  2  2  6  1  3  9  6  1  0  1 1  9  0  0  9  3  4  0  0  4  1 2  7  3  2  4  7  2  4  8  0  7  原始DataFrame列数: 10 列数 % 6: 4  重塑后的DataFrame (使用 Pandas MultiIndex 和 stack):    GroupA  GroupB  GroupC  GroupD  GroupE  GroupF 0       2       2       6       1     3.0     9.0 1       6       1       0       1     NaN     NaN 2       9       0       0       9     3.0     4.0 3       0       0       4       1     NaN     NaN 4       7       3       2       4     7.0     2.0 5       4       8       0       7     NaN     NaN

注意事项:

  • 当最后一组的列数不足group_size时,stack()会自动填充NaN值。您可能需要根据具体需求处理这些NaN值(例如,使用fillna()或dropna())。
  • 此方法比numpy.reshape更灵活,但对于非常大的数据集,性能可能会略低于纯NumPy方法。
  • 同样,原始行索引信息不会直接保留。

总结

本教程介绍了两种将宽格式DataFrame重塑为长格式的有效方法:

  1. numpy.reshape(-1, N): 适用于原始列数是目标分组列数N的完美倍数的情况。它直接操作底层NumPy数组,效率高,代码简洁。
  2. Pandas MultiIndex + stack(): 适用于原始列数不是目标分组列数N的完美倍数的情况。它利用Pandas强大的索引和重塑功能,能够灵活处理不完整的分组,并自动填充NaN。

选择哪种方法取决于您的具体数据特性和需求。在实际应用中,了解这两种方法可以帮助您更高效、更灵活地处理各种数据重塑任务。始终记住在重塑后检查数据类型和NaN值,以确保数据质量符合后续分析要求。

上一篇
下一篇
text=ZqhQzanResources