我有一个Pandas DataFrame:
import pandas as pd
df = pd.DataFrame([[0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0],
[1.0, 0.0, 1.0, 3.0, 1.0, 1.0, 7.0, 0.0],
[0.0, 0.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0]
]
, columns=['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])
A B C D E F G H
0 0.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0
1 1.0 0.0 1.0 3.0 1.0 1.0 7.0 0.0
2 0.0 0.0 13.0 14.0 15.0 16.0 17.0 18.0
我想要返回每行中第一个非零值的系列(不是列表)。这当前有效,但是lookup
会返回一个列表而不是一个系列(我知道我可以将列表转换为一个系列),但我假设有一个更好的方法:
first_nonzero_colnames = (df > 0).idxmax(axis=1, skipna=True)
df.lookup(first_nonzero_colnames.index, first_nonzero_colnames.values)
[ 2. 1. 13.]
我可以使用.apply
,但我想避免使用它。
答案 0 :(得分:8)
试试这个:
res = df[df != 0.0].bfill(axis=1)['A']
我正在做的是用nan
替换所有非零,然后从右边填充它们,这会强制第一列中的所有结果值成为第一个非零值这一行。
或更快的方式,如@piRSquared所建议的那样:
df.replace(0, np.nan).bfill(1).iloc[:, 0]
答案 1 :(得分:5)
这似乎有效:
df[df!=0].cumsum(axis=1).min(axis=1)
Out[74]:
0 2.0
1 1.0
2 13.0
dtype: float64
答案 2 :(得分:3)
@ acushner的答案更好。把它放在那里。
使用idxmax
和apply
m = (df != 0).idxmax(1)
df.T.apply(lambda x: x[m[x.name]])
0 2.0
1 1.0
2 13.0
dtype: float64
这也有效:
m = (df != 0).idxmax(1)
t = zip(m.index, m.values)
df.stack().loc[t].reset_index(1, drop=True)
答案 3 :(得分:2)
我不确定我会称之为“更好”。但它会在一个班轮中返回一个系列。
df.apply(lambda x: x[np.where(x > 0)[0][0]], axis=1)
>>>
0 2.0
1 1.0
2 13.0
dtype: float64
答案 4 :(得分:0)
使用.apply和.nonzero()
这是一种非常快捷的方式 df2.apply(lambda x: x.iloc[x.nonzero()[0][0]], axis=1)
>>>
0 2.0
1 1.0
2 13.0
dtype: float64
性能:
%%timeit
df2.apply(lambda x: x.iloc[x.nonzero()[0][0]], axis=1)
>>>
190 µs ± 8.18 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)