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?
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']]
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
.
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]
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'])]]
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)))
_
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]
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.
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 .
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]]