You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas数据转换:向量化加速循环的方案咨询

问题描述

现有如下格式的DataFrame,每行对应一位唯一的家长,每位家长可拥有多个孩子,孩子相关列遵循统一命名规则:

import pandas as pd

df = pd.DataFrame({'Parent_username': ['Bob1', 'Ron23', 'Lisa00', 'Joe_'],
                   'Parent_age': [38, None, 40, 26],
                   'Child1_name': ['Mike', 'John', 'Curt', 'Kelly'],
                   'Child1_age': [2, None, 1, 2],
                   'Child2_name': ['Pat', 'Dennis', None, None],
                   'Child2_age': [4, None, None, None]}) 

原始DataFrame样式:

Parent_username  Parent_age Child1_name  Child1_age Child2_name  Child2_age
0            Bob1        38.0        Mike         2.0         Pat         4.0
1           Ron23         NaN        John         NaN      Dennis         NaN
2          Lisa00        40.0        Curt         1.0        None         NaN
3            Joe_        26.0       Kelly         2.0        None         NaN

需要将其转换为每行对应一个孩子的格式,其中Child_number表示该孩子是第几个孩子:

df2 = pd.DataFrame({'Child_name': ['Mike', 'Pat', 'John', 'Dennis', 'Curt', 'Kelly'],
                    'Child_number': [1, 2, 1, 2, 1, 1],
                    'Child_age': [2, 4, None, None, 1, 2],
                    'Parent_username': ['Bob1', 'Bob1', 'Ron23', 'Ron23', 'Lisa00', 'Joe_'],
                    'Parent_age': [38, 38, None, None, 40, 26]})

目标样式:

Child_name  Child_number  Child_age Parent_username  Parent_age
0       Mike             1        2.0            Bob1        38.0
1        Pat             2        4.0            Bob1        38.0
2       John             1        NaN           Ron23         NaN
3     Dennis             2        NaN           Ron23         NaN
4       Curt             1        1.0          Lisa00        40.0
5      Kelly             1        2.0            Joe_        26.0

原本使用嵌套循环拷贝数据的方式耗时极长:

for index in df.index:
    for col in df.columns:
        # 用dataframe.loc将df.loc[index, col]拷贝到df2对应位置

希望找到更快的实现方式,不确定向量化操作是否适用于字符串列,寻求建议。


高效实现方案

使用pandas内置的向量化函数可以完全替代循环,效率提升显著,且完美支持字符串列处理,以下提供两种可靠方案:

方案1:使用wide_to_long(推荐,专门适配宽表转长表场景)

wide_to_long是pandas专为这种"前缀+编号+属性"的宽表设计的转换工具,代码简洁高效:

# 执行宽表转长表
df_long = pd.wide_to_long(df,
                          stubnames=['Child'],  # 孩子列的统一前缀
                          i=['Parent_username', 'Parent_age'],  # 保留的家长标识列
                          j='Child_number',  # 生成的孩子编号列名
                          sep='',  # 列名中前缀与编号的分隔符(此处无分隔符)
                          suffix=r'\d+')  # 匹配编号的正则规则(数字)

# 重置索引为普通列,并拆分Child列的姓名与年龄
df_long = df_long.reset_index()
df_long[['Child_name', 'Child_age']] = pd.DataFrame(df_long['Child'].tolist(), index=df_long.index)

# 整理最终格式:删除冗余列、调整列顺序、过滤空孩子姓名行
df_final = df_long.drop('Child', axis=1)[['Child_name', 'Child_number', 'Child_age', 'Parent_username', 'Parent_age']]
df_final = df_final.dropna(subset=['Child_name'])

方案2:使用melt分步处理

如果对wide_to_long的参数逻辑不熟悉,可通过melt分两次处理孩子姓名和年龄列,再合并结果:

# 拆分孩子姓名列
name_melt = df.melt(id_vars=['Parent_username', 'Parent_age'],
                    value_vars=['Child1_name', 'Child2_name'],
                    var_name='Child_number',
                    value_name='Child_name')

# 拆分孩子年龄列
age_melt = df.melt(id_vars=['Parent_username', 'Parent_age'],
                   value_vars=['Child1_age', 'Child2_age'],
                   var_name='Child_number',
                   value_name='Child_age')

# 提取孩子编号并转换为整数类型
name_melt['Child_number'] = name_melt['Child_number'].str.extract(r'(\d+)').astype(int)
age_melt['Child_number'] = age_melt['Child_number'].str.extract(r'(\d+)').astype(int)

# 合并姓名与年龄数据,整理最终格式
df_final = pd.merge(name_melt, age_melt, on=['Parent_username', 'Parent_age', 'Child_number'])
df_final = df_final.dropna(subset=['Child_name'])[['Child_name', 'Child_number', 'Child_age', 'Parent_username', 'Parent_age']]

两种方案均为向量化操作,完全避免循环,处理大数据集时效率比嵌套循环高几个数量级,运行后均可得到目标格式的DataFrame。

内容的提问来源于stack exchange,提问作者user173729

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:32:44