Seleccionar múltiples columnas en un marco de datos de pandas

1113

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.

usuario1234440
fuente
2
Nunca querrás usarlo .ixya que es ambiguo. Use .iloco .locsi debe hacerlo.
Acumenus
1
¿Hay alguna manera de hacerlo sin hacer referencia a los nombres de encabezado? 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 tuve que hacer es leer la tabla csv como delimitada con el libr readr.
MichaelR
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]
MichaelR
3
Para aquellos que tropiezan con este retraso, ixahora está en desuso. Pandas recomienda usar: loc(indexación basada en etiquetas) o iloc(indexación basada en posición).
ZaydH

Respuestas:

1772

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

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

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

Alternativamente, si es importante indexarlos numéricamente y no por su nombre (digamos que su código debe hacer esto automáticamente sin conocer los nombres de las dos primeras columnas), puede hacerlo 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 de un objeto Pandas versus una copia de ese objeto. El primero de los métodos anteriores devolverá una nueva copia en memoria del subobjeto deseado (los segmentos deseados).

A veces, sin embargo, hay convenciones de indexación en Pandas que no hacen esto y, en cambio, le dan una nueva variable que solo se refiere al mismo fragmento de memoria que el subobjeto o el segmento en el objeto original. Esto sucederá con la segunda forma de indexación, por lo que puede modificarlo con la copy()función para obtener una copia regular. Cuando esto sucede, cambiar lo que crees 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 columna (o índices). Como las posiciones de las columnas pueden cambiar, en lugar de los índices de codificación rígida, puede usar ilocjunto con la get_locfunción del columnsmétodo del objeto de marco de datos para obtener índices de columnas.

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

Ahora puede usar este diccionario para acceder a las columnas a través de los nombres y el uso iloc.

ely
fuente
192
Nota: df[['a','b']]produce una copia
Wes McKinney
1
Sí, esto estaba implícito en mi respuesta. Lo de la copia era sólo para uso de ix[]si usted prefiere utilizar ix[]por cualquier razón.
ely
1
ixindexa filas, no columnas. Pensé que el OP quería columnas.
placas el
99
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 al igual que lo hace para una matriz NumPy (dependiendo de los nombres de las columnas, por supuesto). Incluso puede usar la sintaxis de corte 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
77
@ AndrewCassidy Nunca vuelva a usar .ix. Si desea dividir con enteros, use el .ilocque es exclusivo de la última posición al igual que las listas de Python.
Ted Petrou
133

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 E.


Una demostración en 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, se incluye 'E' 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
...
ayhan
fuente
110

Suponiendo que los nombres de sus columnas ( df.columns) son ['index','a','b','c'], entonces los datos que desea están en las columnas 3ra y 4ta. Si no conoce sus nombres cuando se ejecuta su script, puede hacerlo

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

Como EMS señala en su respuesta , df.ixcorta las columnas un poco más concisamente, pero el.columns interfaz de corte podría ser más natural porque usa la sintaxis de indexación / corte de lista de python vainilla 1-D.

WARN: 'index'es un mal nombre para una DataFramecolumna. Esa misma etiqueta también se usa para el df.indexatributo real , una Indexmatriz. Entonces su columna es devuelta por df['index']y el índice real de DataFrame es devuelto por df.index. Un Indexes un tipo especial de Seriesoptimización para la búsqueda de los valores de sus elementos. Para df.index es para buscar filas por su etiqueta. Ese df.columnsatributo también es una pd.Indexmatriz, para buscar columnas por sus etiquetas.

placas
fuente
3
Como señalé en mi comentario anterior, no.ix es solo para filas. Es para rebanar de propósito general, y puede usarse para rebanar 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 , lo cual 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
@ Mr.F: Mi [2:4]es correcto. Tu [2:3]está equivocado. Y el uso de la notación de corte estándar de Python para generar una secuencia / Serie no es engañoso en mi opinión. Pero me gusta que evite la interfaz DataFrame para acceder a la matriz numpy subyacente ix.
placas
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 recupera df.columnsy desea dividirlo por etiqueta , entonces tendría una semántica de corte diferente que si lo corta por posición de índice entero . Sin embargo, definitivamente no lo expliqué bien en mi comentario anterior.
ely
Ahh, ahora entiendo tu punto. Olvidé que columnses una Serie inmutable y el getter ha sido anulado para usar etiquetas como índices. Gracias por tomarte el tiempo de aclarar.
placas
2
Tenga en cuenta la Advertencia de desuso: .ix está en desuso. Por lo tanto, esto tiene sentido: newdf = df [df.columns [2: 4]]
Martien Lubberink
64
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
Wes McKinney
fuente
1
¿Qué pasa si yo quería cambiar el nombre de la columna, por ejemplo, algo como: df[['b as foo', 'c as bar']tal que la salida cambia el nombre de la columna bcomo fooy la columna ccomo bar?
kuanb
55
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
Greg
62

Me doy cuenta de que esta pregunta es bastante antigua, pero en la última versión de pandas hay una manera fácil de hacer exactamente esto. Los nombres de columna (que son cadenas) se pueden dividir de la forma que desee.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)
vector cero
fuente
66
Esto solo se puede hacer en la creación. La pregunta es preguntar si ya lo tiene en un marco de datos.
Banjocat
3
@Banjocat, funciona con un marco de datos existente
mhery
23

Puede proporcionar una lista de columnas para descartar y devolver el DataFrame con solo las columnas necesarias utilizando el drop() función en un Pandas DataFrame.

Solo digo

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

devolvería un DataFrame con solo las columnas byc .

El dropmétodo está documentado aquí .

Muthu Chithambara Jothi
fuente
23

Con pandas

nombres de columnas ingeniosas

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

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

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

con los nombres de columna loc se pueden usar como

dataframe.loc[:,['column1','column2']]
Vivek Ananthan
fuente
20

Encontré este método muy útil:

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

Más detalles se pueden encontrar aquí

Alvis
fuente
¿Cómo tomaría, digamos, solo las columnas 2 y 5?
324
1
Eso sería surveys_df.iloc [:, [2,5]]entonces.
Julian Gorfer el
15

A partir de 0.21.0, el uso de .loco []con una lista con una o más etiquetas faltantes está en desuso a favor de .reindex. Entonces, la respuesta a su 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 1 de las claves (de lo contrario, generaría a KeyError). Este comportamiento está en desuso y ahora muestra un mensaje de advertencia. La alternativa recomendada es usar .reindex().

Lea más en Indización y selección de datos

tozCSS
fuente
10

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 1 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 tu consigues columna Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

También puede seleccionar columnas y filas de estas filas usando .loc(). Esto se llama "rebanar" . Tenga en cuenta que tomo de la columna Test_1aTest_3

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

La "rebanada" 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 Anndesde 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
pink.slash
fuente
8

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

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

Nota: Desde v0.20 ixha quedado en desuso a favor de loc/ iloc.

W.Perrin
fuente
6

Un enfoque diferente y fácil: 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()
Ankita
fuente
55
Por favor no recomiende el uso de iterrows (). Es un facilitador flagrante del peor antipatrón en la historia de los pandas.
cs95
¿Podría explicar qué quiere decir con "peor antipatrón"?
Ankita
1
En mi humilde opinión, iterrows () debería ser la última opción cuando se usan pandas.
Elfo
5

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 subconjunto, o el usuario desea subconjugar un marco de datos utilizando un rango de columnas (por ejemplo, entre 'C': 'E') . pandas.DataFrame.drop () es ciertamente una opción para subconjunto de datos en base a una lista de columnas definidas por el usuario (¡aunque debe tener cuidado de que siempre use una copia del marco de datos y los parámetros in situ no deben establecerse en True !)

Otra opción es usar pandas.columns.difference () , que marca una diferencia en los nombres de columna y devuelve un tipo de matriz de índice 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)

El resultado sería: b c 1 3 4 2 4 5

Harshit
fuente
1
La copia () no es necesaria. es decir: df1 = df[df.columns.difference(columns_for_differencing)]devolverá un marco de datos nuevo / copiado. Podrá modificar df1sin alterar df. Gracias, por cierto. Esto era exactamente lo que necesitaba.
Bazyli Debowski
4

también puedes 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

avíseme si esto le ayuda, por favor use df.pop (c)

Puneet Sinha
fuente
3

He visto varias respuestas sobre eso, pero no me quedó claro. ¿Cómo seleccionarías esas columnas de interés? La respuesta a eso es que si los tiene reunidos en una lista, puede 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, que especifica 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 Machine Learning (más específicamente, en la selección de funciones). Me gustaría discutir otras formas también, pero creo que eso ya ha sido cubierto por otros stackoverflowers. ¡Espero que esto haya sido útil!

Kareem Jeiroudi
fuente
2

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

df1 = df.filter(['a', 'b'])
Ramin Melikov
fuente
0
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
Biplob Das
fuente