Cómo tomar secciones de columna de marco de datos en pandas


264

Cargo algunos datos de aprendizaje automático de un archivo CSV. Las primeras 2 columnas son observaciones y las columnas restantes son características.

Actualmente, hago lo siguiente:

data = pandas.read_csv('mydata.csv')

que da algo como:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Me gustaría cortar esta trama de datos en dos tramas de datos: una que contiene las columnas ay by uno que contiene las columnas c, dye .

No es posible escribir algo como

observations = data[:'c']
features = data['c':]

No estoy seguro de cuál es el mejor método. ¿Necesito unpd.Panel ?

Por cierto, la indexación de marcos de datos me parece bastante inconsistente: data['a']está permitido, pero data[0]no lo está. Por otro lado, data['a':]no está permitido pero sí data[0:]. ¿Hay alguna razón práctica para esto? Esto es realmente confuso si las columnas son indexadas por Int, dado quedata[0] != data[0:1]


3
DataFrame es inherentemente un objeto tipo dict cuando hace df, [...] sin embargo, df[5:10]se agregaron algunas comodidades, por ejemplo, para seleccionar filas ( pandas.pydata.org/pandas-docs/stable/… )
Wes McKinney

1
Entonces, ¿qué es esta inconsistencia es una decisión de diseño a favor de la conveniencia? Muy bien, ¡pero definitivamente debe ser más explícito para los principiantes!
cpa

3
La consideración de diseño de la conveniencia de soporte hace que la curva de aprendizaje sea muy empinada. Deseo que haya una mejor documentación para el comienzo simplemente presentando una interfaz consistente. Por ejemplo, solo enfóquese en la interfaz ix.
Yu Shen

Respuestas:


243

Respuesta 2017 - pandas 0.20: .ix está en desuso. Usa .loc

Ver la desaprobación en los documentos

.locusa indexación basada en etiquetas para seleccionar tanto filas como columnas. Las etiquetas son los valores del índice o las columnas. Cortar con .locincluye el último elemento.

Vamos a suponer que tenemos una trama de datos con las siguientes columnas:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locacepta la misma notación de corte que las listas de Python para las filas y las columnas. Ser notación de rebanadastart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Puede cortar por filas y columnas. Por ejemplo, si usted tiene 5 filas con etiquetas v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y

si está utilizando aplicar con fila lambda, como en: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) entonces puede en myfunc(row){... usar row['foo':'ant']. por ejemplo (de acuerdo con esta respuesta de StackOverflow ), dentro de la myfuncpuede evaluar si alguno de estos no es numérico:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
pashute

44
.ilocdebe usarse ahora, en lugar de .loc. Arregla eso, y lo votaré.
Craned

1
@craned: eso no es correcto. De la documentación de Pandas: .loc se basa principalmente en etiquetas, pero también se puede usar con una matriz booleana. .loc generará KeyError cuando no se encuentren los elementos. Se hace una declaración similar sobre .iloc, excepto que se refiere específicamente a la división basada en índices. En otras palabras, en este ejemplo, utilizó indexación basada en etiquetas y .loc es la opción correcta (básicamente la única opción). Si desea cortar por posición, por ejemplo, 5:10, use .iloc
user2103050

149

Nota: .ix ha quedado en desuso desde Pandas v0.20. En su lugar, debe usar .loco .iloc, según corresponda.

El índice DataFrame.ix es a lo que desea acceder. Es un poco confuso (estoy de acuerdo en que la indexación de Pandas es desconcertante a veces), pero lo siguiente parece hacer lo que quieres:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

donde .ix [segmento de fila, segmento de columna] es lo que se está interpretando. Más información sobre la indexación de Pandas aquí: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


55
Cuidado que los rangos en los pandas incluyen ambos puntos finales, es decir>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
saltamontes

21
Se pueden pasar varias columnas de esta maneradf.ix[:,[0,3,4]]
user602599

3
@ Karmel: Parece un error de copiar / pegar en el resultado anterior. Quizás quisiste decir df.ix[:,'b':'e']?
ChaimG

66
Es mejor usar en loclugar de ix: stackoverflow.com/a/31593712/4323
John Zwinck

55
Las respuestas antiguas como esta deben eliminarse. .ix está en desuso y nunca debe usarse.
Ted Petrou

75

Usemos el conjunto de datos titánico del paquete seaborn como ejemplo

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

usando los nombres de columna

>> titanic.loc[:,['sex','age','fare']]

usando los índices de columna

>> titanic.iloc[:,[2,3,6]]

usando ix (versión anterior a Pandas <.20)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

o

>> titanic.ix[:,[2,3,6]]

utilizando el método reindex

>> titanic.reindex(columns=['sex','age','fare'])

66
En pandas 0.20: .ixestá en desuso.
Shihe Zhang

advertencia de desaprobación: Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.cuando usadf.loc[:, some_list_of_columns]
Marc Maxmeister

35

Además, dado un marco de datos

datos

como en su ejemplo, si desea extraer la columna ayd solamente (es decir, la 1ra y la 4ta columna), iloc mothod del marco de datos de pandas es lo que necesita y podría usarse de manera muy efectiva. Todo lo que necesita saber es el índice de las columnas que desea extraer. Por ejemplo:

>>> data.iloc[:,[0,3]]

Te regalaré

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476

25

Puede dividir las columnas de a DataFramehaciendo referencia a los nombres de cada columna en una lista, así:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]

Entonces, si quiero todos los datos a partir de la columna 'b', ¿necesito encontrar el índice de 'b' en data.columns y hacer data [data.columns [1:]]? ¿Esa es la forma canónica de operar?
cpa

1
¿Quiere decir que desea seleccionar todas las columnas desde 'b' en adelante?
Brendan Wood

Sí, o seleccionando todas las columnas en un rango dado.
cpa

Soy bastante nuevo para los pandas, así que no puedo hablar sobre lo que se considera canónico. Lo haría como dijiste, pero usa la get_locfunción data.columnspara determinar el índice de la columna 'b' o lo que sea.
Brendan Wood

20

Y si viniste aquí buscando cortar dos rangos de columnas y combinarlas (como yo), puedes hacer algo como

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Esto creará un nuevo marco de datos con las primeras 900 columnas y (todas) las columnas> 3593 (suponiendo que tenga unas 4000 columnas en su conjunto de datos).


Genial, alguien ha probado esto ... Me preguntaba, este 0: 899 que obtiene las primeras 900 columnas ... ¿por qué lo hicieron así? Esto no se siente como Python en absoluto. Cuando se usan rangos en python, siempre es 'hasta' no 'hasta e incluido'
zwep

14

A continuación, le mostramos cómo puede utilizar diferentes métodos para dividir en columnas de forma selectiva, incluidas la división selectiva de columnas basada en etiquetas, índices y rangos selectivos.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

Intente evitar simplemente descargar el código como respuesta e intente explicar qué hace y por qué. Es posible que su código no sea obvio para las personas que no tienen la experiencia de codificación relevante. Edite su respuesta para incluir aclaraciones, contexto e intente mencionar cualquier limitación, suposición o simplificación en su respuesta.
Sᴀᴍ Onᴇᴌᴀ

1

Su equivalente

 >>> print(df2.loc[140:160,['Relevance','Title']])
 >>> print(df2.ix[140:160,[3,7]])

1

si el marco de datos se ve así:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

y SALIDA podría ser como

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

si usa el operador lógico np.logical_not

df[np.logical_not(df['group'] == 'vegetable')]

más sobre

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

otros operadores lógicos

  1. logical_and (x1, x2, / [, out, where, ...]) Calcule el valor de verdad de x1 AND x2 por elementos.

  2. logical_or (x1, x2, / [, out, where, casting, ...]) Calcule el valor de verdad de x1 OR x2 por elementos.

  3. logical_not (x, / [, out, where, casting, ...]) Calcule el valor de verdad de NOT x en cuanto al elemento.
  4. logical_xor (x1, x2, / [, out, where, ..]) Calcule el valor de verdad de x1 XOR x2, por elementos.

0

Otra forma de obtener un subconjunto de columnas de su DataFrame, suponiendo que desea todas las filas, sería hacer:
data[['a','b']]y data[['c','d','e']]
si desea usar índices numéricos de columna, puede hacer:
data[data.columns[:2]]ydata[data.columns[2:]]

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.