如何将另一整列作为参数传递给 pandas fillna()

Posted

技术标签:

【中文标题】如何将另一整列作为参数传递给 pandas fillna()【英文标题】:How to pass another entire column as argument to pandas fillna() 【发布时间】:2015-08-02 03:35:15 【问题描述】:

我想使用fillna 方法用另一列中的值填充一列中的缺失值。

(我读到循环遍历每一行是非常糟糕的做法,最好一次完成所有事情,但我不知道如何使用fillna。)

之前的数据:

Day  Cat1  Cat2
1    cat   mouse
2    dog   elephant
3    cat   giraf
4    NaN   ant

之后的数据:

Day  Cat1  Cat2
1    cat   mouse
2    dog   elephant
3    cat   giraf
4    ant   ant

【问题讨论】:

【参考方案1】:

您可以将此列提供给fillna(参见docs),它将使用匹配索引上的这些值来填充:

In [17]: df['Cat1'].fillna(df['Cat2'])
Out[17]:
0    cat
1    dog
2    cat
3    ant
Name: Cat1, dtype: object

【讨论】:

不错!我不知道fillna 需要一个系列。 谢谢!我认为系列必须是 NA 值数量的确切大小。 它也适用于多列行的数据框。 fillna 的这个功能非常有用。 我不得不说我喜欢这个!【参考方案2】:

你可以的

df.Cat1 = np.where(df.Cat1.isnull(), df.Cat2, df.Cat1)

RHS 上的整体结构使用the ternary pattern from the pandas cookbook(无论如何都值得阅读)。这是a? b: c 的矢量版本。

【讨论】:

不是我用来解决这个问题的解决方案,而是非常有趣的模式!谢谢! 有没有办法将它用于多个列?例如如果这个df有cat1、cat2、cat3、cat4、cat5,假设cat5是空的。有没有办法用 cat1 的值填充 cat5,如果 cat1 为空则 cat2,如果 cat2 为空则 cat3 等? @user8322222 我肯定迟到了,但是如果有人有这个问题,你可以做嵌套 np.where,就像你在 excel cell = np.where(cond, val_true, np.where (条件,val_true,val_false),)。 您要提到的是,这只是重新定义了内置的 pandas pd.DataFrame.fillna()。而且我怀疑极端情况下的行为可能会有所不同,例如对于来自不同数据帧的不匹配系列长度:dfA['Cat1'], dfB['Cat2']【参考方案3】:

只需使用value 参数而不是method

In [20]: df
Out[20]:
  Cat1      Cat2  Day
0  cat     mouse    1
1  dog  elephant    2
2  cat     giraf    3
3  NaN       ant    4

In [21]: df.Cat1 = df.Cat1.fillna(value=df.Cat2)

In [22]: df
Out[22]:
  Cat1      Cat2  Day
0  cat     mouse    1
1  dog  elephant    2
2  cat     giraf    3
3  ant       ant    4

【讨论】:

感谢您的回答!使用价值而不是joris描述的方法有什么变化? @xav value 是第一个参数,所以 joris 实际上在做同样的事情。正如他所说,请参阅docs。 是的,文档字符串有点误导,因为method 列在最前面。【参考方案4】:

pandas.DataFrame.combine_first 也可以。

(注意:由于“结果索引列将是各个索引和列的并集”,请检查索引和列是否匹配。)

import numpy as np
import pandas as pd
df = pd.DataFrame([["1","cat","mouse"],
    ["2","dog","elephant"],
    ["3","cat","giraf"],
    ["4",np.nan,"ant"]],columns=["Day","Cat1","Cat2"])

In: df["Cat1"].combine_first(df["Cat2"])
Out: 
0    cat
1    dog
2    cat
3    ant
Name: Cat1, dtype: object

与其他答案比较:

%timeit df["Cat1"].combine_first(df["Cat2"])
181 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit df['Cat1'].fillna(df['Cat2'])
253 µs ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit np.where(df.Cat1.isnull(), df.Cat2, df.Cat1)
88.1 µs ± 793 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

下面这个方法我没用过:

def is_missing(Cat1,Cat2):    
    if np.isnan(Cat1):        
        return Cat2
    else:
        return Cat1

df['Cat1'] = df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)

因为它会引发异常:

TypeError: ("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''", 'occurred at index 0')

这意味着 np.isnan 可以应用于原生 dtype 的 NumPy 数组(例如 np.float64), 但在应用于 object 数组时会引发 TypeError。

所以我修改了方法:

def is_missing(Cat1,Cat2):    
    if pd.isnull(Cat1):        
        return Cat2
    else:
        return Cat1

%timeit df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)
701 µs ± 7.38 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

【参考方案5】:

这里有一个更通用的方法(fillna 方法可能更好)

def is_missing(Cat1,Cat2):    
    if np.isnan(Cat1):        
        return Cat2
    else:
        return Cat1

df['Cat1'] = df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)

【讨论】:

【参考方案6】:

我知道这是一个老问题,但我最近需要做类似的事情。我能够使用以下内容:

df = pd.DataFrame([["1","cat","mouse"],
    ["2","dog","elephant"],
    ["3","cat","giraf"],
    ["4",np.nan,"ant"]],columns=["Day","Cat1","Cat2"])

print(df)

  Day Cat1      Cat2
0   1  cat     mouse
1   2  dog  elephant
2   3  cat     giraf
3   4  NaN       ant

df1 = df.bfill(axis=1).iloc[:, 1]
df1 = df1.to_frame()
print(df1)

产量:

  Cat1
0  cat
1  dog
2  cat
3  ant

希望这对某人有帮助!

【讨论】:

以上是关于如何将另一整列作为参数传递给 pandas fillna()的主要内容,如果未能解决你的问题,请参考以下文章

如何将文件路径作为 bash 脚本中的参数传递给函数? [复制]

Pyspark 将函数作为参数传递给 UDF

Python:如何将 def 中的参数传递给 pandas loc 中的输入?

在Pandas中,我如何将一个函数应用到数据框的某一行,其中行中的每一项都应该作为参数传递给函数?

Python - 将数字作为参数传递给文件名

如何在 PySpark 中将多个参数传递给 Pandas UDF?