获取每行的第一个非空值

发布于 2021-01-29 14:56:57

我有一个示例数据框显示如下。对于每一行,我想先检查c1,如果它不为null,则检查c2。通过这种方式,找到第一个非空列并将该值存储到列结果中。

ID  c1  c2  c3  c4  result
1   a   b           a
2       cc  dd      cc
3           ee  ff  ee
4               gg  gg

我现在正在使用这种方式。但是我想知道是否有更好的方法。(列名没有任何模式,这只是示例)

df["result"] = np.where(df["c1"].notnull(), df["c1"], None)
df["result"] = np.where(df["result"].notnull(), df["result"], df["c2"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c3"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c4"])
df["result"] = np.where(df["result"].notnull(), df["result"], "unknown)

当有很多列时,此方法看起来不好。

关注者
0
被浏览
95
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    首先使用回填NaNs,然后通过iloc以下方式选择第一列:

    df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')
    

    要么:

    df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')
    

    print (df)
       ID   c1   c2  c3   c4 result
    0   1    a    b   a  NaN      a
    1   2  NaN   cc  dd   cc     cc
    2   3  NaN   ee  ff   ee     ee
    3   4  NaN  NaN  gg   gg     gg
    

    性能

    df = pd.concat([df] * 1000, ignore_index=True)
    
    
    In [220]: %timeit df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')
    100 loops, best of 3: 2.78 ms per loop
    
    In [221]: %timeit df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')
    100 loops, best of 3: 2.7 ms per loop
    
    #jpp solution
    In [222]: %%timeit
         ...: cols = df.iloc[:, 1:].T.apply(pd.Series.first_valid_index)
         ...: 
         ...: df['result'] = [df.loc[i, cols[i]] for i in range(len(df.index))]
         ...: 
    1 loop, best of 3: 180 ms per loop
    
    #cᴏʟᴅsᴘᴇᴇᴅ'  s solution
    In [223]: %timeit df['result'] = df.stack().groupby(level=0).first()
    1 loop, best of 3: 606 ms per loop
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看