Eliminar columna de pandas DataFrame

1334

Al eliminar una columna en un DataFrame que uso:

del df['column_name']

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

del df.column_name

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

Juan
fuente
2
Tenga en cuenta que esta pregunta se está discutiendo en Meta .
RM

Respuestas:

862

Como habrás adivinado, la sintaxis correcta es

del df['column_name']

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

Wes McKinney
fuente
25
Me doy cuenta de que esta es una "respuesta" súper antigua, pero mi curiosidad se despierta: ¿por qué es una limitación sintáctica de Python? class A(object): def __init__(self): self.var = 1establece una clase, luego a = A(); del a.varfunciona bien ...
dwanderson
14
@dwanderson la diferencia es que cuando se va a eliminar una columna, el DataFrame debe tener su propio manejo de "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 según sus necesidades. En el caso de del df.name, la variable miembro se elimina sin posibilidad de ejecutar ningún código personalizado. Considere su propio ejemplo: ¿puede obtener del a.varuna impresión de "eliminación de variable"? Si puedes, por favor dime cómo. No puedo :)
Yonatan
55
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 requerimiento;)
CS
1
Esta respuesta no es realmente correcta: los pandasdesarrolladores no lo hicieron , pero eso no significa que sea difícil de hacer.
wizzwizz4
2187

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 y1 para columnas).

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

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

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

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)
LondonRob
fuente
79
¿Se recomienda esto delpor alguna razón?
beardc
20
Aunque este método de eliminación tiene sus ventajas, esta respuesta realmente no responde a la pregunta que se hace.
Paul
109
Verdadero @Paul, pero debido al título de la pregunta, la mayoría de las personas que llegan aquí lo harán intentando averiguar cómo eliminar una columna.
LondonRob
24
@beardc otra ventaja de dropover deles que le droppermite soltar 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 tridimensional o Panel)
placas el
8
Otra ventaja de dropover deles que drop es parte de la API de pandas y contiene documentación.
modulitos
242

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=Truese agregó en pandas v0.13 y no funcionará en versiones anteriores. Tendría que asignar el resultado nuevamente en ese caso:

df = df.drop(columns, axis=1)
Krishna Sankar
fuente
3
Una nota sobre esta respuesta: si se usa una 'lista', los corchetes se deben df.drop(list,inplace=True,axis=1)
quitar
1
esta realmente debería ser la respuesta aceptada, porque deja en claro que la superioridad de este método delpuede eliminar más de una columna a la vez.
dbliss
111

Soltar por índice

Eliminar primera, segunda y cuarta columna:

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 inplace para que los datos originales se puedan modificar sin crear una copia.

Reventado

Selección de columna, 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
jezrael
fuente
1
¿Cómo puedo hacer una fila en pandas?
Kennet Celeste
2
@Yugi Puede usar un marco de datos transpuesto para eso. ex - df.T.pop('A')
Clock Slave
@ClockSlave Eso no modifica el original df. Usted podría hacer df = df.T; df.pop(index); df = df.T, pero esto parece excesivo.
cs95
En lugar de df.drop(df.columns[[0]], axis=1, inplace=True)no sería suficiente para usar df.drop([0], axis=1)?
Anirban Mukherjee
1
@Anirban Mukherjee Depende. Si desea eliminar el nombre de la columna 0, entonces df.drop(0, axis=1)funciona bien. Pero si no sabe el nombre de la columna y necesita eliminar la primera columna, entonces necesita df.drop(df.columns[[0]], axis=1, inplace=True), seleccione la primera columna por posición y suéltela.
Israel
71

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 tenemos que entender el problema, que requiere que nos sumerjamos en los métodos mágicos de Python .

Como señala Wes en sus del df['column']mapas de respuestas al método mágico de Python df.__delitem__('column')que se implementa en pandas para soltar la columna

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

De hecho, __del__casi nunca debe usarse debido a las circunstancias precarias en las que se llama; úsalo con precaución!

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

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

Problema de ejemplo

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

Luego asuma 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 quieres que sea así, puedes usar el .ix, .loco.iloc métodos.
  3. Tal vez, ¿quieres leer datos? Entonces , a menos que el nombre del atributo ya lo haya tomado otro atributo que pertenezca al marco de datos. ¿Quieres modificar los datos? Entonces no .

TLDR;

No puede hacerlo del df.column_nameporque los pandas tienen una arquitectura bastante desarrollada que necesita 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

Zen de Python cita que encaja aquí:

Hay varias formas de eliminar una columna.

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

Las columnas son a veces atributos pero a veces no.

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

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

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

firelynx
fuente
"De hecho, __del__casi nunca debe usarse debido a las circunstancias precarias en las que se llama; ¡úselo con precaución!" es completamente irrelevante aquí, como lo es el método que se usa aquí __delattr__.
pppery
1
@ppperry estás citando mal. lo delque se entiende es el .__del__método incorporado, no el método de instancia. El delbuiltin se está asignando __delattr__y __delitem__es sobre lo que estoy construyendo mi argumento. Entonces quizás quieras volver a leer lo que escribí.
firelynx
1
__... __se interpreta como marcado en negrita por StackExchange
pppery
2
"No use df.column_name, puede ser bonito, pero causa disonancia cognitiva" ¿Qué significa esto? No soy psicólogo, así que tengo que buscar esto para entender lo que quieres decir. Además, citar The Zen no tiene sentido porque hay cientos de formas válidas de hacer lo mismo en los pandas.
cs95
58

Una buena adición es la capacidad de soltar 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 los pandas 0.16.1 en adelante. La documentación está aquí .
eiTan LaVi
fuente
41

desde la versión 0.16.1 puedes hacer

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
sushmit
fuente
3
Y esto también es compatible con la eliminación de varias columnas, algunas de las cuales no es necesario que existan (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
31

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
Andy Hayden
fuente
26

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 utilizado en casi todos los métodos de pandas. Pero, ahora tiene algunas opciones adicionales en la versión 0.21.

Ted Petrou
fuente
1
df.drop (['column_a', 'column_c'], axis = 1) | está funcionando para mí por ahora
YouAreAwesome
21

En pandas 0.16.1+, puede soltar 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 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)
Alejandro
fuente
14

TL; DR

Mucho esfuerzo para encontrar una solución marginalmente más eficiente. Difícil de justificar la complejidad añadida mientras se sacrifica 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 tener en cuenta.

También me centraré en la solución general de eliminar varias columnas a la vez y permitir el intento de eliminar 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 para seleccionar las otras columnas, la dividiré en dos tipos:

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

Selección de etiqueta

Comenzamos fabricando la lista / matriz de etiquetas que representan las columnas que queremos conservar 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

Boolean Slice

Podemos construir una matriz / lista de 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 booleano
En aras 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

Tiempo robusto

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

ingrese la descripción de la imagen aquí

De hecho, las mejores soluciones usan reindexo reindex_axisen el pirateo list(set(df.columns.values.tolist()).difference(dlst)). Un segundo cercano y todavía muy marginalmente 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
piRSquared
fuente
2

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
Médico
fuente
2

Si su marco de datos original dfno es demasiado grande, no tiene restricciones de memoria, y solo necesita mantener unas pocas columnas, entonces también podría crear un nuevo marco de datos con solo las columnas que necesita:

new_df = df[['spam', 'sausage']]
ccpizza
fuente
2

Podemos eliminar o eliminar una columna especificada o columnas sprcified por el método drop () .

Supongamos que df es un marco de datos.

Columna a eliminar = column0

Código:

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 quítelos mediante el método drop ().

Código:

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

Espero que sea de ayuda.

Littin Rajan
fuente
df = df.drop([col1, col2, . . . , coln], axis=1)esto no funciona si especifico un nombre de variable en lugar de col1, col2, etc. Obtengo la columna de error no en el eje cuando está definitivamente presente. @Littin ¿Podrías ayudarme?
RSM
1

Otra forma de eliminar una columna en Pandas DataFrame

Si no está buscando la eliminación in situ, puede crear un nuevo DataFrame especificando las columnas utilizando 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)

Crear un nuevo DataFrame como

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

Obtiene un resultado tan bueno como el que obtiene con del / drop

Daksh
fuente
1
Esto es técnicamente correcto, pero parece una tontería tener que enumerar todas las columnas para mantener en lugar de solo una (o pocas) columnas que desea eliminar.
cs95