0

0

高效利用Pandas与NumPy根据键值条件映射DataFrame多列数据

花韻仙語

花韻仙語

发布时间:2025-11-26 14:40:17

|

671人浏览过

|

来源于php中文网

原创

高效利用Pandas与NumPy根据键值条件映射DataFrame多列数据

本教程探讨了如何高效地根据dataframe中“键”列的值,有条件地映射和修改多列数据。针对重复使用`numpy.select`的低效性,文章提供了两种优化的矢量化解决方案:一是利用`pandas.get_dummies`创建布尔掩码并结合`dataframe.mask`进行批量替换;二是采用数据重塑(`melt`、`merge`、`unstack`)的方法实现灵活的数据过滤与填充,旨在提升数据处理性能和代码可读性

在数据分析和处理中,我们经常需要根据某一“键”列的值,有选择性地更新或保留DataFrame中其他多列的数据。例如,如果key列的值是'key1',我们可能只关心colA和colD的值,而其他列则应被标记为'NA'。传统上,这可能通过为每个目标列单独调用numpy.select来实现,但这在处理大量列时效率低下且代码冗余。本教程将介绍两种更高效、更具Pythonic风格的矢量化方法来解决这一问题。

问题场景概述

假设我们有一个DataFrame,其中包含一个key列和若干数据列(如colA到colD)。我们的目标是:

  • 对于每一行,如果key列的值与特定条件匹配,则保留某些指定列的原始值。
  • 如果key列的值不匹配,则将这些列的值设置为'NA'(或任何其他默认值)。
  • 一个key值可能对应多个需要保留的列。

以下是原始的低效实现示例:

import pandas as pd
import numpy as np

# 创建示例DataFrame
data = {
    'key': ['key1', 'key2', 'key3', 'key1', 'key2'],
    'colA': ['value1A', 'value2A', 'value3A', 'value4A', 'value5A'],
    'colB': ['value1B', 'value2B', 'value3B', 'value4B', 'value5B'],
    'colC': ['value1C', 'value2C', 'value3C', 'value4C', 'value5C'],
    'colD': ['value1D', 'value2D', 'value3D', 'value4D', 'value5D']
}
df = pd.DataFrame(data)

# 低效的重复调用 numpy.select
df['colA'] = np.select([df['key'] == 'key1'], [df['colA']], default='NA')
df['colD'] = np.select([df['key'] == 'key1'], [df['colD']], default='NA')
df['colB'] = np.select([df['key'] == 'key2'], [df['colB']], default='NA')
df['colC'] = np.select([df['key'] == 'key3'], [df['colC']], default='NA')

print("原始DataFrame和低效处理结果:")
print(df)

这种方法的问题在于,每当需要处理一个新列或新的key-column映射时,都需要添加一行新的np.select代码,这在列数很多时难以维护且效率低下。

解决方案一:利用 get_dummies 和 mask 创建布尔掩码

此方法的核心思想是首先构建一个布尔掩码,该掩码指示了DataFrame中每个单元格是否应该保留其原始值。然后,使用DataFrame.mask方法根据此掩码批量替换不符合条件的值。

1. 定义键与列的映射关系

首先,我们需要一个字典来明确每个key值对应哪些列应该被保留。

d = {'key1': ['colA', 'colD'],
     'key2': ['colB'],
     'key3': ['colC']}

2. 生成布尔掩码

接下来,我们将这个字典转换为一个布尔DataFrame,其中行索引是key值,列是数据列名。True表示该key值对应的行,该列应保留数据;False则表示应替换为'NA'。

# 将字典转换为Series并展开
s = pd.Series(d).explode()
# 使用get_dummies创建布尔矩阵,指示每个key对应哪些列
mask_df = pd.get_dummies(s, dtype=bool).groupby(level=0).max()

mask_df的结构将如下所示:

AI at Meta
AI at Meta

Facebook 旗下的AI研究平台

下载
       colA   colB   colC   colD
key1   True  False  False   True
key2  False   True  False  False
key3  False  False   True  False

3. 应用掩码到DataFrame

有了mask_df,我们可以将其重新索引到原始DataFrame的key列,生成一个与原始DataFrame数据部分形状相同的布尔数组。然后,使用DataFrame.mask方法,它会根据布尔条件替换值为True的位置上的数据(注意:mask方法默认替换True,where方法默认替换False)。为了达到我们的目的,即替换不符合条件(False)的值,我们可以直接使用where方法,或者对mask_df取反后使用mask。这里我们直接使用where方法,它在条件为True时保留原始值,条件为False时替换为指定值。

# 筛选出需要处理的数据列
cols_to_process = df.columns.difference(['key'])

# 根据df['key']重新索引mask_df,生成与df数据部分形状一致的布尔数组
# .to_numpy() 转换为NumPy数组以提高性能
aligned_mask = mask_df.reindex(df['key']).to_numpy()

# 使用where方法进行条件替换
df[cols_to_process] = df[cols_to_process].where(aligned_mask, 'NA')

完整代码示例:

import pandas as pd
import numpy as np

data = {
    'key': ['key1', 'key2', 'key3', 'key1', 'key2'],
    'colA': ['value1A', 'value2A', 'value3A', 'value4A', 'value5A'],
    'colB': ['value1B', 'value2B', 'value3B', 'value4B', 'value5B'],
    'colC': ['value1C', 'value2C', 'value3C', 'value4C', 'value5C'],
    'colD': ['value1D', 'value2D', 'value3D', 'value4D', 'value5D']
}
df = pd.DataFrame(data)

d = {'key1': ['colA', 'colD'],
     'key2': ['colB'],
     'key3': ['colC']}

# 1. 创建键与列的映射Series
s = pd.Series(d).explode()

# 2. 生成布尔掩码DataFrame
# get_dummies将s转换为one-hot编码形式的DataFrame
# groupby(level=0).max() 合并相同key的行,确保所有对应列都为True
mask_df = pd.get_dummies(s, dtype=bool).groupby(level=0).max()

# 3. 筛选出需要处理的数据列
cols_to_process = df.columns.difference(['key'])

# 4. 根据df['key']对mask_df进行reindex,使其与原始DataFrame的行对齐
# to_numpy() 转换为NumPy数组,提高后续操作效率
aligned_mask = mask_df.reindex(df['key']).to_numpy()

# 5. 使用where方法进行条件替换:
# 当aligned_mask为True时,保留df[cols_to_process]的原始值
# 当aligned_mask为False时,替换为'NA'
df[cols_to_process] = df[cols_to_process].where(aligned_mask, 'NA')

print("\n解决方案一结果:")
print(df)

解决方案二:利用数据重塑(melt, merge, unstack)

第二种方法通过将数据从宽格式(wide format)转换为长格式(long format),进行过滤,然后再转换回宽格式来实现。这种方法在处理更复杂的数据过滤和聚合场景时非常强大。

1. 定义键与列的映射关系

与方法一相同,我们首先定义映射字典:

d = {'key1': ['colA', 'colD'],
     'key2': ['colB'],
     'key3': ['colC']}

2. 数据重塑为长格式并合并过滤

  • melt: 将原始DataFrame的数据列转换为行,创建variable(列名)和value列。同时保留原始索引和key列。
  • 创建映射DataFrame: 将映射字典d也转换为长格式,包含key和variable。
  • merge: 将熔化后的原始数据与映射DataFrame合并。只有当原始数据的key和variable(列名)组合在映射字典中存在时,数据才会被保留。
  • set_index: 设置新的索引,为后续的unstack做准备。
# 1. 准备映射数据
map_df = pd.Series(d).explode().rename_axis('key').reset_index(name='variable')

# 2. 熔化原始DataFrame,保留'index'和'key'作为id_vars
melted_df = df.reset_index().melt(['index', 'key'])

# 3. 将熔化后的数据与映射数据合并,实现过滤
# 只有在map_df中存在的(key, variable)组合才会被保留
filtered_df = melted_df.merge(map_df)

# 4. 设置索引并堆叠,将'value'列重新转换为宽格式
result_df = filtered_df.set_index(['index', 'key', 'variable'])['value'] \
                       .unstack('variable', fill_value='NA') \
                       .reset_index('key') \
                       .rename_axis(index=None, columns=None)

完整代码示例:

import pandas as pd
import numpy as np

data = {
    'key': ['key1', 'key2', 'key3', 'key1', 'key2'],
    'colA': ['value1A', 'value2A', 'value3A', 'value4A', 'value5A'],
    'colB': ['value1B', 'value2B', 'value3B', 'value4B', 'value5B'],
    'colC': ['value1C', 'value2C', 'value3C', 'value4C', 'value5C'],
    'colD': ['value1D', 'value2D', 'value3D', 'value4D', 'value5D']
}
df = pd.DataFrame(data)

d = {'key1': ['colA', 'colD'],
     'key2': ['colB'],
     'key3': ['colC']}

# 1. 将原始DataFrame的索引重置,并将其和'key'列作为标识符,将其他数据列“熔化”为长格式
# 'index'列用于后续重构原始DataFrame的顺序
melted_df = df.reset_index().melt(['index', 'key'])

# 2. 将映射字典d转换为一个DataFrame,其中包含'key'和'variable'(列名)
map_df = pd.Series(d).explode().rename_axis('key').reset_index(name='variable')

# 3. 将熔化后的数据与映射DataFrame合并
# 只有当melted_df中的(key, variable)组合在map_df中存在时,该行才会被保留
merged_df = melted_df.merge(map_df, on=['key', 'variable'])

# 4. 设置新的多级索引,然后使用unstack将'variable'列重新转换为列
# fill_value='NA'用于填充那些没有匹配到的单元格
# reset_index('key') 将key列从索引中移回普通列
# rename_axis(index=None, columns=None) 清理索引和列的名称,使其更美观
result_df = merged_df.set_index(['index', 'key', 'variable'])['value'] \
                     .unstack('variable', fill_value='NA') \
                     .reset_index('key') \
                     .rename_axis(index=None, columns=None)

# 5. 将处理后的数据合并回原始DataFrame,或者直接使用result_df
# 为了保持原始DataFrame的结构,这里可以将key列也考虑进去
final_df = df[['key']].merge(result_df, left_index=True, right_index=True, how='left')
# 确保列顺序与原始问题一致,并且没有重复的key列
final_df = final_df[['key'] + [col for col in df.columns if col not in ['key']]]

print("\n解决方案二结果:")
print(final_df)

注意:在实际应用中,如果只是需要最终结果,可以直接使用result_df。如果需要确保原始key列的位置和所有列的顺序与原始df完全一致,可能需要额外的列重排操作。上述代码中,为了保持与原始df的key列和列顺序一致,进行了一次merge和列重排。

总结与注意事项

这两种矢量化方法都比重复调用numpy.select更高效、更简洁,尤其是在处理大量列和复杂映射关系时。

  • 方法一(get_dummies + mask)
    • 优点:代码相对直观,直接构建布尔掩码进行条件替换。对于只需要根据条件替换现有DataFrame中值的情况,效率很高。
    • 适用场景:当你需要基于key列的值,有条件地保留或替换DataFrame中现有列的值时。
  • 方法二(melt + merge + unstack)
    • 优点:非常灵活,通过将数据重塑为长格式,可以更容易地进行过滤、聚合和更复杂的条件操作。
    • 适用场景:当你需要执行更复杂的数据转换,例如不仅是替换值,还可能涉及到根据key进行分组计算、聚合,或者从外部源合并数据来决定哪些值应该被保留时。它提供了一种更通用的数据操作范式。

在选择哪种方法时,可以根据具体需求和个人偏好来决定。通常,如果任务只是简单的条件替换,get_dummies和mask的组合可能更直接。如果数据操作涉及到更复杂的重组或与外部数据源的交互,melt/merge/unstack的管道会更具优势。无论选择哪种,都应优先考虑使用Pandas和NumPy提供的矢量化操作,以最大化数据处理的效率和可维护性。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

51

2025.12.04

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python中的format是什么意思
python中的format是什么意思

python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

430

2024.06.27

数据分析的方法
数据分析的方法

数据分析的方法有:对比分析法,分组分析法,预测分析法,漏斗分析法,AB测试分析法,象限分析法,公式拆解法,可行域分析法,二八分析法,假设性分析法。php中文网为大家带来了数据分析的相关知识、以及相关文章等内容。

465

2023.07.04

数据分析方法有哪几种
数据分析方法有哪几种

数据分析方法有:1、描述性统计分析;2、探索性数据分析;3、假设检验;4、回归分析;5、聚类分析。本专题为大家提供数据分析方法的相关的文章、下载、课程内容,供大家免费下载体验。

279

2023.08.07

网站建设功能有哪些
网站建设功能有哪些

网站建设功能包括信息发布、内容管理、用户管理、搜索引擎优化、网站安全、数据分析、网站推广、响应式设计、社交媒体整合和电子商务等功能。这些功能可以帮助网站管理员创建一个具有吸引力、可用性和商业价值的网站,实现网站的目标。

726

2023.10.16

数据分析网站推荐
数据分析网站推荐

数据分析网站推荐:1、商业数据分析论坛;2、人大经济论坛-计量经济学与统计区;3、中国统计论坛;4、数据挖掘学习交流论坛;5、数据分析论坛;6、网站数据分析;7、数据分析;8、数据挖掘研究院;9、S-PLUS、R统计论坛。想了解更多数据分析的相关内容,可以阅读本专题下面的文章。

507

2024.03.13

Python 数据分析处理
Python 数据分析处理

本专题聚焦 Python 在数据分析领域的应用,系统讲解 Pandas、NumPy 的数据清洗、处理、分析与统计方法,并结合数据可视化、销售分析、科研数据处理等实战案例,帮助学员掌握使用 Python 高效进行数据分析与决策支持的核心技能。

71

2025.09.08

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 3.8万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号