将函数应用于 pandas 数据框中的所有列时出现意外行为

Chr*_*ris 7 python pandas

我无法理解为什么调用 pandas 的 dataframe.apply 方法没有返回预期结果。有人可以解释为什么下面显示的第一个 apply 调用没有返回预期结果,而第二个调用却返回预期结果吗?

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "x": [1, 2, np.nan],
    "y": ["hi", "there", np.nan]
})
print(df)
#>      x      y
#> 0  1.0     hi
#> 1  2.0  there
#> 2  NaN    NaN
print(df.dtypes)
#> x    float64
#> y     object
#> dtype: object

# why would something like this not return the expected result (which should
# be TRUE, FALSE):
print(df.apply(lambda x: np.issubdtype(x, np.number)))
#> x    False
#> y    False
#> dtype: bool

# but something like this returns the expected result (i.e., median imputation
# is used if the series is a number, otherwise NULLs are replaced with "MISSING"):
def replace_nulls(s):
    is_numeric = np.issubdtype(s, np.number)
    missing_value = s.median() if is_numeric else "MISSING"
    return np.where(s.isnull(), missing_value, s)

print(df.apply(replace_nulls))
#>      x        y
#> 0  1.0       hi
#> 1  2.0    there
#> 2  1.5  MISSING
Run Code Online (Sandbox Code Playgroud)

由reprexpy 包于 2019-10-03 创建

Ser*_*nes 0

这种混乱源于对传递给函数 in 的内容DataFrame.apply以及如何np.issubdtype使用的误解。

  • DataFrame.apply将每列作为 pandas Series 传递给函数lambda,而不是dtype直接传递列的。
  • np.issubdtype需要两个参数:adtype和要检查的类型或类型元组。

但是,当您将 Series (即x)传递给时np.issubdtype,它不是正确的用法,因为np.issubdtype它被设计为与 一起使用dtypes,而不是直接与 Series 对象一起使用。这就是为什么它对两列都返回 False。

你应该这样做

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "x": [1, 2, np.nan],
    "y": ["hi", "there", np.nan]
})
print(df.apply(lambda x: np.issubdtype(x, np.number)))
Run Code Online (Sandbox Code Playgroud)

这使

x     True
y    False
dtype: bool
Run Code Online (Sandbox Code Playgroud)

这意味着在第一种情况下使用事物的正确方法是:

print(df.apply(lambda x: np.issubdtype(x.dtype, np.number)))
Run Code Online (Sandbox Code Playgroud)

这给出了你上面的内容。

这实际上就是您在第二种情况下所做的,将其用作

def replace_nulls(s):
    is_numeric = np.issubdtype(s.dtype, np.number)  # Correctly checks the dtype of the Series
    missing_value = s.median() if is_numeric else "MISSING"
    return np.where(s.isnull(), missing_value, s)
Run Code Online (Sandbox Code Playgroud)