Améliorez la vitesse de filtrage des trames de données Pandas

9

J'ai un ensemble de données avec 19 colonnes et environ 250k lignes. J'ai travaillé avec de plus grands ensembles de données, mais cette fois, les Pandas ont décidé de jouer avec mes nerfs.

J'ai essayé de diviser le jeu de données d'origine en 3 sous-cadres de données en fonction de quelques règles simples. Cependant, l'exécution du code prend beaucoup de temps. Environ 15-20 secondes juste pour le filtrage.

Une autre façon d'améliorer les performances du code?

import pandas as pd

#read dataset
df = pd.read_csv('myData.csv')

#create a dataframe with col1 10 and col2 <= 15
df1 = df[(df.col1 == 10) & (df.col2 <= 15)]
df = df[~df.isin(df1)].dropna()

#create a dataframe with col3 7 and col4 >= 4
df2 = df[(df.col3 == 7) & (df.col4 >= 4)]
df = df[~df.isin(df2)].dropna()

Au final, j'ai les df1, df2, dfdataframes avec les données filtrées.

Tasos
la source

Réponses:

15

Le concept à comprendre est que le conditionnel est en fait un vecteur. Ainsi, vous pouvez simplement définir les conditions, puis les combiner logiquement, comme:

condition1 = (df.col1 == 10) & (df.col2 <= 15)
condition2 = (df.col3 == 7) & (df.col4 >= 4)

# at this point, condition1 and condition2 are vectors of bools

df1 = df[condition1]
df2 = df[condition2 & ~condition1]
df = df[~ (condition1 | condition2)]

Ce sera beaucoup plus rapide car il n'évalue le conditionnel qu'une seule fois. Il les utilise ensuite pour effectuer une recherche indexée afin de créer les nouveaux cadres de données plus petits.

Stephen Rauch
la source
En cas de présence de None ou NaN, il suffit de prendre garde que la logique booléenne peut ne pas fonctionner sur eux.
kawingkelvin
5

Avez-vous chronométré la ligne de votre code qui prend le plus de temps? Je soupçonne que la ligne df = df[~df.isin(df1)].dropna()prendrait beaucoup de temps. Serait-il plus rapide si vous utilisez simplement la négation de la condition que vous avez appliquée pour obtenir df1, lorsque vous souhaitez filtrer les lignes df1de df?

Autrement dit, utilisez df = df[(df.col1 != 10) | (df.col2 > 15)].

Albert
la source
+1 pour recommander le chronométrage de chaque ligne
kbrose