
本文旨在提供一种高效且避免DataFrame碎片化的方法,将包含不同长度子列表的数据以及对应的列名列表整合到现有的Pandas DataFrame中。我们将利用Python的`itertools.zip_longest`函数处理变长数据,并通过巧妙的转置与字典构建,最终使用`pd.concat`将新数据作为列安全地添加到DataFrame,尤其适用于在循环中动态添加大量列的场景。
在数据分析和处理中,我们经常需要将外部数据源(例如来自API响应或动态生成的数据)整合到现有的Pandas DataFrame中。一个常见的挑战是,当这些外部数据以列表形式存在,并且其内部结构(例如子列表的长度)不一致时,如何高效且正确地将其作为新列添加到DataFrame。直接的列表到DataFrame赋值操作有时会导致性能问题,例如PerformanceWarning: DataFrame is highly fragmented。本教程将介绍一种结合itertools.zip_longest和pd.concat的专业方法来解决这一问题。
假设我们有以下数据:
我们的目标是将 list1 中的元素作为新列名,list2 中的数据作为对应的新行数据添加到 df 中,同时处理 list2 中子列表长度不一致的问题,并用默认值(例如0)填充缺失的数据。
直接尝试 df[list1] = pd.DataFrame(list2, index=df.index) 的方法可能导致DataFrame碎片化警告,尤其当在循环中反复执行此操作时,会严重影响性能。这是因为Pandas在每次添加新列时可能需要重新分配内存,而不是高效地在现有内存块上扩展。
为了解决上述问题,我们将采用以下策略:
itertools.zip_longest 是Python标准库中的一个函数,它类似于内置的 zip 函数,但可以处理不同长度的迭代器。当一个迭代器耗尽时,它会用指定的 fillvalue 填充缺失的值,直到最长的迭代器耗尽。
在我们的场景中,list2 包含多个子列表。为了将这些子列表的元素作为新列的数据,我们需要确保每个子列表都具有与 list1 相同的长度。zip_longest 可以帮助我们实现这一点。
首先,我们定义初始数据:
import pandas as pd
from itertools import zip_longest
# 原始数据
list1 = ['col1', 'col2', 'col3', 'col4']
list2 = [[1, 2, 3], [2, 3], [1, 8, 4, 3], [22, 35, 32], [65], [2, 45, 55]]
df = pd.DataFrame([
['Alex', 33, 'Male'],
['Marly', 28, 'Female'],
['Charlie', 30, 'Female'],
['Mimi', 37, 'Female'],
['James', 44, 'Male'],
['Jone', 25, 'Male']
], columns=['Name', 'Age', 'Gender'])
print("原始DataFrame:")
print(df)
print("\n待添加的列名:", list1)
print("待添加的数据 (变长列表):", list2)接下来是处理 list2 并构建新DataFrame的关键部分:
# 步骤1: 使用 zip_longest 填充并转置 list2
# zip_longest(*list2, fillvalue=0) 会将 list2 视为多列进行转置,
# 并且用 fillvalue=0 填充较短的“行”(即原始子列表中的元素)。
# 例如,如果 list2 是 [[1,2,3], [4,5]],zip_longest(*list2, fillvalue=0) 会得到 (1,4), (2,5), (3,0)。
# 它的输出是按“列”组织的,但我们想要按“行”组织的填充数据。
transposed_and_padded = zip_longest(*list2, fillvalue=0)
# 步骤2: 再次使用 zip 进行转置,将数据恢复为按行组织的填充子列表
# zip(*transposed_and_padded) 将把上面按“列”组织的结果再次转置回来,
# 此时每个元素都是一个填充到最长长度的原始子列表。
# 例如,如果上一步得到 (1,4), (2,5), (3,0),这一步会得到 (1,2,3), (4,5,0)。
# 确保每个子列表的长度与 list1 的长度(即所需列数)一致。
# 在本例中,list1 的长度是4,而 list2 中最长子列表的长度也是4。
# 如果 list1 的长度大于 list2 中子列表的最大长度,
# 我们还需要额外处理以确保最终字典的键值对数量正确匹配。
# 但在这里,list1的长度决定了最终列数,zip_longest已经处理了子列表的内部长度。
# 实际上,zip(*zip_longest(*list2, fillvalue=0)) 的结果是:
# [(1, 2, 3, 0), (2, 3, 0, 0), (1, 8, 4, 3), (22, 35, 32, 0), (65, 0, 0, 0), (2, 45, 55, 0)]
# 这里的每个元组都代表一行数据,且长度与 list1 相同。
padded_rows = zip(*transposed_and_padded)
# 步骤3: 将填充后的行数据与列名 list1 组合成字典列表
# 每个字典代表 DataFrame 的一行,键是列名,值是对应的数据。
new_data_dicts = [dict(zip(list1, vals)) for vals in padded_rows]
# 步骤4: 创建新的DataFrame
new_df_columns = pd.DataFrame(new_data_dicts)
# 步骤5: 使用 pd.concat 将新DataFrame与原始DataFrame合并
# axis=1 表示按列合并。
out_df = pd.concat([df, new_df_columns], axis=1)
print("\n整合后的DataFrame:")
print(out_df)输出结果:
原始DataFrame:
Name Age Gender
0 Alex 33 Male
1 Marly 28 Female
2 Charlie 30 Female
3 Mimi 37 Female
4 James 44 Male
5 Jone 25 Male
待添加的列名: ['col1', 'col2', 'col3', 'col4']
待添加的数据 (变长列表): [[1, 2, 3], [2, 3], [1, 8, 4, 3], [22, 35, 32], [65], [2, 45, 55]]
整合后的DataFrame:
Name Age Gender col1 col2 col3 col4
0 Alex 33 Male 1 2 3 0
1 Marly 28 Female 2 3 0 0
2 Charlie 30 Female 1 8 4 3
3 Mimi 37 Female 22 35 32 0
4 James 44 Male 65 0 0 0
5 Jone 25 Male 2 45 55 0本教程提供了一种健壮且高效的方法,用于将包含变长子列表的数据作为新列添加到Pandas DataFrame中。通过利用 itertools.zip_longest 智能地填充数据,并结合 pd.concat 的高效合并机制,我们不仅解决了数据长度不一致的问题,还避免了DataFrame碎片化带来的性能开销。这种方法尤其适用于需要在循环中动态扩展DataFrame的复杂数据处理场景,是Pandas用户进行高级数据整合的有力工具。
以上就是高效地将变长列表数据整合到Pandas DataFrame的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号