这个问题是由我不久前给出的答案引发的。
假设我有一个像这样的数据框
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
有时被忽略,有时则不然?
原因是
max
的工作原理是将第一个值作为“迄今为止看到的最大值”,然后检查其他值以查看它是否大于迄今为止看到的最大值。但是 nan
的定义使得与它的比较总是返回 False --- 也就是说,nan > 1
是 false,但 1 > nan
也是 false。
因此,如果您以
nan
作为数组中的第一个值,则后续的每次比较都会检查是否为 some_other_value > nan
。这始终是错误的,因此 nan
将保留其“迄今为止看到的最大值”的位置。另一方面,如果 nan
不是第一个值,那么当达到它时,比较 nan > max_so_far
将再次为 false。但在这种情况下,这意味着当前的“迄今为止看到的最大值”(不是nan
)将仍然是迄今为止看到的最大值,因此 nan 将始终被丢弃。
在第一种情况下,您使用 numpy
max
函数,它知道如何处理 numpy.nan
。
在第二种情况下,您使用的是 python 的内置
max
函数。这个不知道怎么处理numpy.nan
。据推测,这种效果是由于 (>, <, == etc.) of numpy.nan
与浮点数的任何比较都会导致 False。实现 max
的一个明显方法是迭代可迭代对象(本例中的行)并检查每个值是否大于前一个,如果大于,则将其存储为最大值。由于当其中一个比较值是numpy.nan
时,这种大于比较总是False,所以记录的最大值是你想要的数字还是numpy.nan
取决于完全取决于第一个值是否为numpy.nan
。
这是由于列表中元素的顺序造成的。首先,如果你输入
max([1, 2, np.nan])
结果是
2
,而
max([np.nan, 2, 3])
给出
np.nan
。原因是 max
函数会逐一遍历列表中的值,并进行如下比较:
if a > b
现在,如果我们看看与
nan
进行比较时得到的结果,np.nan > 2
和 1 > np.nan
都给出 False
,因此在一种情况下,运行最大值被替换为 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
如果可能是inf问题,尝试更换它以及nan。
df[column] = df[column].replace([np.inf, -np.inf], 0.0)
df[column] = df[column].replace([np.nan, -np.nan], 0.0)
使用 numpy.nanmax(list) 会导致排除 NaN。