问题描述
例如:
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值,实际上是该列中的最大值。
1楼
选项A):只要groupby
与first
(可能不是100% )
df.groupby([1]*len(df)).first()==df.max()
Out[89]:
0 1
1 False True
选项b) : bfill
或者使用bfill
(通过列中的向后值填充任何NaN值,然后bfill
之后的第一行是第一个不是NaN
值)
df.bfill().iloc[0]==df.max()
Out[94]:
0 False
1 True
dtype: bool
选项c) : stack
df.stack().reset_index(level=1).drop_duplicates('level_1').set_index('level_1')[0]==df.max()
Out[102]:
level_1
0 False
1 True
dtype: bool
选项d): idxmax
与first_valid_index
df.idxmax()==df.apply(pd.Series.first_valid_index)
Out[105]:
0 False
1 True
dtype: bool
选项E)(从PIR): idxmax
与isna
df.notna().idxmax() == df.idxmax()
Out[107]:
0 False
1 True
dtype: bool
2楼
使用纯numpy
(我觉得这很快)
>>> np.isnan(df.values).argmin(axis=0) == df.fillna(-np.inf).values.argmax(axis=0)
array([False, True])
我们的想法是比较第一个非argmax
的指数是否也是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)
3楼
我们可以在这里使用numpy
的nanmax
来获得有效的解决方案:
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()
结果
4楼
您可以使用底层Numpy数组执行类似于Wens的回答:
>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0).values
array([False, True])
df.max(axis=0)
给出了列方式最大值。
左侧索引df.values
,这是一个2d数组,使其成为1d数组,并将其与每列的df.values
进行元素比较。
如果从右侧排除.values
,结果将只是一个Pandas系列:
>>> df.values[df.notnull().idxmax(), np.arange(df.shape[1])] == df.max(axis=0)
0 False
1 True
dtype: bool
5楼
在发布问题之后我想出了这个:
def nice_method_name_here(sr):
return sr[sr > 0][0] == np.max(sr)
print(df.apply(nice_method_name_here))
这似乎有效,但还不确定!