讲师中心 微信公众号
AI工具推荐 视频效率加速

Pandas与NumPy高效条件选择:从多列中提取首个非空值及其来源

陌芳吖_8581

陌芳吖_8581

发布时间:2025-07-12 23:22:16

|

696人浏览过

|

来源于php中文网

原创

pandas与numpy高效条件选择:从多列中提取首个非空值及其来源

本文探讨了在Pandas DataFrame中根据条件从多列中选择第一个非空值及其对应列名的有效方法。针对numpy.select无法直接返回多列的限制,提出了一种利用Pandas布尔索引与NumPy argmax结合的简洁高效方案,实现了灵活的数据转换和列生成,避免了重复的条件判断,提升了代码的可读性和执行效率。

问题背景与传统方法局限

在数据处理中,我们经常面临需要从多个潜在来源列中,根据特定条件(例如,选择第一个非空值)提取数据,并同时记录该数据来源列名的情况。numpy.select是处理条件赋值的强大工具,但其设计主要针对单列输出。当尝试使用np.select同时返回多个列时,例如一个值列和一个来源列,通常会遇到类型不匹配或维度错误,迫使开发者采取多次独立的np.select调用,即使这些调用共享相同的条件逻辑。

考虑以下DataFrame示例:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A': [1.0, 2.0, np.nan],
    'B': [4, 5, 6]
})
print("原始DataFrame:")
print(df)

期望的输出是新增val和val_source两列,其中val优先取A列的值,如果A列为NaN,则取B列的值;val_source则记录该值来自A或B。

传统的np.select方法可能如下所示:

# 传统但繁琐的方法
conds = [df['A'].notna(), True]
choices_val = [df['A'], df['B']]
choices_src = ['A', 'B']

df['val'] = np.select(conds, choices_val, default=np.nan)
df['val_source'] = np.select(conds, choices_src, default=np.nan)
print("\n使用传统np.select方法的结果:")
print(df)

尽管此方法能够达到目的,但其缺点在于需要重复定义条件并进行两次独立的np.select操作,当涉及更多列或更复杂的条件时,代码会显得冗长且效率不高。

高效解决方案:结合Pandas布尔索引与NumPy argmax

为了解决上述问题,我们可以利用Pandas的布尔索引能力和NumPy的argmax函数,以一种更简洁高效的方式实现目标。核心思想是首先确定每行中第一个非空值所在的列位置,然后利用这个位置信息直接从原始DataFrame中提取值和对应的列名。

1. 确定每行第一个非空值的列索引

首先,我们需要识别DataFrame中哪些位置是非空的。df.notna()会返回一个布尔型的DataFrame,其中True表示非空,False表示空(NaN)。

# 步骤1: 获取非空值的布尔DataFrame并转换为NumPy数组
notna_df = df.notna()
print("\ndf.notna()结果:")
print(notna_df)

notna_array = notna_df.to_numpy()
print("\n转换为NumPy数组:")
print(notna_array)

接下来,使用NumPy的argmax函数。argmax(axis=1)会沿着每行(axis=1)查找第一个True值(即第一个非空值)的索引。如果一行中所有值都为False,argmax会返回0(即该行的第一个列索引),这在我们的场景中是可接受的,因为它会按照我们定义的优先级(例如,A优先于B)选择。

科学计算器在线使用工具代码
科学计算器在线使用工具代码

html5 css3制作在线科学计算器ui布局,3D计算器面板,加减乘除数字计算器工具特效。

下载
# 步骤2: 找出每行第一个非空值的列索引
idx = notna_array.argmax(axis=1)
print("\n每行第一个非空值的列索引 (idx):")
print(idx)

此时,idx数组 [0 0 1] 表示:

  • 第0行:第一个非空值在索引0(即'A'列)。
  • 第1行:第一个非空值在索引0(即'A'列)。
  • 第2行:第一个非空值在索引1(即'B'列)。

2. 提取对应的值 (val)

有了每行第一个非空值的列索引idx,我们可以使用NumPy的“花式索引”(fancy indexing)来高效地从原始DataFrame的NumPy表示中提取对应的值。

# 步骤3: 提取对应的值
df_numpy = df.to_numpy()
val = df_numpy[(df.index, idx)] # df.index提供行索引,idx提供列索引
print("\n提取的val值:")
print(val)

df.to_numpy()[(df.index, idx)] 的工作原理是:df.index 提供了所有行的索引(0, 1, 2),而 idx 提供了每行对应的列索引(0, 0, 1)。NumPy会根据这些配对的索引,从df_numpy中选择出对应的元素。

3. 提取对应的来源列名 (val_source)

同样,利用idx数组,我们可以从DataFrame的列名列表中直接获取对应的列名。

# 步骤4: 提取对应的来源列名
val_source = df.columns[idx]
print("\n提取的val_source列名:")
print(val_source)

df.columns 返回一个包含所有列名的索引对象,通过df.columns[idx],我们可以根据idx中的列索引,批量获取对应的列名。

4. 将结果添加到原始DataFrame

最后,将计算出的val和val_source添加到原始DataFrame中:

df['val'] = val
df['val_source'] = val_source

print("\n最终DataFrame:")
print(df)

完整示例代码

将上述步骤整合,形成完整的解决方案:

import pandas as pd
import numpy as np

# 原始DataFrame
df = pd.DataFrame({
    'A': [1.0, 2.0, np.nan],
    'B': [4, 5, 6]
})

print("原始DataFrame:")
print(df)

# 确定每行第一个非空值的列索引
# df.notna() -> 布尔型DataFrame
# .to_numpy() -> 转换为NumPy数组
# .argmax(axis=1) -> 找出每行第一个True(非空)的索引
idx = df.notna().to_numpy().argmax(axis=1)

# 提取对应的值
# df.to_numpy() -> 原始DataFrame的NumPy表示
# (df.index, idx) -> 使用花式索引,根据行索引和计算出的列索引提取值
df['val'] = df.to_numpy()[(df.index, idx)]

# 提取对应的来源列名
# df.columns -> DataFrame的列名列表
# df.columns[idx] -> 根据idx中的列索引获取对应的列名
df['val_source'] = df.columns[idx]

print("\n转换后的DataFrame:")
print(df)

优势与注意事项

  • 简洁高效: 相比于多次调用np.select,此方法代码量更少,逻辑更集中,且利用了NumPy的向量化操作,性能优越,尤其适用于大型数据集。
  • 灵活性: 这种方法能够灵活地处理多列选择,并同时获取值和其来源信息。
  • 优先级处理: argmax默认返回第一个最大值的索引,这天然地符合了“优先选择第一个非空列”的需求。
  • 适用场景: 主要适用于需要从一组列中,按照从左到右的优先级,选择第一个非空值及其来源的场景。如果需要更复杂的条件逻辑(例如,基于多个列的组合条件),可能仍需结合其他Pandas或NumPy功能。
  • 全NaN行处理: 如果某一行所有列均为NaN,argmax会返回0(即第一列的索引)。在这种情况下,val将是NaN,val_source将是第一列的列名。这通常是可接受的行为,但如果需要特殊处理全NaN行,可能需要额外的检查。

总结

通过结合Pandas的布尔索引和NumPy的argmax函数,我们能够以一种优雅且高效的方式,解决从DataFrame多列中条件性地提取值并记录其来源的问题。这种方法不仅提升了代码的可读性和简洁性,也充分利用了底层库的性能优势,是处理此类数据转换任务的推荐实践。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

相关专题

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

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

320

2025.12.04

Python 数据清洗与预处理实战
Python 数据清洗与预处理实战

本专题系统讲解 Python 在数据清洗与预处理中的核心技术,包括使用 Pandas 进行缺失值处理、异常值检测、数据格式化、特征工程与数据转换,结合 NumPy 高效处理大规模数据。通过实战案例,帮助学习者掌握 如何处理混乱、不完整数据,为后续数据分析与机器学习模型训练打下坚实基础。

252

2026.01.31

Python数据分析与Pandas高级实战
Python数据分析与Pandas高级实战

本专题围绕 Python 数据分析展开,系统讲解 Pandas 的高级用法,包括数据清洗、透视表、时间序列分析以及多表合并与分组操作。通过实战案例,帮助开发者掌握高效处理与分析数据的方法,提高数据处理效率与分析能力。

511

2026.04.13

Revel框架模板渲染与表单验证
Revel框架模板渲染与表单验证

本专题围绕Revel框架视图层开发,介绍模板语法、变量输出、布局复用、表单提交、参数绑定与验证规则,帮助开发者完成安全规范的页面交互。

0

2026.10.16

Revel框架MVC路由与控制器
Revel框架MVC路由与控制器

本专题聚焦Revel框架MVC核心机制,讲解路由定义、控制器Action、参数绑定、请求响应和反向路由,并结合常见场景梳理接口请求处理流程。

0

2026.10.16

Revel框架入门与安装配置
Revel框架入门与安装配置

本专题从Revel框架环境搭建讲起,系统介绍命令行工具安装、项目创建、目录结构、配置文件及热代码重载,帮助开发者快速完成首个Go Web应用。

0

2026.10.16

Linux 新手先学哪些命令
Linux 新手先学哪些命令

Linux新手命令专题汇集终端基础、文件目录操作、文本查看、软件安装和权限管理等入门文章,帮助按实际任务练习常用命令并建立命令行操作习惯。

0

2026.10.15

MySQL 忘记密码怎么办
MySQL 忘记密码怎么办

MySQL忘记密码专题汇集不同版本与系统下的root密码重置方法,覆盖MySQL 5.7、8.0、Mac、Linux及本地集成环境,并提示恢复权限与重新登录的检查步骤。

0

2026.10.15

Vue.js 中 ref 和 reactive 的区别
Vue.js 中 ref 和 reactive 的区别

Vue.js中ref和reactive的区别专题汇集两种响应式API的定义、访问方式、对象解构、侦听与性能取舍等文章,帮助结合实际状态类型选择合适写法。

0

2026.10.15

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
JDK 27官方文档
JDK 27官方文档

共0课时 | 0人学习

LLVM入门手册
LLVM入门手册

共0课时 | 0人学习

Buffalo框架快速入门指南
Buffalo框架快速入门指南

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn