Pandas列值比较与新列赋值问题:避免NaN及批量实现
问题背景
需要比较两列或多列的值,将较大值和较小值分别存入新列。尝试先复制两列到新列,再修改符合条件的行,但出现不符合条件的行被改为NaN的问题,需解决两个核心问题:
- 如何避免不符合条件的行变为NaN;
- 如何批量完成该操作。
原代码及问题现象
import pandas as pd a = [ {'a': 5, 'b': 10, 'c': 5}, {'a': 4, 'b': 0.5, 'c': 1}, {'a': 3.5, 'b': 15, 'c': 9}, {'a': 2.1, 'b': 5, 'c': 8}, {'a': 0.1, 'b': 1, 'c': 5}, ] df = pd.DataFrame(a) df.loc[:, ['Big', 'Small']] = df[['a', 'b']].values print(df.head()) df.loc[df['a'] < df['b'], ['Big', 'Small']] = df[['b', 'a']] print(df.head())
原输出结果:
初始状态:
a b c Big Small
0 5.0 10.0 5 5.0 10.0
1 4.0 0.5 1 4.0 0.5
2 3.5 15.0 9 3.5 15.0
3 2.1 5.0 8 2.1 5.0
4 0.1 1.0 5 0.1 1.0修改后异常结果:
a b c Big Small
0 5.0 10.0 5 NaN NaN
1 4.0 0.5 1 4.0 0.5
2 3.5 15.0 9 NaN NaN
3 2.1 5.0 8 NaN NaN
4 0.1 1.0 5 NaN NaN
期望结果:
a b c Big Small0 5.0 10.0 5 10.0 5.0
1 4.0 0.5 1 4.0 0.5
2 3.5 15.0 9 15.0 3.5
3 2.1 5.0 8 5.0 2.1
4 0.1 1.0 5 1.0 0.1
问题原因
出现NaN是因为赋值语句df.loc[df['a'] < df['b'], ['Big', 'Small']] = df[['b', 'a']]中,右侧的df[['b','a']]是全量数据,而左侧是筛选后的行索引,两者索引不匹配的位置会被自动填充为NaN。
解决方案
1. 避免NaN的两种方法
方法一:匹配筛选后的索引赋值
修改赋值语句,只取筛选后的行数据进行赋值:
df.loc[df['a'] < df['b'], ['Big', 'Small']] = df.loc[df['a'] < df['b'], ['b', 'a']].values
方法二:直接用内置函数生成最值列(推荐)
无需先复制再修改,直接调用Pandas的max和min函数,一行代码生成目标列:
df['Big'] = df[['a', 'b']].max(axis=1) df['Small'] = df[['a', 'b']].min(axis=1)
2. 批量处理多列的方法
批量处理多组两列组合
如果需要处理多组列对(比如同时处理(a,b)、(c,a)),可以用循环批量生成对应最值列:
# 定义需要处理的列组,每组两个列 column_pairs = [('a', 'b'), ('c', 'a')] for col1, col2 in column_pairs: df[f'Big_{col1}_{col2}'] = df[[col1, col2]].max(axis=1) df[f'Small_{col1}_{col2}'] = df[[col1, col2]].min(axis=1)
处理任意多列的全局最值
如果要从多列中提取每行的全局最大/最小值,直接指定列范围即可:
# 从a、b、c三列中提取每行的最大最小值 df['Global_Big'] = df[['a', 'b', 'c']].max(axis=1) df['Global_Small'] = df[['a', 'b', 'c']].min(axis=1)
完整示例代码(推荐方法)
import pandas as pd a = [ {'a': 5, 'b': 10, 'c': 5}, {'a': 4, 'b': 0.5, 'c': 1}, {'a': 3.5, 'b': 15, 'c': 9}, {'a': 2.1, 'b': 5, 'c': 8}, {'a': 0.1, 'b': 1, 'c': 5}, ] df = pd.DataFrame(a) # 直接生成最值列 df['Big'] = df[['a', 'b']].max(axis=1) df['Small'] = df[['a', 'b']].min(axis=1) print(df.head())
输出结果:
a b c Big Small0 5.0 10.0 5 10.0 5.0
1 4.0 0.5 1 4.0 0.5
2 3.5 15.0 9 15.0 3.5
3 2.1 5.0 8 5.0 2.1
4 0.1 1.0 5 1.0 0.1
内容的提问来源于stack exchange,提问作者white.seolpyo.com

