
本文详细介绍了如何在Pandas DataFrame中高效地创建新列,使其值根据特定条件和相邻单元格进行填充。核心方法是结合使用Series.where()进行条件性赋值,以及Series.bfill()或Series.ffill()来回填或前向填充缺失值,从而实现复杂的数据依赖逻辑,避免低效的循环操作。
场景描述与挑战
在数据处理中,我们经常需要根据一列的特定条件来创建或修改另一列。更复杂的情况是,当条件不满足时,新列的值需要依赖于其上方或下方的某个有效值。例如,给定一个包含“colonne 1”和“dimension 1”的dataframe,我们的目标是创建一个新列“new”,其规则如下:
如果“Dimension 1”列的值为“Organisation”,则“new”列的对应单元格取“Colonne 1”列的当前值。如果“Dimension 1”列的值不是“Organisation”,则“new”列的对应单元格需要从其下方最近的“Organisation”类型单元格中获取值,并向上填充。
传统的迭代方法(如使用for循环或apply函数)在处理大型DataFrame时效率低下。Pandas提供了更优化的矢量化操作来解决这类问题。
解决方案:结合where()与填充方法
Pandas中的Series.where()方法允许我们根据一个布尔条件选择性地替换Series中的值。当条件为False时,对应位置的值会被替换为NaN(默认),这为后续的填充操作创造了条件。接着,我们可以利用Series.bfill()(backward fill,向后填充)或Series.ffill()(forward fill,向前填充)来处理这些NaN值,实现复杂的依赖填充逻辑。
1. 使用 Series.where() 创建条件性缺失值
首先,我们使用where()方法来初步填充“new”列。如果“Dimension 1”是“Organisation”,则取“Colonne 1”的值;否则,该位置暂时留空(NaN)。
import pandas as pdimport io# 示例数据data = """ Colonne 1 Dimension 10 MTN_LI2 Indicator1 MTN_IRU Indicator2 MTN_ACE Indicator3 MTN_IME Indicator4 RIPP7 Organisation5 CA_SOT Indicator6 CA_OTI Indicator7 CNW00 Organisation8 BSNTF Organisation9 RIPNJ Organisation"""df = pd.read_csv(io.StringIO(data), sep=r's{2,}', engine='python', skipinitialspace=True)# 步骤1: 使用where()初步创建新列# 如果 df['Dimension 1'] 等于 'Organisation',则取 df['Colonne 1'] 的值,# 否则,该位置为 NaNdf['new_temp'] = df['Colonne 1'].where(df['Dimension 1'].eq('Organisation'))print("--- 步骤1结果 (初步填充,非Organisation为NaN) ---")print(df)
输出 df[‘new_temp’] 将会是:
--- 步骤1结果 (初步填充,非Organisation为NaN) --- Colonne 1 Dimension 1 new_temp0 MTN_LI2 Indicator NaN1 MTN_IRU Indicator NaN2 MTN_ACE Indicator NaN3 MTN_IME Indicator NaN4 RIPP7 Organisation RIPP75 CA_SOT Indicator NaN6 CA_OTI Indicator NaN7 CNW00 Organisation CNW008 BSNTF Organisation BSNTF9 RIPNJ Organisation RIPNJ
2. 使用 Series.bfill() 向后填充(向下查找,向上填充)
为了满足“如果不是’Organisation’,则取其下方最近的’Organisation’值”的需求,我们可以使用bfill()。bfill()会从Series的末尾开始,用遇到的第一个非NaN值填充其上方的所有NaN。
# 步骤2: 使用 bfill() 填充 NaNdf['new_bfill'] = df['new_temp'].bfill()print("n--- 步骤2结果 (使用 bfill() 填充) ---")print(df[['Colonne 1', 'Dimension 1', 'new_bfill']])
输出结果:
--- 步骤2结果 (使用 bfill() 填充) --- Colonne 1 Dimension 1 new_bfill0 MTN_LI2 Indicator RIPP71 MTN_IRU Indicator RIPP72 MTN_ACE Indicator RIPP73 MTN_IME Indicator RIPP74 RIPP7 Organisation RIPP75 CA_SOT Indicator CNW006 CA_OTI Indicator CNW007 CNW00 Organisation CNW008 BSNTF Organisation BSNTF9 RIPNJ Organisation RIPNJ
这完美地解决了最初的问题描述:“如果Dimension 1不等于Organisation,则该单元格获取其上方(按逻辑,是其下方最近的Organisation值向上填充)的单元格值。”
3. 使用 Series.ffill() 向前填充(向上查找,向下填充)
作为对比,如果需求是“如果不是’Organisation’,则取其上方最近的’Organisation’值”,那么可以使用ffill()。ffill()会从Series的开头开始,用遇到的第一个非NaN值填充其下方的所有NaN。
# 步骤3: 使用 ffill() 填充 NaN (作为对比,解决不同需求)df['new_ffill'] = df['new_temp'].ffill()print("n--- 步骤3结果 (使用 ffill() 填充) ---")print(df[['Colonne 1', 'Dimension 1', 'new_ffill']])
输出结果:
--- 步骤3结果 (使用 ffill() 填充) --- Colonne 1 Dimension 1 new_ffill0 MTN_LI2 Indicator NaN1 MTN_IRU Indicator NaN2 MTN_ACE Indicator NaN3 MTN_IME Indicator NaN4 RIPP7 Organisation RIPP75 CA_SOT Indicator RIPP76 CA_OTI Indicator RIPP77 CNW00 Organisation CNW008 BSNTF Organisation BSNTF9 RIPNJ Organisation RIPNJ
注意,ffill()在遇到第一个Organisation值(RIPP7)之前,无法填充前几个NaN,因为它们上方没有有效值。这说明了ffill()和bfill()在处理起始/结束NaN时的不同行为。
总结与注意事项
高效性: 结合Series.where()和Series.bfill()/Series.ffill()是Pandas中处理这类条件性填充问题的最佳实践。它们是高度优化的矢量化操作,远比基于Python循环的方案快。灵活性: 这种模式非常灵活,可以应用于各种复杂的条件填充场景。where()可以配合任何布尔条件,而bfill()和ffill()则提供了两种基本的填充方向。初始NaN处理:bfill()会填充其上方的NaN,如果Series的开头就是NaN且其下方没有非NaN值,则这些NaN会保留。ffill()会填充其下方的NaN,如果Series的末尾是NaN且其上方没有非NaN值,则这些NaN会保留。链式操作: 在实际应用中,为了代码简洁,通常会将where()和bfill()/ffill()链式调用,例如:df[‘new’] = df[‘Colonne 1’].where(df[‘Dimension 1’].eq(‘Organisation’)).bfill()。
通过掌握where()和填充方法,您可以高效且优雅地解决Pandas中涉及复杂条件和行间依赖的数据转换问题。
以上就是利用Pandas高效创建依赖上一个有效值的条件列的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1367008.html
微信扫一扫
支付宝扫一扫