【问题标题】:Getting last non na value across rows in a pandas dataframe在熊猫数据框中跨行获取最后一个非 na 值
【发布时间】:2017-03-27 18:42:46
【问题描述】:

我有一个形状为 (40,500) 的数据框。数据框中的每一行都有一些数值,直到某个可变列号 k,之后的所有条目都是 nan。

我正在尝试获取每行中最后一个非 nan 列的值。有没有办法在不遍历数据框的所有行的情况下做到这一点?

示例数据框:

2016-06-02 7.080 7.079 7.079 7.079 7.079 7.079   nan   nan   nan
2016-06-08 7.053 7.053 7.053 7.053 7.053 7.054   nan   nan   nan  
2016-06-09 7.061 7.061 7.060 7.060 7.060 7.060   nan   nan   nan   
2016-06-14   nan   nan   nan   nan   nan   nan   nan   nan   nan  
2016-06-15 7.066 7.066 7.066 7.066   nan   nan   nan   nan   nan  
2016-06-16 7.067 7.067 7.067 7.067 7.067 7.067 7.068 7.068   nan  
2016-06-21 7.053 7.053 7.052   nan   nan   nan   nan   nan   nan  
2016-06-22 7.049 7.049   nan   nan   nan   nan   nan   nan   nan  
2016-06-28 7.058 7.058 7.059 7.059 7.059 7.059 7.059 7.059 7.059  

请求输出

2016-06-02 7.079 
2016-06-08 7.054
2016-06-09 7.060
2016-06-14   nan 
2016-06-15 7.066
2016-06-16 7.068 
2016-06-21 7.052 
2016-06-22 7.049
2016-06-28 7.059  

【问题讨论】:

    标签: python pandas multidimensional-array dataframe na


    【解决方案1】:

    您需要带有自定义函数的last_valid_index,因为如果所有值都是NaN,它将返回KeyError

    def f(x):
        if x.last_valid_index() is None:
            return np.nan
        else:
            return x[x.last_valid_index()]
    
    df['status'] = df.apply(f, axis=1)
    print (df)
                    1      2      3      4      5      6      7      8      9  \
    0                                                                           
    2016-06-02  7.080  7.079  7.079  7.079  7.079  7.079    NaN    NaN    NaN   
    2016-06-08  7.053  7.053  7.053  7.053  7.053  7.054    NaN    NaN    NaN   
    2016-06-09  7.061  7.061  7.060  7.060  7.060  7.060    NaN    NaN    NaN   
    2016-06-14    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN   
    2016-06-15  7.066  7.066  7.066  7.066    NaN    NaN    NaN    NaN    NaN   
    2016-06-16  7.067  7.067  7.067  7.067  7.067  7.067  7.068  7.068    NaN   
    2016-06-21  7.053  7.053  7.052    NaN    NaN    NaN    NaN    NaN    NaN   
    2016-06-22  7.049  7.049    NaN    NaN    NaN    NaN    NaN    NaN    NaN   
    2016-06-28  7.058  7.058  7.059  7.059  7.059  7.059  7.059  7.059  7.059   
    
                status  
    0                   
    2016-06-02   7.079  
    2016-06-08   7.054  
    2016-06-09   7.060  
    2016-06-14     NaN  
    2016-06-15   7.066  
    2016-06-16   7.068  
    2016-06-21   7.052  
    2016-06-22   7.049  
    2016-06-28   7.059  
    

    替代解决方案 - fillna 使用方法 ffill 并通过 iloc 选择最后一列:

    df['status'] = df.ffill(axis=1).iloc[:, -1]
    print (df)
                status  
    0                   
    2016-06-02   7.079  
    2016-06-08   7.054  
    2016-06-09   7.060  
    2016-06-14     NaN  
    2016-06-15   7.066  
    2016-06-16   7.068  
    2016-06-21   7.052  
    2016-06-22   7.049  
    2016-06-28   7.059  
    

    【讨论】:

      【解决方案2】:

      使用agg('last')

      df.groupby(['status'] * df.shape[1], 1).agg('last')
      


      agg 内的

      'last' 产生组内的最后一个有效值。我传递了一个长度等于列数的列表。此列表的每个值都是“状态”。这意味着我按一组分组。结果是一个数据框,其中有一列名为“状态”

      【讨论】:

      • 谢谢,这解决了问题,但我只能接受一个答案。鉴于耶斯瑞尔的方法易于理解和直截了当,我接受他并支持你和他。谢谢 piRsquared!
      • 我认为这个解决方案比应用 lambda 更快。但是我无法将其应用于数据框的子集
      【解决方案3】:

      这是一个基于 NumPy 的解决方案 -

      In [113]: a
      Out[113]: 
      array([[ 17.,  53.,  nan,  63.,  66.,  nan,  nan,  nan,  nan,  nan],
             [ 54.,  96.,  71.,  20.,  70.,  58.,  91.,  nan,  nan,  nan],
             [ 58.,  26.,  72.,  93.,  58.,  29.,  44.,  28.,  36.,  88.],
             [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan],
             [ 94.,  23.,  nan,  nan,  92.,  81.,  40.,  30.,  84.,  nan]])
      
      In [114]: m = ~np.isnan(a)
      
      In [115]: a[np.arange(m.shape[0]), m.shape[1]-m[:,::-1].argmax(1)-1]
      Out[115]: array([ 66.,  91.,  88.,  nan,  84.])
      

      要将其移植到数据帧,首先我们可以将值提取为数组:a = df.values,最后制作输出数据帧:

      vals = a[np.arange(m.shape[0]), m.shape[1]-m[:,::-1].argmax(1)-1]
      df_out = pd.DataFrame(vals,index=df.index)
      

      【讨论】:

      • 谢谢,这完美解决了问题,但我只能接受一个答案。鉴于耶斯瑞尔的方法易于理解和直截了当,我接受他并支持你和他。谢谢迪瓦卡!
      猜你喜欢
      • 2019-04-07
      • 2021-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多