Python 如何查找:每列中的第一个非NaN值是否为数据帧中该列的最大值?

Python 如何查找:每列中的第一个非NaN值是否为数据帧中该列的最大值?,python,pandas,max,nan,Python,Pandas,Max,Nan,例如: 0 1 0 87.0 NaN 1 NaN 99.0 2 NaN NaN 3 NaN NaN 4 NaN 66.0 5 NaN NaN 6 NaN 77.0 7 NaN NaN 8 NaN NaN 9 88.0 NaN 我的预期输出是:[False,True],因为87是第一个!NaN值,但不是列0中的最大值99不过是第一个!NaN值,实际上是该列中的最大值。选项a):只需使用first执行grou

例如:

      0     1
0  87.0   NaN
1   NaN  99.0
2   NaN   NaN
3   NaN   NaN
4   NaN  66.0
5   NaN   NaN
6   NaN  77.0
7   NaN   NaN
8   NaN   NaN
9  88.0   NaN
我的预期输出是:
[False,True]
,因为87是第一个!NaN值,但不是列
0
中的最大值<代码>99不过是第一个!NaN值,实际上是该列中的最大值。

选项a):只需使用
first执行
groupby
(可能不是100%)

选项b)
b填充
或者使用
bfill
(用列中的向后值填充任何NaN值,
bfill
后的第一行是第一个非
NaN
值)

选项c)
堆栈
选项d)
idxmax
带有
第一个有效索引
选项e)(来自Pir)
idxmax
带有
isna

发布问题后,我提出了以下建议:

def nice_method_name_here(sr):
    return sr[sr > 0][0] == np.max(sr)

print(df.apply(nice_method_name_here))

这似乎有效,但还不确定

您可以对底层Numpy数组执行类似于Wens答案的操作:

>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0).values
array([False,  True])
df.max(轴=0)
给出了列方向的最大值

左侧索引了
df.values
,这是一个2d数组,使其成为1d数组,并将其按元素与每列的最大值进行比较

如果从右侧排除
.values
,结果将只是一个系列:

>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0)
0    False
1     True
dtype: bool

使用纯
numpy
(我认为这非常快)

其目的是比较第一个非nan的索引是否也是
argmax
的索引

时间安排

df = pd.concat([df]*1000).reset_index(drop=True) # setup

%timeit np.isnan(df.values).argmin(axis=0) == df.fillna(-np.inf).values.argmax(axis=0)
207 µs ± 8.83 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.groupby([1]*len(df)).first()==df.max()
9.78 ms ± 339 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.bfill().iloc[0]==df.max()
824 µs ± 47.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.stack().reset_index(level=1).drop_duplicates('level_1').set_index('level_1')[0]==df.max()
3.55 ms ± 249 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.idxmax()==df.apply(pd.Series.first_valid_index)
1.5 ms ± 25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0)
1.13 ms ± 14.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.values[(~np.isnan(df.values)).argmax(axis=0), np.arange(df.shape[1])] == df.max(axis=0).values
450 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

我们可以在这里使用
numpy
nanmax
来获得有效的解决方案:

a = df.values
np.nanmax(a, 0) == a[np.isnan(a).argmin(0), np.arange(a.shape[1])]

时间安排(此处提供了大量选项):


功能

设置


结果


当前,
groupby/first
返回每个组的第一个非NaN值。但我不确定我们是否应该依赖它,正如首席开发人员所说。选项4非常好,泰。我不认为df.notna().idxmax()==df.idxmax()相关:。很高兴看到这些答案的表现如何比较和衡量。(cc:unutbu)如果一列中的所有值都是NaN,这是否有效?这种情况下的预期行为是
False
def nice_method_name_here(sr):
    return sr[sr > 0][0] == np.max(sr)

print(df.apply(nice_method_name_here))
>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0).values
array([False,  True])
>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0)
0    False
1     True
dtype: bool
>>> np.isnan(df.values).argmin(axis=0) == df.fillna(-np.inf).values.argmax(axis=0)
array([False,  True])
df = pd.concat([df]*1000).reset_index(drop=True) # setup

%timeit np.isnan(df.values).argmin(axis=0) == df.fillna(-np.inf).values.argmax(axis=0)
207 µs ± 8.83 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.groupby([1]*len(df)).first()==df.max()
9.78 ms ± 339 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.bfill().iloc[0]==df.max()
824 µs ± 47.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.stack().reset_index(level=1).drop_duplicates('level_1').set_index('level_1')[0]==df.max()
3.55 ms ± 249 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.idxmax()==df.apply(pd.Series.first_valid_index)
1.5 ms ± 25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0)
1.13 ms ± 14.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.values[(~np.isnan(df.values)).argmax(axis=0), np.arange(df.shape[1])] == df.max(axis=0).values
450 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
a = df.values
np.nanmax(a, 0) == a[np.isnan(a).argmin(0), np.arange(a.shape[1])]
array([False,  True])
def chris(df):
    a = df.values
    return np.nanmax(a, 0) == a[np.isnan(a).argmin(0), np.arange(a.shape[1])]

def bradsolomon(df):
    df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0).values

def wen1(df):
    return df.groupby([1]*len(df)).first()==df.max()

def wen2(df):
    return df.bfill().iloc[0]==df.max()

def wen3(df):
    return df.idxmax()==df.apply(pd.Series.first_valid_index)

def rafaelc(df):
    return np.isnan(df.values).argmin(axis=0) == df.fillna(-np.inf).values.argmax(axis=0)

def pir(df):
    return df.notna().idxmax() == df.idxmax()
res = pd.DataFrame(
       index=['chris', 'bradsolomon', 'wen1', 'wen2', 'wen3', 'rafaelc', 'pir'],
       columns=[10, 20, 30, 100, 500, 1000],
       dtype=float
)

for f in res.index:
    for c in res.columns:
        a = np.random.rand(c, c)
        a[a > 0.4] = np.nan
        df = pd.DataFrame(a)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=50)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N");
ax.set_ylabel("time (relative)");

plt.show()