【问题标题】:How to get last n values in each row using pandas如何使用 pandas 获取每行中的最后 n 个值
【发布时间】:2019-01-11 05:55:16
【问题描述】:

我有一个 df,其中包含与下面非常相似的内容。它有很多列,其中一些包含 NaN。我想从每一行中获取最后 n 个元素,不包括 NaN。其中n在这里代表3。

输入:

   col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   

   col12  col13   I  
0    NaN    NaN  r1  
1    NaN    NaN  r2  
2    NaN    NaN  r3  
3  324.0  234.0  r4  
4    NaN    NaN  r5  
5    NaN    NaN  r6 

输出:

   col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   

   col12  col13   I                 res1  
0    NaN    NaN  r1  [23.0, 23.0, 123.0]  
1    NaN    NaN  r2   [12.0, 23.0, 23.0]  
2    NaN    NaN  r3    [23, 323.0, 12.0]  
3  324.0  234.0  r4  [2.0, 324.0, 234.0]  
4    NaN    NaN  r5   [34.0, 34.0, 34.0]  
5    NaN    NaN  r6     [45.0, 45.0, 45] 

到目前为止,我使用以下代码得到了解决方案。

df['res1']=df.apply(lambda x:x.dropna().values.tolist()[len(x.dropna().values.tolist())-4:len(x.dropna().values.tolist())-1],axis=1)

我的解决方案看起来非常无效,首先我使用 lambda,这会使我的代码性能降低,并重复相同的方法来获取索引。

我希望为这个问题得到明确的性能解决方案。

输入数据框文件为 here

df=pd.read_csv('s1.csv')#code to reproduce input

【问题讨论】:

  • 你能提供代码来重现你的数据框吗?
  • @MohitMotwani - 添加

标签: python pandas


【解决方案1】:

如果每行有更多的非缺失行,如阈值的解决方案:

将 numpy 与 justify 函数一起使用:

df['res1'] = justify(df.iloc[:, :-1].values, invalid_val=np.nan, side='right')[:, -3:].tolist()
print (df)
   col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   

   col12  col13   I                 res1  
0    NaN    NaN  r1  [23.0, 23.0, 123.0]  
1    NaN    NaN  r2   [12.0, 23.0, 23.0]  
2    NaN    NaN  r3  [23.0, 323.0, 12.0]  
3  324.0  234.0  r4  [2.0, 324.0, 234.0]  
4    NaN    NaN  r5   [34.0, 34.0, 34.0]  
5    NaN    NaN  r6   [45.0, 45.0, 45.0]

如果没有,需要循环:

#changed a bit https://stackoverflow.com/a/40835254
def loop_compr_based(a, last):
    mask = ~np.isnan(a)
    stop = mask.sum(1).cumsum()
    start = np.append(0,stop[:-1])
    am = a[mask].tolist()
    out = np.array([am[start[i]:stop[i]][-last:] for i  in range(len(start))])
    return out

df['res1'] = loop_compr_based(df.iloc[:, :-1].values, 5).tolist()
print (df)
   col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   

   col12  col13   I                                 res1  
0    NaN    NaN  r1      [23.0, 23.0, 23.0, 23.0, 123.0]  
1    NaN    NaN  r2             [45.0, 12.0, 23.0, 23.0]  
2    NaN    NaN  r3      [56.0, 34.0, 23.0, 323.0, 12.0]  
3  324.0  234.0  r4  [2343.0, 2344.0, 2.0, 324.0, 234.0]  
4    NaN    NaN  r5       [5.0, 675.0, 34.0, 34.0, 34.0]  
5    NaN    NaN  r6             [34.0, 45.0, 45.0, 45.0]  

【讨论】:

    【解决方案2】:

    meltgroupby 一起使用

    df['res1']=df.melt('I').dropna().groupby('I')['value'].apply(lambda x : x.tolist()[-3:]).tolist() 
    # melt the data , then drop nan , since you want the not nan values of last 3 , then we groupby slice the last three. 
    df
       col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
    0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
    1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
    2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
    3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
    4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
    5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   
       col12  col13   I                 res1  
    0    NaN    NaN  r1  [23.0, 23.0, 123.0]  
    1    NaN    NaN  r2   [12.0, 23.0, 23.0]  
    2    NaN    NaN  r3  [23.0, 323.0, 12.0]  
    3  324.0  234.0  r4  [2.0, 324.0, 234.0]  
    4    NaN    NaN  r5   [34.0, 34.0, 34.0]  
    5    NaN    NaN  r6   [45.0, 45.0, 45.0]  
    

    【讨论】:

    • @MohamedThasinah 添加了
    【解决方案3】:

    使用apply+boolean index

    df['res1'] = df.filter(like='col').apply(lambda x: x[x.notnull()].values[-3:].tolist(), 1)
    
    print(df)
       col1  col2  col3  col4   col5  col6    col7  col8   col9   col10  col11  \
    0   NaN   NaN  23.0    23   23.0   NaN    23.0  23.0  123.0     NaN    NaN   
    1   NaN   NaN   NaN    45   12.0  23.0    23.0   NaN    NaN     NaN    NaN   
    2  45.0  56.0  34.0    23  323.0  12.0     NaN   NaN    NaN     NaN    NaN   
    3   NaN   NaN  34.0    65    NaN  65.0  2343.0   NaN    NaN  2344.0    2.0   
    4   NaN   NaN   NaN     5  675.0  34.0    34.0  34.0    NaN     NaN    NaN   
    5  34.0  45.0  45.0    45    NaN   NaN     NaN   NaN    NaN     NaN    NaN   
    
       col12  col13   I                 res1  
    0    NaN    NaN  r1  [23.0, 23.0, 123.0]  
    1    NaN    NaN  r2   [12.0, 23.0, 23.0]  
    2    NaN    NaN  r3  [23.0, 323.0, 12.0]  
    3  324.0  234.0  r4  [2.0, 324.0, 234.0]  
    4    NaN    NaN  r5   [34.0, 34.0, 34.0]  
    5    NaN    NaN  r6   [45.0, 45.0, 45.0]  
    

    【讨论】:

      【解决方案4】:

      一种快速而肮脏的方式:

      import pandas as pd
      import numpy as np
      
      df = pd.DataFrame()
      df['A'] = [1,2,3]
      df['B'] = [2,np.nan,np.nan]
      df['C'] = [3,4,5]
      df['D'] = [4,5,np.nan]
      df['E'] = [np.nan,6,np.nan]
      res_list = []
      
      for i, row in df.iterrows():
          res_list.append([x for x in list(sorted(row)) if not np.isnan(x)][0:3])
      
      df['res'] = res_list
      print(df)
      

      输出:

         A    B  C    D    E              res
      0  1  2.0  3  4.0  NaN  [1.0, 2.0, 3.0]
      1  2  NaN  4  5.0  6.0  [2.0, 4.0, 5.0]
      2  3  NaN  5  NaN  NaN       [3.0, 5.0]
      

      【讨论】:

        猜你喜欢
        • 2013-01-17
        • 1970-01-01
        • 2017-04-19
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 2019-07-20
        • 1970-01-01
        • 2018-05-28
        相关资源
        最近更新 更多