Sélection / exclusion des ensembles de colonnes dans les 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 d'entre elles. 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 de mal? Peut-être plus généralement, quels mécanismes Panda a-t-il pour prendre en charge la sélection et exclusions d'ensembles arbitraires de colonnes à partir d'un dataframe?
9 réponses
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 convertir cela en un ensemble:
cols = [col for col in df.columns if col not in ['B', 'D']]
df2 = df[cols]
Ont Également un coup d'oeil dans le haut-DataFrame.filter
fonction.
Approche minimaliste mais gourmande (suffisante pour le df donné):
df.filter(regex="[^BD]")
Approche conservatrice / 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)))
, Vous avez juste besoin de convertir votre set
pour un 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 un copie de DataFrame
à l'exclusion d'une liste de colonnes:
df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
df2 = df.drop(['B', 'D'], axis=1)
Mais attention! Vous mentionnez les vues dans votre question, suggérant que si vous avez changé df
, vous voudriez que df2
change aussi. (Comme une vue dans une base de données.)
Cette méthode n'atteint pas cela:
>>> df.loc[0, 'A'] = 999 # Change the first value in df
>>> df.head(1)
A B C D
0 999 -0.742688 -1.980673 -0.920133
>>> df2.head(1) # df2 is unchanged. It's not a view, it's a copy!
A C
0 0.251262 -1.980673
Notez également que cela est également vrai de la méthode de @ piggybox. (Bien que cette méthode soit agréable et lisse et pythonique. Je ne vais pas le faire vers le bas!!)
Pour en savoir plus sur les vues et les copies voir cette réponse SO et cette partie des documents Pandas auxquels cette réponse fait référence.
Vous avez 4 colonnes A,B,C, D
Voici une meilleure façon 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 dans une 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'])]]
Dans la même veine, lors de la lecture d'un fichier, on peut souhaiter exclure des colonnes dès le départ, plutôt que de lire inutilement des données indésirables en mémoire et de les rejeter plus tard.
, Comme des pandas 0.20.0, usecols
accepte maintenant callables.1 Cette mise à jour permet 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 traditionnelle usecols
- seules les colonnes spécifiées sont sauter.
Compte tenu de
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
A C
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 comme un DataFrame séparé, sautant 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 objet existant. Cependant, la technique présentée ici est très utile lors de la lecture directe de données à partir de fichiers dans un DataFrame.
Une demande a été posée par "skipcols" option dans cette question et a été résolu dans une version ultérieure question.