web-dev-qa-db-fra.com

Sélection / exclusion des ensembles de colonnes dans pandas

Je souhaite créer des vues ou des cadres de données à partir d'un cadre de données existant en fonction des sélections de colonnes.

Par exemple, j'aimerais créer une image de données df2 à partir d'une image de données df1 contenant toutes les colonnes, à l'exception de deux d'entre elles. J'ai essayé de faire ce qui suit, mais ça n'a pas marché:

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 pandas doit prendre en charge la sélection et exclusions d'ensembles arbitraires de colonnes d'une trame de données?

222
Amelio Vazquez-Reina

Vous pouvez soit supprimer les colonnes dont vous n’avez pas besoin OR 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']]
313
Amrita Sawant

Il existe une nouvelle méthode d'indexation appelée difference . Il retourne les colonnes d'origine, les colonnes passées en argument étant supprimées.

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

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

124
IanS

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]
63
piggybox

ne autre option, sans déposer ni 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'])]]

# or more simply include columns:
df[['A', 'B']]

# exclude columns you don't want
df[df.columns[~df.columns.isin(['C','D'])]]
33
MrE

Consultez également la fonction intégrée DataFrame.filter .

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)))
_
16
Frank

Vous avez juste besoin de convertir votre set en 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]
6
tacaswell

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 avez mentionné des points de vue dans votre question, suggérant que si vous changiez df, vous voudriez que df2 change également. (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 ceci est également vrai de la méthode de @ piggybox. (Bien que cette méthode soit agréable et lisse et Pythonic. Je ne vais pas le faire !!)

Pour plus d'informations sur les vues par rapport aux copies, voir cette SO réponse et cette partie de la Pandas docs auquel cette réponse fait référence.

4
LondonRob

Dans le même ordre d'idées, lors de la lecture d'un fichier, on peut souhaiter exclure les colonnes dès le départ, plutôt que de lire inutilement des données indésirables dans la mémoire et de les supprimer ultérieurement.

À partir de pandas 0.20.0, usecols accepte maintenant les callables .1 Cette mise à jour permet des options plus souples pour la lecture de 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 ignorées.


Étant 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

          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 en tant que DataFrame séparé, en ignorant maintenant les colonnes non désirées (B et D).

Notez que dans la situation du PO, étant donné que des données sont déjà créées, la meilleure approche est la réponse acceptée, qui supprime les colonnes non désirées d'un objet existant. Toutefois, la technique présentée ici est particulièrement utile lors de la lecture directe de données de fichiers dans un DataFrame.

Une demande a été émise pour une option "skipcols" dans ce problème et a été traitée ultérieurement (problème .

4
pylang

Vous avez 4 colonnes A, B, C, D

Voici un meilleur moyen de sélectionner les colonnes dont vous avez besoin pour le nouveau cadre de données: -

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

si vous souhaitez utiliser les numéros de colonne à la place, utilisez: -

df2 = df1[[0,3]]
3
Kapil Marwaha