J'ai un dataframe comme celui-ci:
sort_idx = df1['col1'].apply(np.argsort).values
for rowidxval, (index, row) in enumerate(df1.iterrows()):
df1['col1'][index] = df1['col1'][index][sort_idx[rowidxval]]
df1['col2'][index] = df1['col2'][index][sort_idx[rowidxval]]
Je veux trier les valeurs des tableaux de la colonne 2 en fonction des valeurs des tableaux de la colonne 1.
Voici ma solution:
df1= pd.DataFrame({
'col1': [np.asarray([1,4,3,2]), np.asarray([9,10,7,5]), np.asarray([100,120,10,22])],
'col2': [np.asarray([0,1,4,5]), np.asarray([100,101,102,103]), np.asarray([10,11,12,13])]
})
df1
col1 col2
0 [1, 4, 3, 2] [0, 1, 4, 5]
1 [9, 10, 7, 5] [100, 101, 102, 103]
2 [100, 120, 10, 22] [10, 11, 12, 13]
Existe-t-il une manière élégante et pythonique de le faire au lieu de trier par force brute les données par ligne? Que faire si je souhaite trier à nouveau plusieurs colonnes en fonction des valeurs de la colonne 1?
3 Réponses :
Les listes en colonnes ne sont jamais recommandées (les dtypes mixtes et les dtypes mutables introduisent des goulots d'étranglement et une réduction des performances dans le code), mais vous pouvez le rendre aussi rapide que possible en utilisant une compréhension de liste:
df['col2'] = [y[x.argsort()] for x, y in zip(df.col1, df.col2)]
df
col1 col2
0 [1, 4, 3, 2] [0, 5, 4, 1]
1 [9, 10, 7, 5] [103, 102, 100, 101]
2 [100, 120, 10, 22] [12, 13, 10, 11]
S'ils sont tous les deux des tableaux, la solution simplifie:
df['col2'] = [np.array(y)[np.argsort(x)] for x, y in zip(df.col1, df.col2)]
df
col1 col2
0 [1, 4, 3, 2] [0, 5, 4, 1]
1 [9, 10, 7, 5] [103, 102, 100, 101]
2 [100, 120, 10, 22] [12, 13, 10, 11]
Pour plus d'informations sur les problèmes liés aux performances, consultez la section "Dtypes mixtes" dans Pour les boucles avec des pandas - Quand dois-je m'en soucier? .
Essayez d'éviter d'utiliser des tableaux NumPy dans des séries. Une telle structure de données ne supportera pas les calculs vectorisés. Puisque dans ce cas tous vos tableaux ont la même taille, vous pouvez facilement les diviser en plusieurs colonnes:
# STEP 1: split NumPy arrays into separate columns
col1 = pd.DataFrame(df1.pop('col1').values.tolist()).add_prefix('col1_')
col2 = pd.DataFrame(df1.pop('col2').values.tolist()).add_prefix('col2_')
df1 = df1.join(pd.concat([col1, col2], axis=1))
# STEP 2: calculate indices for NumPy assignment
x_idx = np.arange(df1.shape[0])[:, None]
y_idx = df1.iloc[:, :4].values.argsort(1)
# STEP 3: assign via iloc
df1.iloc[:, 4:] = df1.iloc[:, 4:].values[x_idx, y_idx]
print(df1)
# col1_0 col1_1 col1_2 col1_3 col2_0 col2_1 col2_2 col2_3
# 0 1 4 3 2 0 5 4 1
# 1 9 10 7 5 103 102 100 101
# 2 100 120 10 22 12 13 10 11
Utilisation de la boucle for
[[z for _,z in sorted(zip(x,y))] for x, y in zip(df1.col1, df1.col2)] Out[250]: [[0, 5, 4, 1], [103, 102, 100, 101], [12, 13, 10, 11]] #df1.col2=[[z for _,z in sorted(zip(x,y))] for x, y in zip(df1.col1, df1.col2)]