Seleccionar varias columnas en un marco de datos de Pandas

1429

Tengo datos en diferentes columnas, pero no sé cómo extraerlos para guardarlos en otra variable.

index  a   b   c
1      2   3   4
2      3   4   5

¿Cómo selecciono 'a', 'b'y guardarlo en que gl1?

Lo intenté

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

Ninguno parece funcionar.

5
  • 4
    Nunca querrás usarlo .ixya que es ambiguo. Utilice .iloco .locsi debe hacerlo. 12/07/17 a las 17:14
  • 1
    ¿Hay alguna forma de hacerlo sin hacer referencia a los nombres de los encabezados? como en R, puedo hacerlo así: > csvtable_imp_1 <- csvtable_imp[0:6]y selecciona la cantidad delta de las primeras columnas entre 0 y 6. Todo lo que tenía que hacer era leer la tabla csv como delimitada con la librería readr. 19 oct 2018 a las 0:30
  • He trabajado un poco más con eso. Encontré algo que funcionó como quería. El valor predeterminado es seleccionar números de caracteres y no columnas.infile_1 = largefile_stay.ix[:,0:6] 19/10/18 a las 0:43
  • 4
    Para aquellos que se tropiezan con esto tarde, ixahora está en desuso. Pandas recomienda usar: loc(indexación basada en etiquetas) o iloc(indexación basada en la posición).
    ZaydH
    4 dic 2018 a las 16:20
  • 1
    Pandas: Reemplazo para .ix
    Connor
    24/03/19 a las 20:18
2217

Los nombres de las columnas (que son cadenas) no se pueden dividir de la manera que intentó.

Aquí tienes un par de opciones. Si sabe por el contexto qué variables desea dividir, puede devolver una vista solo de esas columnas pasando una lista a la __getitem__sintaxis (las []).

df1 = df[['a', 'b']]

Alternativamente, si es importante indexarlos numéricamente y no por su nombre (digamos que su código debería hacer esto automáticamente sin conocer los nombres de las dos primeras columnas), entonces puede hacer esto en su lugar:

df1 = df.iloc[:, 0:2] # Remember that Python does not slice inclusive of the ending index.

Además, debe familiarizarse con la idea de una vista en un objeto Pandas frente a una copia de ese objeto. El primero de los métodos anteriores devolverá una nueva copia en la memoria del subobjeto deseado (los cortes deseados).

A veces, sin embargo, existen convenciones de indexación en Pandas que no hacen esto y, en cambio, le brindan una nueva variable que solo se refiere a la misma porción de memoria que el subobjeto o segmento en el objeto original. Esto sucederá con la segunda forma de indexación, por lo que puede modificarla con el .copy()método para obtener una copia regular. Cuando esto sucede, cambiar lo que cree que es el objeto cortado a veces puede alterar el objeto original. Siempre es bueno estar atento a esto.

df1 = df.iloc[0, 0:2].copy() # To avoid the case where changing df1 also changes df

Para usarlo iloc, debe conocer las posiciones de las columnas (o índices). Como las posiciones de las columnas pueden cambiar, en lugar de los índices de codificación rígida, puede utilizar ilocjunto con la get_locfunción del columnsmétodo del objeto de marco de datos para obtener índices de columna.

{df.columns.get_loc(c): c for idx, c in enumerate(df.columns)}

Ahora puede usar este diccionario para acceder a columnas a través de nombres y usando iloc.

20
  • 245
    Nota: df[['a','b']]produce una copia 8/07/12 a las 17:54
  • 1
    Sí, esto estaba implícito en mi respuesta. La parte sobre la copia fue solo para usar ix[]si prefiere usarla ix[]por cualquier motivo.
    ely
    8 de julio de 12 a las 18:09
  • 11
    ixacepta argumentos de corte, por lo que también puede obtener columnas. Por ejemplo, df.ix[0:2, 0:2]obtiene la submatriz 2x2 superior izquierda tal como lo hace para una matriz NumPy (dependiendo de los nombres de sus columnas, por supuesto). Incluso puede usar la sintaxis de sector en los nombres de cadena de las columnas, como df.ix[0, 'Col1':'Col5']. Eso obtiene todas las columnas que están ordenadas entre Col1y Col5en la df.columnsmatriz. Es incorrecto decir que ixindexa filas. Ese es solo su uso más básico. También admite mucha más indexación que eso. Entonces, ixes perfectamente general para esta pregunta.
    ely
    31/10/12 a las 19:02
  • 7
    @AndrewCassidy Nunca vuelva a usar .ix. Si desea dividir con números enteros, use .ilocque sea exclusivo de la última posición, al igual que las listas de Python. 1 de julio de 2017 a las 13:55
  • 5
    @ dte324 Si su DataFrame tiene un nombre df, use df.iloc[:, [1, 4]]. Por lo general, si desea este tipo de patrón de acceso, ya conocerá estos nombres de columna en particular, y puede usar df.loc[:, ['name2', 'name5']]dónde 'name2'y 'name5'son los nombres de cadena de sus columnas para las columnas respectivas que desea, o buscar los nombres con, por ejemplo name2 = df.columns[1].
    ely
    12/09/19 a las 12:19
198

A partir de la versión 0.11.0, las columnas se pueden dividir de la manera que intentó usar el .locindexador:

df.loc[:, 'C':'E']

es equivalente a

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

y devuelve columnas a Ctravés de E.


Una demostración de un DataFrame generado aleatoriamente:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)),
                  columns=list('ABCDEF'),
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out:
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

Para obtener las columnas de C a E (tenga en cuenta que, a diferencia de la división de enteros, 'E' se incluye en las columnas):

df.loc[:, 'C':'E']

Out:
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

Lo mismo funciona para seleccionar filas basadas en etiquetas. Obtenga las filas 'R6' a 'R10' de esas columnas:

df.loc['R6':'R10', 'C':'E']

Out:
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.loctambién acepta una matriz booleana para que pueda seleccionar las columnas cuya entrada correspondiente en la matriz es True. Por ejemplo, df.columns.isin(list('BCD'))devuelve array([False, True, True, True, False, False], dtype=bool)- Verdadero si el nombre de la columna está en la lista ['B', 'C', 'D']; Falso, de lo contrario.

df.loc[:, df.columns.isin(list('BCD'))]

Out:
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...
1
  • df.loc [:, 'C': 'E'] esta es la respuesta exacta que estaba buscando. Estaba poniendo la C y la E en otro soporte, fue mi error. Gracias
    JQTs
    24 de junio a las 20:18
128

Suponiendo que los nombres de sus columnas ( df.columns) están ['index','a','b','c'], entonces los datos que desea están en la tercera y cuarta columnas. Si no conoce sus nombres cuando se ejecuta su script, puede hacer esto

newdf = df[df.columns[2:4]] # Remember, Python is zero-offset! The "third" entry is at slot two.

Como señala EMS en su respuesta , df.ixdivide las columnas de manera un poco más concisa, pero la .columnsinterfaz de corte podría ser más natural, porque utiliza la sintaxis de indexación / corte de lista de Python unidimensional de vainilla.

Advertencia :'index'es un mal nombre para unaDataFramecolumna. Esa misma etiqueta también se usa para eldf.indexatributoreal, unaIndexmatriz. Entonces su columna es devuelta pordf['index']y el índice de DataFrame real es devuelto pordf.index. AnIndexes un tipo especial deSeriesoptimización para la búsqueda de los valores de sus elementos. Para df.index, es para buscar filas por su etiqueta. Esedf.columnsatributo también es unapd.Indexmatriz, para buscar columnas por sus etiquetas.

5
  • 3
    Como señalé en mi comentario anterior, no.ix es solo para filas. Es para corte de propósito general y puede usarse para corte multidimensional. Básicamente es solo una interfaz para la sintaxis habitual de NumPy . Dicho esto, se puede convertir fácilmente en un problema de columna sobre el tramo en un problema fila sobre el tramo aplicando sólo una operación de transposición, . Su ejemplo usa , que es un poco engañoso. El resultado de es a ; tenga cuidado de no tratarlo simplemente como una matriz. Además, probablemente debería cambiarlo para que coincida con su comentario "3º y 4º".__getitem__df.Tcolumns[1:3]columnsSeriescolumns[2:3]
    ely
    31/10/12 a las 19:11
  • @ Mr.F: Mi [2:4]es correcto. Tu [2:3]esta mal. Y el uso de la notación de corte de Python estándar para generar una secuencia / Serie no es engañoso en mi opinión. Pero me gusta su omisión de la interfaz DataFrame para acceder a la matriz numpy subyacente con ix.
    hobs
    4 de febrero de 2016 a las 17:26
  • Tiene razón en este caso, pero el punto que estaba tratando de hacer es que, en general, el corte con etiquetas en Pandas incluye el punto final del corte (o al menos este era el comportamiento en la mayoría de las versiones anteriores de Pandas). Entonces, si lo recupera df.columnsy desea dividirlo por etiqueta , entonces tendrá una semántica de segmento diferente que si lo dividiera por posición de índice entero . Sin embargo, definitivamente no lo expliqué bien en mi comentario anterior.
    ely
    4 de febrero de 2016 a las 18:05
  • Ahh, ahora veo tu punto. Olvidé que columnses una Serie inmutable y que el captador ha sido anulado para usar etiquetas como índices. Gracias por tomarse el tiempo para aclarar.
    hobs
    5 de febrero de 2016 a las 0:17
  • 2
    Tenga en cuenta la advertencia de obsolescencia: .ix está obsoleto. Por lo tanto, esto tiene sentido: newdf = df [df.columns [2: 4]] 1 de julio de 2017 a las 23:57
80

En la última versión de Pandas, hay una manera fácil de hacer exactamente esto. Los nombres de las columnas (que son cadenas) se pueden dividir de la manera que desee.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)
4
  • 9
    Esto solo se puede hacer en la creación. La pregunta es preguntar si ya lo tiene en un marco de datos. 28 nov 2017 a las 7:05
  • df1 = df.iloc[:, columns] funciona cuando ya tiene el marco de datos. 13 de febrero a las 10:26
  • Y esta interfaz de creación para crear nombres de columnas siempre ha estado ahí.
    hobs
    23 de agosto a las 22:41
  • @ BálintSass y si ya conoce los nombres de las columnas en lugar de solo su posición entera (índice).
    hobs
    23 de agosto a las 22:42
71
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5
3
  • 1
    ¿Qué pasa si quisiera cambiar el nombre de la columna, por ejemplo algo como: df[['b as foo', 'c as bar']tal que la salida cambie el nombre de la columna bcomo fooy la columna ccomo bar?
    kuanb
    14 feb 2017 a las 20:30
  • 6
    df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
    Greg
    25 de agosto de 2017 a las 22:48
  • Una explicación estaría en orden. Por ejemplo, ¿cuál es la esencia? Puede editar su respuesta , sin "Editar:", "Actualizar:" o similar, la respuesta debería aparecer como si estuviera escrita hoy. 8 de febrero a las 14:55
48

Con pandas

nombres de columna de ingenio

dataframe[['column1','column2']]

para seleccionar por iloc y columnas específicas con número de índice:

dataframe.iloc[:,[1,2]]

con nombres de columna loc se puede utilizar como

dataframe.loc[:,['column1','column2']]
27

Puede proporcionar una lista de columnas que se eliminarán y devolver el DataFrame con solo las columnas necesarias utilizando la drop()función en un Pandas DataFrame.

Solo digo

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

devolvería un DataFrame con solo las columnas by c.

El dropmétodo está documentado aquí .

24

Encontré este método muy útil:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

Puede encontrar más detalles aquí .

2
  • ¿Cómo tomaría, digamos, solo las columnas 2 y 5?
    324
    12/09/19 a las 1:40
  • 2
    Eso sería surveys_df.iloc [:, [2,5]]entonces. 3 oct 2019 a las 8:43
24

A partir de 0.21.0, el uso .loco []con una lista con una o más etiquetas faltantes está obsoleto en favor de .reindex. Entonces, la respuesta a tu pregunta es:

df1 = df.reindex(columns=['b','c'])

En versiones anteriores, el uso .loc[list-of-labels]funcionaría siempre que se encontrara al menos una de las claves (de lo contrario, generaría un KeyError). Este comportamiento está obsoleto y ahora muestra un mensaje de advertencia. La alternativa recomendada es utilizar .reindex().

Obtenga más información en Indexación y selección de datos .

19

Puede usar el pandas.DataFrame.filtermétodo para filtrar o reordenar columnas como esta:

df1 = df.filter(['a', 'b'])

Esto también es muy útil cuando está encadenando métodos.

2
  • 2
    filteres genial y no tan conocido como debería ser. En particular, también se puede utilizar expresiones regulares como este: df.filter(regex='a|b'). Tengo un ejemplo más largo en una respuesta a esta pregunta: stackoverflow.com/questions/29241836/…
    JohnE
    26 feb a las 15:48
  • 2
    El filtro también puede ignorar las columnas que no existen en la "lista de elementos = ..", lo que a veces es muy útil. 29 mar a las 14:50
14

Puedes usar Pandas.

Creo el DataFrame:

import pandas as pd
df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]],
                  index=['Jane', 'Peter','Alex','Ann'],
                  columns=['Test_1', 'Test_2', 'Test_3'])

El DataFrame:

       Test_1  Test_2  Test_3
Jane        1       2       5
Peter       5       4       5
Alex        7       7       8
Ann         7       6       9

Para seleccionar una o más columnas por nombre:

df[['Test_1', 'Test_3']]

       Test_1  Test_3
Jane        1       5
Peter       5       5
Alex        7       8
Ann         7       9

También puedes usar:

df.Test_2

Y obtienes columna Test_2:

Jane     2
Peter    4
Alex     7
Ann      6

También puede seleccionar columnas y filas de estas filas usando .loc(). A esto se le llama "rebanar" . Observe que tomo de la columna Test_1a Test_3:

df.loc[:, 'Test_1':'Test_3']

El "Slice" es:

       Test_1  Test_2  Test_3
Jane        1       2       5
Peter       5       4       5
Alex        7       7       8
Ann         7       6       9

Y si solo quieres Petery Annde columnas Test_1y Test_3:

df.loc[['Peter', 'Ann'], ['Test_1', 'Test_3']]

Usted obtiene:

       Test_1  Test_3
Peter       5       5
Ann         7       9
10

Si desea obtener un elemento por índice de fila y nombre de columna, puede hacerlo como df['b'][0]. Es tan simple como te puedas imaginar.

O puede usar df.ix[0,'b']: uso mixto de índice y etiqueta.

Nota: Desde v0.20, ixha quedado obsoleto en favor de loc/ iloc.

8

Un enfoque diferente y sencillo: iterar filas

Usando iterows

 df1 = pd.DataFrame() # Creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index, 'A'] = df.loc[index, 'A']
    df1.loc[index, 'B'] = df.loc[index, 'B']
    df1.head()
3
  • 8
    No recomiende el uso de iterrows (). Es un habilitador flagrante del peor anti-patrón en la historia de los pandas.
    cs95
    9 de junio de 2019 a las 3:49
  • ¿Podría explicar qué quiere decir con "peor antipatrón"?
    Ankita
    9/06/19 a las 19:41
  • 2
    En mi humilde opinión, iterrows () debería ser la última opción al usar pandas.
    Elf
    16/08/19 a las 14:07
7
df[['a', 'b']]  # Select all rows of 'a' and 'b'column 
df.loc[0:10, ['a', 'b']]  # Index 0 to 10 select column 'a' and 'b'
df.loc[0:10, 'a':'b']  # Index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5]  # Index 0 to 10 and column 3 to 5
df.iloc[3, 3:5]  # Index 3 of column 3 to 5
1
  • Debería estar df.loc[0:10, 'a':'b']en la tercera fila. Lo acabo de editar. 10/10/20 a las 1:35
6

Los diferentes enfoques discutidos en las respuestas anteriores se basan en la suposición de que el usuario conoce los índices de columna para colocar o subconjuntos, o el usuario desea subconjuntos de un marco de datos utilizando un rango de columnas (por ejemplo, entre 'C': 'E' ).

pandas.DataFrame.drop () es sin duda una opción a los datos de subconjuntos en base a una lista de columnas definidas por el usuario (aunque hay que tener cuidado de utilizar siempre copia de trama de datos y InPlace parámetros no se debe establecer en Verdadero !!)

Otra opción es usar pandas.columns.difference () , que establece una diferencia en los nombres de las columnas y devuelve un tipo de índice de matriz que contiene las columnas deseadas. La siguiente es la solución:

df = pd.DataFrame([[2,3,4], [3,4,5]], columns=['a','b','c'], index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

La salida sería:

    b   c
1   3   4
2   4   5
1
  • 1
    La copia () no es necesaria. es decir: df1 = df[df.columns.difference(columns_for_differencing)]devolverá un marco de datos nuevo / copiado. Podrás modificar df1sin alterar df. Gracias, por cierto. Esto era exactamente lo que necesitaba. 8/08/18 a las 17:20
6

Intente usar pandas.DataFrame.get(consulte la documentación ):

import pandas as pd
import numpy as np

dates = pd.date_range('20200102', periods=6)
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))
df.get(['A', 'C'])
5

También puede usar df.pop () :

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

Utilice df.pop(c).

3

Para seleccionar varias columnas, extráigalas y visualícelas a partir de entonces: dfse denominó anteriormente marco de datos, luego cree un nuevo marco de datos df1y seleccione las columnas A a D que desea extraer y ver.

df1 = pd.DataFrame(data_frame, columns=['Column A', 'Column B', 'Column C', 'Column D'])
df1

¡Se mostrarán todas las columnas obligatorias!

3

He visto varias respuestas al respecto, pero una no me quedó clara. ¿Cómo seleccionaría esas columnas de interés?

La respuesta a eso es que si los tiene reunidos en una lista, puede simplemente hacer referencia a las columnas usando la lista.

Ejemplo

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

Tengo la siguiente lista / matriz NumPy extracted_features, especificando 63 columnas. El conjunto de datos original tiene 103 columnas, y me gustaría extraer exactamente esas, luego usaría

dataset[extracted_features]

Y terminarás con esto

Ingrese la descripción de la imagen aquí

Esto es algo que usaría con bastante frecuencia en el aprendizaje automático (más específicamente, en la selección de funciones). También me gustaría discutir otras formas, pero creo que eso ya ha sido cubierto por otros usuarios de Stack Overflower.

2
def get_slize(dataframe, start_row, end_row, start_col, end_col):
    assert len(dataframe) > end_row and start_row >= 0
    assert len(dataframe.columns) > end_col and start_col >= 0
    list_of_indexes = list(dataframe.columns)[start_col:end_col]
    ans = dataframe.iloc[start_row:end_row][list_of_indexes]
    return ans

Solo usa esta función

2

Para excluir algunas columnas, puede colocarlas en el índice de columnas. Por ejemplo:

   A   B    C     D
0  1  10  100  1000
1  2  20  200  2000

Seleccione todas las columnas excepto una:

df[df.columns.drop('C')]

Producción:

   A   B     D
0  1  10  1000
1  2  20  2000

Seleccione todos excepto dos:

df[df.columns.drop(['B', 'D'])]

Producción:

   A    C
0  1  100
1  2  200