我有一个df,其中包含与以下内容非常相似的内容。它有很多列,其中一些包含NaN。我想从除了NaN的每一行中获取最后n个元素。其中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
答案 0 :(得分:4)
如果每一行都有更多非缺失行(如treshold),则该解决方案:
将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]
答案 1 :(得分:3)
将melt
与groupby
一起使用
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]
答案 2 :(得分: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]
答案 3 :(得分:1)
一种快速而肮脏的方式:
ResponseBaseModel.class
输出:
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)