numpy 可以做到这一点。 argmax algorithm@piRSquared 提供。
A = df.values
idx = A.shape[1] - (~np.isnan(A))[:, ::-1].argmax(1) - 1
cols = df.columns[idx]
res = pd.DataFrame({'ID': df['ID'], 'col': cols,
'last': A[range(A.shape[0]), idx]})
# ID col last
# 0 1 c2 1.0
# 1 2 c3 1.0
# 2 3 c7 1.0
性能基准测试
import random
import pandas as pd
%timeit cs(df) # 10 loops, best of 3: 63.5 ms per loop
%timeit jp(df) # 100 loops, best of 3: 2.76 ms per loop
%timeit wen(df) # 10 loops, best of 3: 346 ms per loop
# create dataframe with randomised np.nan
df = pd.DataFrame(np.random.randint(0, 9, (1000, 1000)), dtype=float)
df = df.rename(columns={0: 'ID'})
ix = [(row, col) for row in range(df.shape[0]) for col in range(df.shape[1])]
for row, col in random.sample(ix, int(round(.1*len(ix)))):
df.iat[row, col] = np.nan
def jp(df):
A = df.values
idx = A.shape[1] - (~np.isnan(A))[:, ::-1].argmax(1) - 1
cols = df.columns[idx]
res = pd.DataFrame({'ID': df['ID'], 'col': cols,
'last': A[range(A.shape[0]), idx]})
return df
def wen(df):
s=df.apply(pd.Series.last_valid_index, 1)
df['Last']=df.lookup(s.index,s)
df['Col']=s
return df
def cs(df):
i = (~np.isnan(df.values)).cumsum(1).argmax(1) # pure numpy
df = pd.DataFrame({
'ID' : df.ID,
'Colname' : df.columns[i],
'lastValue' : df.values[np.arange(len(df)), i]
})
return df