Sélection / exclusion des ensembles de colonnes dans Pandas

Je voudrais créer des vues ou des dataframes à partir d’un dataframe existant en fonction des sélections de colonnes.

Par exemple, je voudrais créer un dataframe df2 à partir d’un dataframe df1 qui contient toutes les colonnes sauf deux. J’ai essayé de faire ce qui suit, mais cela n’a pas fonctionné:

import numpy as np import pandas as pd # Create a dataframe with columns A,B,C and D df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) # Try to create a second dataframe df2 from df with all columns except 'B' and D my_cols = set(df.columns) my_cols.remove('B').remove('D') # This returns an error ("unhashable type: set") df2 = df[my_cols] 

Qu’est-ce que je fais mal? Peut-être plus généralement, quels mécanismes Panda doit-il prendre en charge pour sélectionner et exclure des ensembles de colonnes arbitraires d’un cadre de données?

Vous pouvez soit supprimer les colonnes dont vous n’avez pas besoin, soit sélectionner celles dont vous avez besoin.

 # Using DataFrame.drop df.drop(df.columns[[1, 2]], axis=1, inplace=True) # drop by Name df1 = df1.drop(['B', 'C'], axis=1) # Select the ones you want df1 = df[['a','d']] 

Il existe une nouvelle méthode d’index appelée difference . Il renvoie les colonnes d’origine, avec les colonnes passées comme argument supprimé.

 df2 = df[df.columns.difference(['B', 'D'])] 

Ici, la sortie est utilisée pour filtrer les colonnes B et D de df .

Vous n’avez pas vraiment besoin de le convertir en un ensemble:

 cols = [col for col in df.columns if col not in ['B', 'D']] df2 = df[cols] 

Jetez également un œil à la fonction DataFrame.filter .

Approche minimaliste mais gourmande (suffisante pour le df donné):

 df.filter(regex="[^BD]") 

Approche conservasortingce / paresseuse (correspondances exactes uniquement):

 df.filter(regex="^(?!(B|D)$).*$") 

Conservateur et générique:

 exclude_cols = ['B','C'] df.filter(regex="^(?!({0})$).*$".format('|'.join(exclude_cols))) 

Il vous suffit de convertir votre set en list

 import pandas as pd df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) my_cols = set(df.columns) my_cols.remove('B') my_cols.remove('D') my_cols = list(my_cols) df2 = df[my_cols] 

Voici comment créer une copie d’un DataFrame excluant une liste de colonnes:

 df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) df2 = df.drop(['B', 'D'], axis=1) 

Mais fais attention! Vous mentionnez des points de vue dans votre question, suggérant que si vous df2 df , vous souhaitiez également que df2 change. (Comme une vue serait dans une firebase database.)

Cette méthode n’atteint pas cela:

 >>> df.loc[0, 'A'] = 999 # Change the first value in df >>> df.head(1) ABCD 0 999 -0.742688 -1.980673 -0.920133 >>> df2.head(1) # df2 is unchanged. It's not a view, it's a copy! AC 0 0.251262 -1.980673 

Notez également que cela est également vrai pour la méthode de @ piggybox. (Bien que cette méthode soit bien et lisse et Pythonic. Je ne le fais pas !!)

Pour plus d’informations sur les vues et les copies, voir cette réponse de SO et cette partie des documents de Pandas auxquels cette réponse fait référence.

Dans le même ordre d’idées, lors de la lecture d’un fichier, il peut être souhaitable d’exclure les colonnes au lieu de lire des données inutiles en mémoire et de les ignorer ultérieurement.

À partir des pandas 0.20.0, usecols accepte désormais les callables . 1 Cette mise à jour offre des options plus flexibles pour la lecture des colonnes:

 skipcols = [...] read_csv(..., usecols=lambda x: x not in skipcols) 

Ce dernier modèle est essentiellement l’inverse de la méthode usecols traditionnelle – seules les colonnes spécifiées sont ignorées.


Donné

Données dans un fichier

 import numpy as np import pandas as pd df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) filename = "foo.csv" df.to_csv(filename) 

Code

 skipcols = ["B", "D"] df1 = pd.read_csv(filename, usecols=lambda x: x not in skipcols, index_col=0) df1 

Sortie

  AC 0 0.062350 0.076924 1 -0.016872 1.091446 2 0.213050 1.646109 3 -1.196928 1.153497 4 -0.628839 -0.856529 ... 

Détails

Un DataFrame a été écrit dans un fichier. Il a ensuite été relu en tant que DataFrame distinct, ignorant maintenant les colonnes indésirables ( B et D ).

Notez que pour la situation de l’OP, puisque les données sont déjà créées, la meilleure approche est la réponse acceptée, qui supprime les colonnes indésirables d’un object existant. Cependant, la technique présentée ici est particulièrement utile lors de la lecture directe de données à partir de fichiers dans un DataFrame.

Une demande a été soulevée pour une option “skipcols” dans ce numéro et a été traitée dans un numéro ultérieur.

Vous avez 4 colonnes A, B, C, D

Voici un meilleur moyen de sélectionner les colonnes dont vous avez besoin pour le nouveau dataframe: –

 df2 = df1[['A','D']] 

Si vous souhaitez utiliser des numéros de colonne à la place, utilisez: –

 df2 = df1[[0,3]] 

Une autre option, sans laisser tomber ou filtrer en boucle:

 import numpy as np import pandas as pd # Create a dataframe with columns A,B,C and D df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) # include the columns you want df[df.columns[df.columns.isin(['A', 'B'])]] # exclude columns you don't want df[df.columns[~df.columns.isin(['C','D'])]]