J'ai un df qui contient assez similaire à ci-dessous. il comporte de nombreuses colonnes et certaines d'entre elles contiennent NaN. Je veux obtenir les n derniers éléments de chaque ligne à l'exclusion de NaN. Où n représente 3 ici.
Entrée:
df=pd.read_csv('s1.csv')#code to reproduce input
Sortie:
df['res1']=df.apply(lambda x:x.dropna().values.tolist()[len(x.dropna().values.tolist())-4:len(x.dropna().values.tolist())-1],axis=1)
Jusqu'à présent, j'obtiens la solution en utilisant le code ci-dessous. p >
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]
Ma solution semble très inefficace, première chose que j'utilise lambda qui rend mes performances de code trop faibles, et répète la même méthode pour obtenir l'index.
J'espère obtenir une solution de performance claire pour ce problème.
Le fichier Dataframe d'entrée est ici
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
4 Réponses :
Utilisation de melt avec 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]
@MohamedThasinah ajouté
Solution si chaque ligne a plus de lignes non manquantes comme treshold:
utilisez numpy avec justify a > fonction:
#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]
Sinon, besoin de boucles:
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]
Utilisation de apply + index booléen :
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]
Une manière rapide et sale:
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]
Sortie:
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)
Pouvez-vous fournir du code pour reproduire votre dataframe?
@MohitMotwani - ajouté