【问题标题】:Get the second to last column per row that isn't null获取每行不为空的倒数第二列
【发布时间】:2021-01-19 07:03:29
【问题描述】:

我正在尝试获取每行倒数第二个非空列,其中空值可以在任何列中。由于 null 可以在任何地方,因此此类解决方案不起作用:Pandas select the second to last column which is also not nan

不是理想的解决方案: 我能够用下面的代码解决它,但必须有一种更简洁的方法来编写它。任何反馈将不胜感激。

data = [[1, 10, np.nan, np.nan], [2, 15, 13, np.nan], [9, 14, np.nan, np.nan]] 
df = pd.DataFrame(data, columns = ['a', 'b', 'c', 'd']) 

df['count_nulls'] = len(df.columns) - df.apply(lambda x: x.count(), axis=1)
df['count_nonnull'] = df.apply(lambda x: x.count(), axis=1)-1
df['new_index'] = np.where(df['count_nonnull']==1, 1, 
                             np.where(df['count_nonnull']==0,0, df['count_nonnull'] - 1))
df['value'] = df.values[np.arange(len(df)), df['new_index']-1]
df

【问题讨论】:

    标签: python pandas indexing


    【解决方案1】:

    您可以检查 notna 并在 axis=1 上执行反向 cumsum ,然后获取返回 2 的第一列。并使用 df.lookup 获取其值:

    u = df.notna().iloc[:,::-1].cumsum(axis=1)
    df['value'] = df.lookup(df.index,u.eq(2).dot(u.columns+',').str.split(',').str[0])
    

    print(df)
    
       a   b     c   d  value
    0  1  10   NaN NaN      1
    1  2  15  13.0 NaN     15
    2  9  14   NaN NaN      9
    

    由于lookup 已弃用,因此可以使用以下 cmets:

    u = df.notna().iloc[:,::-1].cumsum(axis=1)
    v = u.eq(2).dot(u.columns+',').str.split(',').str[0]
    df['value'] = df.stack().loc[pd.MultiIndex.from_arrays((v.index,v))].to_numpy()
    

    其他部分不用apply就可以解决,或者嵌套np.where

    df.assign(
        count_nulls=df.isna().sum(1),
        count_non_null=df.notna().sum(1),
        new_index=lambda df: np.select(
            [df.count_non_null == 1, df.count_non_null == 0], 
             [1, 0], 
             df.count_non_null - 1))
    

    【讨论】:

    • 我猜这不是 pandas 1.2 版;查找似乎是deprecated
    • @Christopher 不知道弃用,编辑了我的答案。
    • 别担心,@anky。已经给了我+1。如果您不介意,我会为您的其他答案添加一个额外的解决方案。
    • @sammywemmy 绝对不介意 :-)
    【解决方案2】:

    您可以使用pandas.DataFrame.applypandas.Series.shift

    df.apply(lambda x: x.shift(x.isnull().sum())[-2], axis = 1)
    #0     1.0
    #1    15.0
    #2     9.0
    

    这个想法是将行移动“NaNs”次,因此倒数第二个不是NaN 将始终位于倒数第二个位置。

    【讨论】:

    • 如果您添加更多列,则会出现问题
    • @Christopher 在左边还是在右边?有或没有 nan 值?
    • @Christopher 您可以将[2] 更改为[-2] 以获得一般情况。我已经编辑过了
    • 关键是它需要是动态的。这并不能解决问题。
    • @Christopher 我不明白,你能给我举个例子吗?
    【解决方案3】:

    您可以通过pandas.DataFrame.applypandas.DataFrame.dropna 访问倒数第二个元素。

    >>> df.apply(lambda x:x.dropna().iloc[-2], axis=1)
    0     1.0
    1    15.0
    2     9.0
    

    【讨论】:

    • 如果一行中有更多的空值,或者一行中的所有空值都不起作用
    猜你喜欢
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 2012-09-20
    • 2023-03-03
    • 1970-01-01
    • 2017-10-27
    相关资源
    最近更新 更多