为什么 max() 有时 return nan 有时会忽略它?

Why does max() sometimes return nan and sometimes ignores it?

这个问题的动机是我刚才给的

假设我有一个这样的数据框

import numpy as np
import pandas as pd

df = pd.DataFrame({'a': [1, 2, np.nan], 'b': [3, np.nan, 10], 'c':[np.nan, 5, 34]})

     a     b     c
0  1.0   3.0   NaN
1  2.0   NaN   5.0
2  NaN  10.0  34.0

我想用行的最大值替换 NaN

df.apply(lambda row: row.fillna(row.max()), axis=1)

这给了我想要的输出

      a     b     c
0   1.0   3.0   3.0
1   2.0   5.0   5.0
2  34.0  10.0  34.0

然而,当我使用

df.apply(lambda row: row.fillna(max(row)), axis=1)

出于某种原因,它仅在以下三种情况中的两种情况下被正确替换:

     a     b     c
0  1.0   3.0   3.0
1  2.0   5.0   5.0
2  NaN  10.0  34.0

确实,如果我手动检查

max(df.iloc[0, :])
max(df.iloc[1, :])
max(df.iloc[2, :])

然后打印

3.0
5.0
nan

做的时候

df.iloc[0, :].max()
df.iloc[1, :].max()
df.iloc[2, :].max()

它打印预期的

3.0
5.0
34.0

我的问题是为什么 max() 在三种情况中有一种失败,但在所有 3 种情况下都失败。为什么 NaN 有时被忽略,有时却没有?

在第一种情况下,您使用的是 numpy max 函数,它知道如何处理 numpy.nan

在第二种情况下,您使用的是 python 中的内置 max 函数。这个不知道怎么处理numpy.nan。据推测,这种效果是由于 numpy.nan 与浮点数的任何比较(>、<、== 等)都会导致 False。实现 max 的一种明显方法是迭代可迭代对象(在本例中为行)并检查每个值是否大于前一个值,如果是,则将其存储为最大值。由于当比较的值之一为 numpy.nan 时,此大于比较将始终为 False,因此记录的最大值是否为您想要的数字或 numpy.nan 完全取决于第一个值是否为 numpy.nan与否。

两者不同:max() vs df.max().

max(): python 内建函数,必须是非空可迭代对象。在这里检查: https://docs.python.org/2/library/functions.html#max

而pandas dataframe -- df.max(skipna=..),有一个参数叫skipna,默认值为True,表示排除NA/null的值.在这里检查: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.max.html

原因是 max 的工作原理是将第一个值作为 "max seen so far",然后检查其他值以查看它是否大于目前看到的最大值。但是 nan 被定义为与它的比较总是 return False --- 也就是说,nan > 1 是 false 但 1 > nan 也是 false。

所以如果你从nan开始作为数组中的第一个值,之后的每次比较都会检查是否some_other_value > nan。这将始终为 false,因此 nan 将保留其 "max seen so far" 的位置。另一方面,如果 nan 不是第一个值,那么当达到第一个值时,比较 nan > max_so_far 将再次为假。但在这种情况下,这意味着当前 "max seen so far"(不是 nan)将保持目前看到的最大值,因此 nan 将始终被丢弃。

这是由于列表中元素的排序。首先,如果您输入

max([1, 2, np.nan])

结果是2,而

max([np.nan, 2, 3])

给出np.nan。这样做的原因是 max 函数通过如下比较逐一遍历列表中的值:

if a > b

现在,如果我们看看与 nan 比较时得到的结果,np.nan > 21 > np.nan 都给出 False,所以在一种情况下 运行 maximum 替换为 nan 而在另一个则不是。