Eliminar una columna de un marco de datos de Pandas

1727

Al eliminar 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

Dado que es posible acceder a la columna / Serie como df.column_name, esperaba que esto funcionara.

1
  • 2
    Tenga en cuenta que esta pregunta se está discutiendo en Meta .
    R.M.
    22 de mayo de 2019 a las 16:37
2725

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

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

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

Para eliminar la columna sin tener que reasignar dfpuede 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, la primera, segunda y cuarta columnas:

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

También trabajando con sintaxis de "texto" para las columnas:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)

Nota: Introducido en v0.21.0 (27 de octubre de 2017), el método drop () acepta palabras clave de índice / columnas como alternativa a la especificación del eje.

Entonces ahora podemos simplemente hacer:

df = df.drop(columns=['column_nameA', 'column_nameB'])
5
  • 95
    ¿Se recomienda esto delpor alguna razón?
    beardc
    10/1213 a las 20:13
  • 27
    Aunque este método de eliminación tiene sus méritos, esta respuesta realmente no responde a la pregunta que se hace.
    Paul
    28 de mayo de 2014 a las 12:59 p.m.
  • 140
    Es cierto @Paul, pero debido al título de la pregunta, la mayoría de las personas que llegan aquí lo harán tratando de averiguar cómo eliminar una columna. 28 de mayo de 2014 a las 16:43
  • 33
    @beardc otra ventaja de dropover deles que le droppermite eliminar varias columnas a la vez, realizar la operación en el lugar o no, y también eliminar registros a lo largo de cualquier eje (especialmente útil para una matriz 3-D o Panel)
    hobs
    14/04/2016 a las 20:17
  • 17
    Otra ventaja de dropover deles que drop es parte de la API de pandas y contiene documentación. 12 de agosto de 2016 a las 8:53
1201

Como habrás adivinado, la sintaxis correcta es

del df['column_name']

Es difícil hacer que del df.column_namefuncione simplemente como resultado de las limitaciones sintácticas en Python. del df[name]se traduce df.__delitem__(name)bajo las sábanas por Python.

8
  • 31
    Me doy cuenta de que esta es una "respuesta" muy antigua, pero me pica la curiosidad: ¿por qué es una limitación sintáctica de Python? class A(object): def __init__(self): self.var = 1configura una clase, luego a = A(); del a.varfunciona bien ... 4 oct 2016 a las 14:24
  • 20
    @dwanderson, la diferencia es que cuando se va a eliminar una columna, el DataFrame debe tener su propio manejo para "cómo hacerlo". En el caso de del df[name], se traduce a df.__delitem__(name)cuál es un método que DataFrame puede implementar y modificar a sus necesidades. En el caso de del df.name, la variable miembro se elimina sin posibilidad de que se ejecute ningún código personalizado. Considere su propio ejemplo: ¿puede llegar del a.vara dar como resultado una impresión de "eliminación de variable"? Si puede, dígame cómo. No puedo :)
    Yonatan
    22 de diciembre de 2016 a las 8:27
  • 8
    @Yonatan Puede usar docs.python.org/3/reference/datamodel.html#object.__delattr__ o descriptores para eso: docs.python.org/3/howto/descriptor.html 19 de enero de 2017 a las 16:06
  • 5
    El comentario de @Yonatan Eugene también se aplica a Python 2; los descriptores han estado en Python 2 desde 2.2 y es trivial satisfacer su requisito;)
    C S
    20 de junio de 2017 a las 12:38
  • 3
    Esta respuesta no es realmente correcta, los pandasdesarrolladores no lo hicieron , pero eso no significa que sea difícil de hacer. 30 de septiembre de 2017 a las 9:42
285

Usar:

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

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

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

Gota por índice

Elimine la primera, segunda y cuarta columnas:

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

Eliminar la primera columna:

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

Existe un parámetro opcional inplacepara que los datos originales se puedan modificar sin crear una copia.

Apareció

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

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
0
81

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

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

Al principio, debemos comprender el problema, lo que requiere que nos sumerjamos en los métodos mágicos de Python .

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

Sin embargo, como se señala en el enlace anterior sobre los métodos mágicos de Python :

In fact, __del__ should almost never be used because of the precarious circumstances under which it is called; use it with caution!

Se podría argumentar que del df['column_name']no debería utilizarse ni fomentarse y, por del df.column_namelo tanto , ni siquiera debería considerarse.

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

Problema de ejemplo

¿Qué sucede si defino una columna en un marco de datos llamado "dtypes" o "columnas"?

Entonces suponga que quiero eliminar estas columnas.

del df.dtypes__delattr__confundiría el método como si debiera eliminar el atributo "dtypes" o la columna "dtypes".

Preguntas arquitectónicas detrás de este problema

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

Pandas responde:

  1. Si, en todos los sentidos
  2. No, pero si usted quiere que sea, puede utilizar los .ix, .loco .ilocmétodos.
  3. Tal vez, ¿quieres leer datos? Entonces , a menos que el nombre del atributo ya esté tomado por otro atributo que pertenezca al marco de datos. ¿Quieres modificar los datos? Entonces no .

TLDR;

No se puede hacer del df.column_name, porque Pandas tiene una arquitectura bastante desarrollada que necesita ser reconsiderada para que este tipo de disonancia cognitiva no se les ocurra a sus usuarios.

Tipo profesional:

No use df.column_name. Puede ser bonito, pero provoca disonancia cognitiva .

Citas de Zen of Python que encajan aquí:

Hay varias formas de eliminar una columna.

There should be one-- and preferably only one --obvious way to do it.

A veces, las columnas son atributos, pero a veces no.

Special cases aren't special enough to break the rules.

¿ del df.dtypesElimina el atributo dtypes o la columna dtypes?

In the face of ambiguity, refuse the temptation to guess.

1
  • 1
    En realidad, aborda la parte de PORQUÉ de la pregunta original. Implementé subclases de pandas dataframe. Si lo hace, le enseñará una parte vital de esta respuesta. Diferenciar atributos y nombres de columnas es un gran problema. df.a deja ambigüedad si a es un atributo o un nombre de columna. Sin embargo, como se escribe pandas, df ["a"] solo puede ser una columna. 21 de julio a las 4:43
66

Una buena adición es la capacidad de eliminar columnas solo si existen . De esta manera, puede cubrir más casos de uso y solo eliminará las columnas existentes de las etiquetas 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 desde pandas 0.16.1 en adelante. La documentación está aquí .
46

Desde la versión 0.16.1, puede hacer

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
1
  • 3
    ¡Y esto también permite eliminar varias columnas, algunas de las cuales no necesitan existir (es decir, sin generar errores errors= 'ignore') df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore'), si tal aplicación lo desea!
    muon
    21/10/2016 a las 19:57
36

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 í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 "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax
0
30

Pandas 0.21+ respuesta

La versión 0.21 de Pandas ha cambiado dropligeramente el método para incluir los parámetros indexy columnspara que coincidan con la firma de los métodos renamey reindex.

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

Personalmente, prefiero usar el axisparámetro para denotar columnas o índice porque es el parámetro de palabra clave predominante que se usa en casi todos los métodos de pandas. Pero ahora tiene algunas opciones adicionales en la versión 0.21.

0
23

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

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

Usar:

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

O de lo contrario puedes ir con

del df['colname']

Para eliminar varias columnas según los números de columna

df.drop(df.iloc[:,1:3], axis = 1, inplace = True)

Para eliminar varias columnas según los nombres de las columnas

df.drop(['col1','col2',..'coln'], axis = 1, inplace = True)
0
18

TL; DR

Mucho esfuerzo para encontrar una solución ligeramente más eficiente. Difícil de justificar la complejidad añadida sacrificando la simplicidad dedf.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 a considerar.

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

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


Configuración
Considere la pd.DataFrame dflista y para eliminardlst

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

df

   A  B  C  D  E  F  G  H  I   J
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 debería verse así:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Como estoy equiparando la eliminación de una columna con la selección de las otras columnas, la dividiré en dos tipos:

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

Selección de etiquetas

Comenzamos por fabricar la lista / matriz de etiquetas 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 etiquetas
Para comparar el proceso de selección, suponga:

 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 para:

   A  B  C  D  E  F  G
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 valores booleanos para cortar

  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 Boolean
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 para:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Sincronización robusta

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 tarda en ejecutarse df.drop(dlst, 1, errors='ignore'). Parece que después de todo ese esfuerzo, solo mejoramos el rendimiento modestamente.

ingrese la descripción de la imagen aquí

De hecho, las mejores soluciones utilizan reindexo reindex_axisen el truco list(set(df.columns.values.tolist()).difference(dlst)). Un segundo cercano y todavía muy ligeramente mejor de lo que dropes 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
13

Podemos eliminar o eliminar una columna especificada o columnas especificadas mediante el método drop () .

Suponga que df es un marco de datos.

Columna que se eliminará = columna0

Code:

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

Para eliminar varias columnas col1, col2,. . . , coln, tenemos que insertar todas las columnas que debían eliminarse en una lista. Luego elimínelos con el método drop ().

Code:

df = df.drop([col1, col2, . . . , coln], axis=1)
0
6

Si su marco de datos original dfno es demasiado grande, no tiene restricciones de memoria y solo necesita mantener algunas columnas, o, si no conoce de antemano los nombres de todas las columnas adicionales que no necesita, entonces podría también cree un nuevo marco de datos con solo las columnas que necesita:

new_df = df[['spam', 'sausage']]
3

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

  • Pitón: del df['column_name']
  • JavaScript: del df['column_name'] o del df.column_name
0
3

Eliminando una columna usando la ilocfunción de dataframey slicing, cuando tenemos un nombre de columna típico con valores no deseados:

df = df.iloc[:,1:] # Removing an unnamed index column

Aquí 0está la fila predeterminada y 1es la primera columna, por :,1:lo tanto, es nuestro parámetro para eliminar la primera columna.

0
2

Otra forma de eliminar una columna en un Pandas DataFrame

Si no está buscando una eliminación en el lugar , puede crear un nuevo DataFrame especificando las columnas usando la DataFrame(...)función como:

my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']}

df = pd.DataFrame(my_dict)

Cree un nuevo DataFrame como

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

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

1
  • 1
    Esto es técnicamente correcto, pero parece una tontería tener que enumerar todas las columnas para conservar en lugar de solo una (o pocas) columnas que desea eliminar.
    cs95
    23 de mayo de 2019 a las 17:24