解决 Pandas DataFrame 高度碎片化警告:高效创建多列的策略


当在 pandas dataframe 中通过循环或重复赋值创建大量新列时,可能会遇到 `performancewarning: dataframe is highly fragmented` 警告。此警告表明 dataframe 内存布局变得碎片化,导致性能下降。本文将深入探讨此警告的成因,并提供使用 `pd.concat` 方法高效、批量创建新列的专业解决方案,从而避免碎片化并提升数据处理效率。

理解 DataFrame 碎片化警告

PerformanceWarning: DataFrame is highly fragmented 警告通常在您对现有 DataFrame 反复执行列插入操作时出现。在 Pandas 中,DataFrame 的内存布局通常是为连续性访问优化的。当您使用 df['new_col'] = ... 这种方式逐个添加大量新列时,Pandas 可能会在底层执行多次内存重新分配操作。每次重新分配都可能导致数据在内存中的存储不再连续,从而形成“碎片”。

这种碎片化现象会带来两个主要问题:

  1. 性能下降: 内存碎片化会增加数据访问的开销,因为处理器需要花费更多时间来查找和读取非连续存储的数据块。这在处理大型 DataFrame 时尤为明显。
  2. 内存效率降低: 碎片化的内存可能导致实际使用的内存量高于理论值,因为一些小的空闲块可能无法被有效利用。

考虑一个常见场景:从一个包含长字符串的列中,根据不同位置切片并生成数百甚至近千个新列。以下是导致警告的典型代码模式:

import pandas as pd
import numpy as np
import string

# 模拟一个包含长字符串的DataFrame
np.random.seed(0)
df_fragmented = pd.DataFrame({
    "long_string": ["".join(np.random.choice(
        [*string.printable[:62]], size=5000)) for _ in range(10000)]
})

def parse_long_string_fragmented(df):
    # 假设需要从 long_string 中切片出 972 个新列
    # 这是一个简化示例,实际可能需要更多列
    df['a001'] = df['long_string'].str[0:2]
    df['a002'] = df['long_string'].str[2:4]
    df['a003'] = df['long_string'].str[4:13]
    # ... 更多类似的列赋值操作,直到 a972
    df['a972'] = df['long_string'].str[4994:]
    return df

# 调用此函数时,会触发 PerformanceWarning
# result_fragmented = parse_long_string_fragmented(df_fragmented.copy())

上述代码中,每次 df['aXXX'] = ... 都会尝试在现有 DataFrame 中插入新列。当列数非常多时,这种重复的插入操作会显著增加 DataFrame 的碎片化程度,并最终触发 PerformanceWarning。

解决方案:使用 pd.concat 批量创建新列

为了避免 DataFrame 碎片化并提高性能,最佳实践是批量创建所有新列,然后一次性将它们添加到原始 DataFrame 中。pd.concat 函数是实现这一目标的高效工具。

核心思想是:

  1. 预先定义所有需要切片的起始和结束位置。
  2. 利用 Pandas 的字符串切片功能 (.str[start:end]),为每个新列生成一个 Series。
  3. 将所有这些 Series 收集起来,使用 pd.concat(..., axis=1) 将它们合并成一个新的 DataFrame。
  4. 最后,使用 df.join() 或 pd.concat 将这个包含所有新列的 DataFrame 与原始 DataFrame 合并。

以下是使用 pd.concat 解决上述问题的具体实现:

import pandas as pd
import numpy as np
import string

# 1. 准备示例数据
np.random.seed(0)
df = pd.DataFrame({
    "long_string": ["".join(np.random.choice(
        [*string.printable[:62]], size=5000)) for _ in range(10000)]
})

# 2. 定义切片规则 (使用字典更具可读性)
# 这是一个包含 972 个切片规则的字典
slices_mapper = {f"a{i+1:03d}": (i*2, (i+1)*2) for i in range(249)} # 简化到249个,避免过长的输出
# 假设实际场景中,最后几列可能不是固定长度,例如:
slices_mapper["a250"] = (498, 500) # 模拟最后几列
slices_mapper["a251"] = (500, None) # 从500到字符串末尾

# 3. 定义解析函数,使用 pd.concat
def parse_long_string_optimized(df_input, mapper):
    """
    高效解析长字符串列并创建多个新列,避免 DataFrame 碎片化。

    Args:
        df_input (pd.DataFrame): 包含 'long_string' 列的 DataFrame。
        mapper (dict): 字典,键为新列名,值为元组 (start, end) 表示切片范围。

    Returns:
        pd.DataFrame: 包含原始列和所有新列的 DataFrame。
    """
    # 使用字典推导式为每个新列生成一个 Series,然后通过 pd.concat 沿列方向合并
    new_cols_df = pd.concat(
        {
            col_name: df_input["long_string"].str[start:end]
            for col_name, (start, end) in mapper.items()
        },
        axis=1 # 沿列方向合并
    )

    # 将新生成的 DataFrame 与原始 DataFrame 进行连接
    return df_input.join(new_cols_df)

# 4. 调用优化后的函数
result_optimized = parse_long_string_optimized(df, slices_mapper)

# 打印结果 DataFrame 的信息
print(result_optimized.head())
print(f"\nDataFrame 形状: {result_optimized.shape}")
print(f"DataFrame 列数: {len(result_optimized.columns)}")

代码解释:

  • slices_mapper: 这是一个字典,其键是您希望创建的新列的名称(例如 a001),值是一个元组 (start, end),表示从 long_string 列中切片的起始和结束索引。使用 None 作为结束索引表示切片到字符串末尾。
  • 字典推导式 for col_name, (start, end) in mapper.items(): 这会遍历 slices_mapper 字典中的每一个键值对。对于每个键值对,它会从 df_input["long_string"] 中使用 .str[start:end] 方法提取相应的子字符串,生成一个新的 Pandas Series。
  • pd.concat({...}, axis=1):
    • 花括号 {...} 中的内容创建了一个字典,其中键是新列名,值是对应的 Series。
    • pd.concat 接收一个 Series 或 DataFrame 对象的列表或字典。当传入字典时,字典的键将成为新 DataFrame 的列名。
    • axis=1 参数指示 pd.concat 沿着列方向(水平方向)进行连接,将所有的 Series 组合成一个全新的 DataFrame new_cols_df。
  • df_input.join(new_cols_df): 最后,使用 df.join() 方法将原始 DataFrame df_input 与包含所有新列的 new_cols_df 进行合并。join 方法默认基于索引进行合并,这里两个 DataFrame 的索引是匹配的,因此可以无缝连接。

总结与最佳实践

  • 避免逐列添加: 当需要创建大量新列时,应避免使用 df['new_col'] = ... 这种逐列赋值的方式,因为它会导致 DataFrame 碎片化和性能下降。
  • 优先批量操作: 采用 pd.concat、df.assign() (适用于少量列) 或其他批量操作来一次性创建和添加多列。
  • pd.concat 的优势: 适用于从现有列派生出大量新列的场景,它通过构建一个全新的、非碎片化的 DataFrame 来避免性能问题。
  • 数据结构设计: 在设计数据处理流程时,预先考虑如何高效地生成和整合新数据,以减少不必要的中间操作和内存重分配。
  • 必要时使用 df.copy(): 如果一个 DataFrame 已经变得高度碎片化,并且您需要对其进行大量后续操作,可以考虑使用 new_df = old_df.copy() 来创建一个全新的、内存连续的副本,从而“整理”DataFrame 的内存。但这通常是亡羊补牢,更好的方法是在一开始就避免碎片化。

通过采纳 pd.concat 这种批量处理策略,您可以显著提升 Pandas 数据处理的效率和稳定性,尤其是在处理大规模数据集和复杂特征工程任务时。


# 处理器  # app  # 工具  # 数据访问  # 键值对  # pandas  # for  # 字符串  # 循环  # 数据结构  # 切片  # copy  # 对象  # 这是一个  # 数据处理  # 适用于  # 它会  # 键值  # 串列  # 是一个  # 是在  # 多个  # 亡羊补牢 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: 如何在Golang中使用闭包_封装变量与函数作用域  Windows执行文件被SmartScreen拦截原因_安全提示与绕过方式  c# 如何用c#实现一个支持优先级的任务队列  php订单日志怎么记录发货_php记录订单发货操作日志指南【指南】  c++ unordered_map怎么用 c++哈希表用法【教程】  Win11怎么开启窗口对齐助手_Windows11系统多任务处理设置  Win11怎么关闭透明效果_Windows11个性化颜色关闭透明  c++的位运算怎么用 与、或、异或、移位操作详解【底层知识】  如何在Golang中优化文件读写性能_使用缓冲和并发处理  Python字符串操作教程_切片拼接与格式化详解  Win11怎么设置组合键快捷方式_Windows11自定义快捷键操作  mac怎么分屏_MAC双屏显示与分屏操作技巧【指南】  Win10电脑怎么设置休眠快捷键_Windows10电源按钮功能定义  如何使用 Python 合并文件夹内多个 Excel 文件并避免权限错误  c++20的std::format怎么用 比printf更安全高效的格式化方法【详解】  Win11怎么开启游戏工具栏_Windows11 Xbox Game Bar快捷键  Laravel 查询 JSON 列:高效筛选包含数组中任意值的记录  PHP接收参数长度超限怎么办_修改postmaxsize设置教程【解答】  如何在 Go 中比较自定义的数组类型(如 [20]byte)  Win11怎样安装微信开发者工具_Win11安装开发者工具教程【步骤】  Python函数缓存机制_lru_cache解析【指导】  Python项目回滚策略_发布安全说明【指导】  Win11怎么关闭触控板_Win11笔记本禁用触摸板快捷键  如何使用Golang指针与接口结合_实现方法调用和动态类型  Windows 10怎么录屏_Windows 10使用Xbox Game Bar录制屏幕视频教程  Python迭代器生成器进阶教程_节省内存与懒加载实战  Win11怎么恢复旧版开始菜单_通过软件还原Win10风格菜单【详解】  Windows7怎么找回经典开始菜单_Windows7经典菜单找回步骤【方法】  Win11声音太小怎么办_Windows 11开启响度均衡增强音量【技巧】  Win11 C盘满了怎么清理 Win11磁盘清理和存储感知使用教程【新手必看】  Win11如何卸载OneDrive_Win11卸载OneDrive方法【教程】  为什么Go建议使用error接口作为错误返回_Go Error接口设计原因说明  Mac的“调度中心”与“空间”怎么用_Mac多桌面高效管理【技巧】  Win11时间怎么同步到原子钟 Win11高精度时间同步设置【指南】  Win11文件扩展名怎么显示_Win11查看文件后缀名设置【基础】  Win11怎么设置右键刷新选项_Windows11显示更多选项技巧  c++中如何计算坐标系中两点间距离_c++勾股定理求距离  如何使用Golang实现函数指针_函数变量与回调示例  Python数据挖掘进阶教程_分类回归与聚类案例解析  Linux如何安装Golang环境_Linux下Go语言开发包配置【方法】  Win10如何备份驱动程序_Win10驱动备份步骤【攻略】  PythonGIL机制理解_多线程限制解析【教程】  Python模块的__name__属性如何由导入方式决定?  Win10电脑怎么设置网络名称_Windows10注册表NetworkList修改  Python数据抓取合法性_合规说明【指导】  Python爬虫项目实战教程_Scrapy抓取与存储数据实例  Go 中实现 Python urllib.quote() 功能的等效方法  php下载安装选zip还是msi格式_两种安装包对比【教程】  Win11无法识别耳机怎么办_解决Win11插耳机没声音问题【步骤】  如何更改Windows资源管理器的默认启动位置?(快速访问/此电脑) 

 2025-11-27

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.