Eliminar varias columnas según los nombres de las columnas en Pandas

94

Tengo algunos datos y cuando los importo obtengo las siguientes columnas innecesarias Estoy buscando una manera fácil de eliminar todos estos

   'Unnamed: 24', 'Unnamed: 25', 'Unnamed: 26', 'Unnamed: 27',
   'Unnamed: 28', 'Unnamed: 29', 'Unnamed: 30', 'Unnamed: 31',
   'Unnamed: 32', 'Unnamed: 33', 'Unnamed: 34', 'Unnamed: 35',
   'Unnamed: 36', 'Unnamed: 37', 'Unnamed: 38', 'Unnamed: 39',
   'Unnamed: 40', 'Unnamed: 41', 'Unnamed: 42', 'Unnamed: 43',
   'Unnamed: 44', 'Unnamed: 45', 'Unnamed: 46', 'Unnamed: 47',
   'Unnamed: 48', 'Unnamed: 49', 'Unnamed: 50', 'Unnamed: 51',
   'Unnamed: 52', 'Unnamed: 53', 'Unnamed: 54', 'Unnamed: 55',
   'Unnamed: 56', 'Unnamed: 57', 'Unnamed: 58', 'Unnamed: 59',
   'Unnamed: 60'

Están indexados por indexación 0, así que probé algo como

    df.drop(df.columns[[22, 23, 24, 25, 
    26, 27, 28, 29, 30, 31, 32 ,55]], axis=1, inplace=True)

Pero esto no es muy eficiente. Intenté escribir algunos bucles for, pero esto me pareció un mal comportamiento de Pandas. Por eso hago la pregunta aquí.

He visto algunos ejemplos que son similares ( Soltar pandas de varias columnas ) pero esto no responde a mi pregunta.

Peadar Coyle
fuente
2
¿Qué quieres decir con eficiente? ¿Funciona demasiado lento? Si su problema es que no desea obtener los índices de todas las columnas que desea eliminar, tenga en cuenta que puede dar df.dropuna lista de nombres de columnas:df.drop(['Unnamed: 24', 'Unnamed: 25', ...], axis=1)
Carsten
¿No sería más fácil simplemente un subconjunto de las columnas de interés: es decir df = df[cols_of_interest], de lo contrario podría cortar el df por columnas y obtener las columnasdf.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)
EdChum
2
Me refiero a ineficaz en términos de tipeo o 'mal olor de código'
Peadar Coyle
1
Vale la pena señalar que en la mayoría de los casos es más fácil mantener las columnas que desea y luego eliminar las que no desea: df = df ['col_list']
sparrow

Respuestas:

65

No sé a qué te refieres con ineficiente, pero si te refieres en términos de escritura, podría ser más fácil seleccionar las columnas de interés y volver a asignarlas al df:

df = df[cols_of_interest]

Dónde cols_of_interesthay una lista de las columnas que le interesan.

O puede cortar las columnas y pasar esto a drop:

df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)

La llamada a headsolo selecciona 0 filas ya que solo nos interesan los nombres de las columnas en lugar de los datos

actualizar

Otro método: sería más sencillo usar la máscara booleana de str.containse invertirla para enmascarar las columnas:

In [2]:
df = pd.DataFrame(columns=['a','Unnamed: 1', 'Unnamed: 1','foo'])
df

Out[2]:
Empty DataFrame
Columns: [a, Unnamed: 1, Unnamed: 1, foo]
Index: []

In [4]:
~df.columns.str.contains('Unnamed:')

Out[4]:
array([ True, False, False,  True], dtype=bool)

In [5]:
df[df.columns[~df.columns.str.contains('Unnamed:')]]

Out[5]:
Empty DataFrame
Columns: [a, foo]
Index: []
EdChum
fuente
Recibo errores cuando intento hacer ~ df.columns ... (TypeError: tipo de operando incorrecto para unario ~: 'str') o df.columns.str.contains ... (AttributeError: el objeto 'Index' no tiene atributo 'str'). ¿Alguna idea de por qué podría ser esto?
Dai
@EdChum ¿puedo crear df = df [cols_of_interest] , donde cols_of_interest le agrega un nombre de columna cada vez que se repite un bucle for?
@Victor no, si lo sobrescribe dfcon su nueva columna, appendtal vez debería, pero realmente no entiendo su pregunta, debe publicar una pregunta real en SO en lugar de hacer un comentario, ya que es deficiente en SO
EdChum
@EdChum tienes toda la razón. He creado la pregunta y estoy tratando de resolverla buscando diferentes partes de SO. Aqui esta el link ! cualquier contribución ayudará a stackoverflow.com/questions/48923915/…
213

El enfoque más simple con diferencia es:

yourdf.drop(['columnheading1', 'columnheading2'], axis=1, inplace=True)
Philipp Schwarz
fuente
1
Usé este formato en algunos de mis códigos y recibo una SettingWithCopyWarningadvertencia.
KillerSnail
2
@KillerSnail, se guarda para ignorar. Para evitar errores, intente: df = df.drop (['colheading1', 'colheading2'], axis = 1)
Philipp Schwarz
5
El término axisexplicado: stackoverflow.com/questions/22149584/… . Esencialmente, axis=0se dice que es "por columnas" y axis=1"por filas".
Rohmer
5
Y inplace=Truesignifica que DataFramese modifica en su lugar.
Rohmer
1
@Killernail si no quieres la advertencia, hazloyourdf = yourdf.drop(['columnheading1', 'columnheading2'], axis=1)
happy_sisyphus
41

Mi favorito personal, y más fácil que las respuestas que he visto aquí (para varias columnas):

df.drop(df.columns[22:56], axis=1, inplace=True)

O creando una lista para varias columnas.

col = list(df.columns)[22:56]
df.drop(col, axis=1, inplace=1)
Sheldonzy
fuente
8
Esta debería ser la respuesta. Más limpio, más fácil de leer, con una sintaxis de indexación nativa de Pandas sencilla.
Brent Faust
2
Esta respuesta debe tener una marca verde junto a ella, no las demás.
Siavosh Mahboubian
1
Pequeña corrección (a menos que me equivoque): el segundo bloque de código debería tener 'inplace = True' en lugar de 'inplace = 1'.
Thredolsen
20

Esta es probablemente una buena forma de hacer lo que quiere. Eliminará todas las columnas que contengan 'Sin nombre' en su encabezado.

for col in df.columns:
    if 'Unnamed' in col:
        del df[col]
Knightofni
fuente
esto for col in df.columns:se puede simplificar for col in df:, además, el OP no ha indicado cuál es el esquema de nomenclatura para las otras columnas, todas podrían contener 'Sin nombre', también esto es ineficiente ya que elimina las columnas una a la vez
EdChum
Ciertamente no es eficiente, pero mientras no estemos trabajando en grandes marcos de datos, no tendrá un impacto significativo. El punto positivo de este método es que es fácil de recordar y rápido de codificar, mientras que crear una lista de las columnas que desea conservar puede ser bastante doloroso.
knightofni
Creo que esto es probable que sea mas potente en gran df, ya que no tiene que hacer una copia local coninplace = True
Matt
13

Puede hacer esto en una línea y una vez:

df.drop([col for col in df.columns if "Unnamed" in col], axis=1, inplace=True)

Esto implica menos movimiento / copia del objeto que las soluciones anteriores.

Pedro
fuente
11

No estoy seguro de si esta solución se ha mencionado en alguna parte, pero una forma de hacerlo es pandas.Index.difference.

>>> df = pd.DataFrame(columns=['A','B','C','D'])
>>> df
Empty DataFrame
Columns: [A, B, C, D]
Index: []
>>> to_remove = ['A','C']
>>> df = df[df.columns.difference(to_remove)]
>>> df
Empty DataFrame
Columns: [B, D]
Index: []
px06
fuente
4

Puede simplemente pasar los nombres de las columnas como una lista especificando el eje como 0 o 1

  • eje = 1: a lo largo de las filas
  • eje = 0: a lo largo de las columnas
  • Por defecto eje = 0

    data.drop(["Colname1","Colname2","Colname3","Colname4"],axis=1)

Maddu Swaroop
fuente
4

Simple y fácil. Elimina todas las columnas después del 22.

df.drop(columns=df.columns[22:]) # love it
Niedson
fuente
Para modificar dfen su lugar, agregue la bandera inplace=True, De modo quedf.drop(columns=df.columns[22:], inplace=True)
arilwan
1

Lo siguiente funcionó para mí:

for col in df:
    if 'Unnamed' in col:
        #del df[col]
        print col
        try:
            df.drop(col, axis=1, inplace=True)
        except Exception:
            pass
Shivgan
fuente
0

df = df[[col for col in df.columns if not ('Unnamed' in col)]]

Sarah
fuente
1
Esto es similar al de Peter, excepto que las columnas no deseadas se filtran en lugar de eliminarse.
Sarah