Eliminar columna de pandas DataFrame por nombre de columna

Cuando borro una columna en un DataFrame, uso:

del df['column_name'] 

Y esto funciona muy bien. ¿Por qué no puedo usar lo siguiente?

 del df.column_name 

Como puede acceder a la columna / Serie como df.column_name , espero que esto funcione.

Como has adivinado, la syntax correcta es

 del df['column_name'] 

Es difícil hacer que del df.column_name funcione simplemente como resultado de limitaciones sintácticas en Python. del df[name] se traduce a df.__delitem__(name) bajo las carátulas de Python.

La mejor manera de hacer esto en pandas es usar drop :

 df = df.drop('column_name', 1) 

donde 1 es el número del eje ( 0 para las filas y 1 para las columnas).

Para eliminar la columna sin tener que reasignar df puede hacer:

 df.drop('column_name', axis=1, inplace=True) 

Finalmente, para colocar por número de columna en lugar de por etiqueta de columna, intente esto para eliminar, por ejemplo, las columnas 1, 2 y 4:

 df = df.drop(df.columns[[0, 1, 3]], axis=1) # df.columns is zero-based pd.Index 

Utilizar:

 columns = ['Col1', 'Col2', ...] df.drop(columns, inplace=True, axis=1) 

Esto eliminará una o más columnas en el lugar. Tenga en cuenta que inplace=True se agregó en pandas v0.13 y no funcionará en versiones anteriores. Tendrías que volver a asignar el resultado en ese caso:

 df = df.drop(columns, axis=1) 

Caer por índice

Eliminar primera, segunda y cuarta columnas:

 df.drop(df.columns[[0,1,3]], axis=1, inplace=True) 

Eliminar primera columna:

 df.drop(df.columns[[0]], axis=1, inplace=True) 

Hay un parámetro opcional en el inplace para que los datos originales puedan modificarse sin crear una copia.

Popped

Selección de columnas, adición, eliminación

Eliminar columna column-name :

 df.pop('column-name') 

Ejemplos:

 df = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6]), ('C', [7,8, 9])], orient='index', columns=['one', 'two', 'three']) 

print df :

  one two three A 1 2 3 B 4 5 6 C 7 8 9 

df.drop(df.columns[[0]], axis=1, inplace=True) print df :

  two three A 2 3 B 5 6 C 8 9 

three = df.pop('three') print df :

  two A 2 B 5 C 8 

La pregunta real planteada, perdida por la mayoría de las respuestas aquí es:

¿Por qué no puedo usar del df.column_name ?

Al principio debemos entender el problema, que requiere que nos sumergamos en los métodos mágicos de los pitones .

Como lo señala Wes en su respuesta del df['column'] asigna al método mágico de python df.__delitem__('column') que se implementa en los pandas para eliminar la columna

Sin embargo, como se señaló en el enlace anterior sobre los métodos mágicos de python :

De hecho, deli casi nunca debe usarse debido a las precarias circunstancias en que se llama; ¡Úsalo con precaución!

Podría argumentar que del df['column_name'] no se debe usar o alentar, y por lo tanto del df.column_name ni siquiera se debe considerar.

Sin embargo, en teoría, del df.column_name podría del df.column_name para trabajar en pandas usando el método mágico __delattr__ . Sin embargo, esto introduce ciertos problemas, problemas que ya tiene la implementación del df['column_name'] , pero en menor grado.

Problema de ejemplo

¿Qué pasa si defino una columna en un dataframe llamado “dtypes” o “columnas”.

Entonces asume que quiero eliminar estas columnas.

del df.dtypes confundiría el método __delattr__ como si eliminara el atributo “dtypes” o la columna “dtypes”.

Preguntas arquitectónicas detrás de este problema.

  1. ¿Es un dataframe una colección de columnas ?
  2. ¿Es un dataframe una colección de filas ?
  3. ¿Es una columna un atributo de un dataframe?

Pandas responde:

  1. Si en todos los sentidos
  2. No, pero si lo desea, puede usar los .ix , .loc o .iloc .
  3. Tal vez, ¿quieres leer datos? Entonces , a menos que el nombre del atributo ya esté tomado por otro atributo que pertenece al dataframe. ¿Quieres modificar los datos? Entonces no

TLDR;

No puede hacer del df.column_name porque pandas tiene una architecture bastante desarrollada que debe ser reconsiderada para que este tipo de disonancia cognitiva no ocurra a sus usuarios.

Protip:

No use df.column_name, puede ser bonito, pero causa disonancia cognitiva

Cotizaciones de Zen de Python que encaja aquí:

Hay varias formas de eliminar una columna.

Debe haber una, y preferiblemente solo una, obvia forma de hacerlo.

Las columnas son a veces atributos pero a veces no.

Los casos especiales no son lo suficientemente especiales para romper las reglas.

¿El del df.dtypes elimina el atributo dtypes o la columna dtypes?

Ante la ambigüedad, rechace la tentación de adivinar.

Una buena adición es la posibilidad de eliminar columnas solo si existen . De esta manera puede cubrir más casos de uso, y solo eliminará las columnas existentes de las tags que se le pasaron:

Simplemente agregue errores = ‘ignorar’ , por ejemplo .:

 df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore') 
  • Esto es nuevo a partir de pandas 0.16.1 en adelante. La documentación está aquí .

A partir de la versión 0.16.1 se puede hacer.

 df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore') 

Es una buena práctica usar siempre la notación [] . Una razón es que la notación de atributo ( df.column_name ) no funciona para los índices numerados:

 In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]]) In [2]: df[1] Out[2]: 0 2 1 5 Name: 1 In [3]: df.1 File "", line 1 df.1 ^ SyntaxError: invalid syntax 

En pandas 0.16.1+ puede eliminar columnas solo si existen según la solución publicada por @eiTanLaVi. Antes de esa versión, puede lograr el mismo resultado a través de una lista de comprensión condicional:

 df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df], axis=1, inplace=True) 

Pandas 0.21+ respuesta

La versión 0.21 de Pandas ha cambiado el método de drop ligeramente para incluir los parámetros de index y columns para que coincida con la firma de los métodos de rename y reindex .

 df.drop(columns=['column_a', 'column_c']) 

Personalmente, prefiero usar el parámetro axis para denotar columnas o índice porque es el parámetro de palabra clave predominante usado en casi todos los métodos de pandas. Pero, ahora tienes algunas opciones agregadas en la versión 0.21.

TL; DR

Mucho esfuerzo para encontrar una solución marginalmente más eficiente. Es difícil justificar la complejidad agregada mientras se sacrifica la simplicidad de df.drop(dlst, 1, errors='ignore')

 df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1) 

Preámbulo
Eliminar una columna es semánticamente lo mismo que seleccionar las otras columnas. Mostraré algunos métodos adicionales para considerar.

También me centraré en la solución general de eliminar varias columnas a la vez y permitir el bash de eliminar columnas que no están presentes.

El uso de estas soluciones es general y también funcionará para el caso simple.


Preparar
Tenga en cuenta el df pd.DataFrame y la lista para eliminar dlst

 df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3)) dlst = list('HIJKLM') 

 df ABCDEFGHIJ 0 1 2 3 4 5 6 7 8 9 10 1 1 2 3 4 5 6 7 8 9 10 2 1 2 3 4 5 6 7 8 9 10 

 dlst ['H', 'I', 'J', 'K', 'L', 'M'] 

El resultado debe verse como:

 df.drop(dlst, 1, errors='ignore') ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Ya que estoy igualando la eliminación de una columna para seleccionar las otras columnas, la dividiré en dos tipos:

  1. Selección de tags
  2. Selección booleana

Selección de tags

Comenzamos por fabricar la lista / matriz de tags que representan las columnas que queremos mantener y sin las columnas que queremos eliminar.

  1. df.columns.difference(dlst)

     Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object') 
  2. np.setdiff1d(df.columns.values, dlst)

     array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object) 
  3. df.columns.drop(dlst, errors='ignore')

     Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object') 
  4. list(set(df.columns.values.tolist()).difference(dlst))

     # does not preserve order ['E', 'D', 'B', 'F', 'G', 'A', 'C'] 
  5. [x for x in df.columns.values.tolist() if x not in dlst]

     ['A', 'B', 'C', 'D', 'E', 'F', 'G'] 

Columnas de tags
Para poder comparar el proceso de selección, asum:

  cols = [x for x in df.columns.values.tolist() if x not in dlst] 

Entonces podemos evaluar

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

Que todos evalúan a:

  ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Rebanada booleana

Podemos construir una matriz / lista de booleanos para rebanar

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

Columnas de booleano
Por el bien de la comparación

 bools = [x not in dlst for x in df.columns.values.tolist()] 
  1. df.loc[: bools]

Que todos evalúan a:

  ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Tiempo robusto

Funciones

 setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst) difference = lambda df, dlst: df.columns.difference(dlst) columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore') setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst)) comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst] loc = lambda df, cols: df.loc[:, cols] slc = lambda df, cols: df[cols] ridx = lambda df, cols: df.reindex(columns=cols) ridxa = lambda df, cols: df.reindex_axis(cols, 1) isin = lambda df, dlst: ~df.columns.isin(dlst) in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst) comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()] brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1) 

Pruebas

 res1 = pd.DataFrame( index=pd.MultiIndex.from_product([ 'loc slc ridx ridxa'.split(), 'setdiff1d difference columndrop setdifflst comprehension'.split(), ], names=['Select', 'Label']), columns=[10, 30, 100, 300, 1000], dtype=float ) res2 = pd.DataFrame( index=pd.MultiIndex.from_product([ 'loc'.split(), 'isin in1d comp brod'.split(), ], names=['Select', 'Label']), columns=[10, 30, 100, 300, 1000], dtype=float ) res = res1.append(res2).sort_index() dres = pd.Series(index=res.columns, name='drop') for j in res.columns: dlst = list(range(j)) cols = list(range(j // 2, j + j // 2)) d = pd.DataFrame(1, range(10), cols) dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100) for s, l in res.index: stmt = '{}(d, {}(d, dlst))'.format(s, l) setp = 'from __main__ import d, dlst, {}, {}'.format(s, l) res.at[(s, l), j] = timeit(stmt, setp, number=100) rs = res / dres 

 rs 10 30 100 300 1000 Select Label loc brod 0.747373 0.861979 0.891144 1.284235 3.872157 columndrop 1.193983 1.292843 1.396841 1.484429 1.335733 comp 0.802036 0.732326 1.149397 3.473283 25.565922 comprehension 1.463503 1.568395 1.866441 4.421639 26.552276 difference 1.413010 1.460863 1.587594 1.568571 1.569735 in1d 0.818502 0.844374 0.994093 1.042360 1.076255 isin 1.008874 0.879706 1.021712 1.001119 0.964327 setdiff1d 1.352828 1.274061 1.483380 1.459986 1.466575 setdifflst 1.233332 1.444521 1.714199 1.797241 1.876425 ridx columndrop 0.903013 0.832814 0.949234 0.976366 0.982888 comprehension 0.777445 0.827151 1.108028 3.473164 25.528879 difference 1.086859 1.081396 1.293132 1.173044 1.237613 setdiff1d 0.946009 0.873169 0.900185 0.908194 1.036124 setdifflst 0.732964 0.823218 0.819748 0.990315 1.050910 ridxa columndrop 0.835254 0.774701 0.907105 0.908006 0.932754 comprehension 0.697749 0.762556 1.215225 3.510226 25.041832 difference 1.055099 1.010208 1.122005 1.119575 1.383065 setdiff1d 0.760716 0.725386 0.849949 0.879425 0.946460 setdifflst 0.710008 0.668108 0.778060 0.871766 0.939537 slc columndrop 1.268191 1.521264 2.646687 1.919423 1.981091 comprehension 0.856893 0.870365 1.290730 3.564219 26.208937 difference 1.470095 1.747211 2.886581 2.254690 2.050536 setdiff1d 1.098427 1.133476 1.466029 2.045965 3.123452 setdifflst 0.833700 0.846652 1.013061 1.110352 1.287831 

 fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True) for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]): ax = axes[i // 2, i % 2] g.plot.bar(ax=ax, title=n) ax.legend_.remove() fig.tight_layout() 

Esto es relativo al tiempo que lleva ejecutar df.drop(dlst, 1, errors='ignore') . Parece que después de todo ese esfuerzo, solo mejoramos el rendimiento modestamente.

introduzca la descripción de la imagen aquí

Si es el caso, las mejores soluciones usan reindex_axis o reindex_axis en la list(set(df.columns.values.tolist()).difference(dlst)) . Un segundo cercano y aún muy marginalmente mejor que el drop es np.setdiff1d .

 rs.idxmin().pipe( lambda x: pd.DataFrame( dict(idx=x.values, val=rs.lookup(x.values, x.index)), x.index ) ) idx val 10 (ridx, setdifflst) 0.653431 30 (ridxa, setdifflst) 0.746143 100 (ridxa, setdifflst) 0.816207 300 (ridx, setdifflst) 0.780157 1000 (ridxa, setdifflst) 0.861622 

Si desea eliminar una sola columna ( col_name ) desde un dataframe ( df ), intente uno de los siguientes:

 df = df.drop(col_name, axis=1) 

O

 df.drop(col_name, axis=1, inplace=True) 

Si desea eliminar una lista de columnas ( col_lst = [col_name_1,col_name_2,...] ) de un dataframe ( df ), intente uno de los siguientes:

 df.drop(col_lst, axis=1, inplace=True) 

O

 df.drop(columns=col_lst, inplace=True) 

La syntax de puntos funciona en JavaScript, pero no en Python.

  • Python: del df['column_name']
  • JavaScript: del df['column_name'] o del df.column_name

prueba esto, creo que esta es la forma más simple:

drop((['A','B'],axis=1)

Otra forma de eliminar una columna en Pandas DataFrame

Si no está buscando una eliminación in situ, puede crear un nuevo DataFrame especificando las columnas con la función DataFrame(...) como

 my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']} df = pd.DataFrame(my_dict) 

Crear un nuevo DataFrame como

 newdf = pd.DataFrame(df, columns=['name', 'age']) 

Obtienes un resultado tan bueno como lo que obtienes con del / drop