Pandas: obtenga el valor de la primera fila de una columna determinada

300

Esta parece una pregunta ridículamente fácil ... pero no veo la respuesta fácil que esperaba.

Entonces, ¿cómo obtengo el valor en una enésima fila de una columna dada en Pandas? (Estoy particularmente interesado en la primera fila, pero también estaría interesado en una práctica más general).

Por ejemplo, digamos que quiero extraer el valor 1.2 en Btime como variable.

¿Cuál es la forma correcta de hacer esto?

df_test =

  ATime   X   Y   Z   Btime  C   D   E
0    1.2  2  15   2    1.2  12  25  12
1    1.4  3  12   1    1.3  13  22  11
2    1.5  1  10   6    1.4  11  20  16
3    1.6  2   9  10    1.7  12  29  12
4    1.9  1   1   9    1.9  11  21  19
5    2.0  0   0   0    2.0   8  10  11
6    2.4  0   0   0    2.4  10  12  15
Ahmed Haque
fuente
77
Si simplemente quisieras que la primera fila df_test.head(1)funcionara, la forma más general es usar iloccomo respondió unutbu
EdChum
1
¿Quieres solo el valor 1.2? o la serie de longitud 1 con la que obtienes df_test.head(1), que también contendrá el índice? Para obtener solo el valor hacer df_test.head(1).item(), o tolist()luego cortar.
smci

Respuestas:

472

Para seleccionar la ithfila, useiloc :

In [31]: df_test.iloc[0]
Out[31]: 
ATime     1.2
X         2.0
Y        15.0
Z         2.0
Btime     1.2
C        12.0
D        25.0
E        12.0
Name: 0, dtype: float64

Para seleccionar el i-ésimo valor en la Btimecolumna que podría usar:

In [30]: df_test['Btime'].iloc[0]
Out[30]: 1.2

Hay una diferencia entre df_test['Btime'].iloc[0](recomendado) y df_test.iloc[0]['Btime']:

Los marcos de datos almacenan datos en bloques basados ​​en columnas (donde cada bloque tiene un solo tipo de letra). Si primero selecciona por columna, se puede devolver una vista (que es más rápida que devolver una copia) y se conserva el tipo de letra original. Por el contrario, si selecciona primero por fila y si el DataFrame tiene columnas de diferentes tipos, entonces Pandas copia los datos en una nueva Serie de tipos de objetos. Por lo tanto, seleccionar columnas es un poco más rápido que seleccionar filas. Por lo tanto, aunque df_test.iloc[0]['Btime']funciona, df_test['Btime'].iloc[0]es un poco más eficiente.

Hay una gran diferencia entre los dos cuando se trata de asignación. df_test['Btime'].iloc[0] = xafecta df_test, pero df_test.iloc[0]['Btime'] puede que no. Vea a continuación una explicación de por qué. Debido a que una diferencia sutil en el orden de indexación hace una gran diferencia en el comportamiento, es mejor usar una asignación de indexación única:

df.iloc[0, df.columns.get_loc('Btime')] = x

df.iloc[0, df.columns.get_loc('Btime')] = x (recomendado):

La forma recomendada de asignar nuevos valores a un DataFrame es evitar la indexación encadenada y, en su lugar, usar el método mostrado por andrew ,

df.loc[df.index[n], 'Btime'] = x

o

df.iloc[n, df.columns.get_loc('Btime')] = x

El último método es un poco más rápido, ya que df.loctiene que convertir las etiquetas de fila y columna en índices posicionales, por lo que se necesita un poco menos de conversión si se usa df.ilocen su lugar.


df['Btime'].iloc[0] = x funciona, pero no se recomienda:

Aunque esto funciona, está aprovechando la forma en que los marcos de datos se implementan actualmente . No hay garantía de que Pandas tenga que trabajar de esta manera en el futuro. En particular, está aprovechando el hecho de que (actualmente) df['Btime']siempre devuelve una vista (no una copia), por lo que df['Btime'].iloc[n] = xpuede usarse para asignar un nuevo valor en la enésima ubicación de la Btimecolumna de df.

Dado que Pandas no ofrece garantías explícitas sobre cuándo los indexadores devuelven una vista frente a una copia, las asignaciones que utilizan indexación encadenada generalmente siempre generan una SettingWithCopyWarningrespuesta, aunque en este caso la asignación logra modificar df:

In [22]: df = pd.DataFrame({'foo':list('ABC')}, index=[0,2,1])
In [24]: df['bar'] = 100
In [25]: df['bar'].iloc[0] = 99
/home/unutbu/data/binky/bin/ipython:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._setitem_with_indexer(indexer, value)

In [26]: df
Out[26]: 
  foo  bar
0   A   99  <-- assignment succeeded
2   B  100
1   C  100

df.iloc[0]['Btime'] = x No funciona:

En contraste, la asignación con df.iloc[0]['bar'] = 123no funciona porque df.iloc[0]está devolviendo una copia:

In [66]: df.iloc[0]['bar'] = 123
/home/unutbu/data/binky/bin/ipython:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

In [67]: df
Out[67]: 
  foo  bar
0   A   99  <-- assignment failed
2   B  100
1   C  100

Advertencia : previamente había sugerido df_test.ix[i, 'Btime']. Pero esto no está garantizado para darle el ithvalor ya que ixintenta indexar por etiqueta antes de intentar indexar por posición . Entonces, si el DataFrame tiene un índice entero que no está en orden ordenado a partir de 0, entonces usar ix[i]devolverá la fila etiquetada en i lugar de la ithfila. Por ejemplo,

In [1]: df = pd.DataFrame({'foo':list('ABC')}, index=[0,2,1])

In [2]: df
Out[2]: 
  foo
0   A
2   B
1   C

In [4]: df.ix[1, 'foo']
Out[4]: 'C'
unutbu
fuente
1
@CristianCiupitu: los DataFrames almacenan datos en bloques basados ​​en columnas (donde cada bloque tiene un solo tipo de letra). Si selecciona primero por columna, se puede devolver una vista (que es más rápida que devolver una copia) y se conserva el tipo de letra original. Por el contrario, si selecciona primero por fila y si el DataFrame tiene columnas de diferentes tipos, entonces Pandas copia los datos en una nueva Serie de tipos de objetos. Por lo tanto, seleccionar columnas es un poco más rápido que seleccionar filas. Por lo tanto, aunque df_test.iloc[0]['Btime']funciona, df_test.iloc['Btime'][0]es un poco más eficiente.
unutbu
@unutbu, se df['Btime'].iloc[0]prefiere df['Btime'].values[0]? Puedo ver en la documentación que dice "Advertencia: Recomendamos usar Series.array o Series.to_numpy (), dependiendo de si necesita una referencia a los datos subyacentes o una matriz NumPy". pero no estoy seguro exactamente qué significa eso
aydow
28

Tenga en cuenta que la respuesta de @unutbu será correcta hasta que desee establecer el valor en algo nuevo, entonces no funcionará si su marco de datos es una vista.

In [4]: df = pd.DataFrame({'foo':list('ABC')}, index=[0,2,1])
In [5]: df['bar'] = 100
In [6]: df['bar'].iloc[0] = 99
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pandas-0.16.0_19_g8d2818e-py2.7-macosx-10.9-x86_64.egg/pandas/core/indexing.py:118: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._setitem_with_indexer(indexer, value)

Otro enfoque que funcionará consistentemente con la configuración y la obtención es:

In [7]: df.loc[df.index[0], 'foo']
Out[7]: 'A'
In [8]: df.loc[df.index[0], 'bar'] = 99
In [9]: df
Out[9]:
  foo  bar
0   A   99
2   B  100
1   C  100
Andrés
fuente
1
Estoy recorriendo un montón de archivos .csv y leyendo el primer valor de una determinada columna en cada uno. Por alguna razón que no puedo explicar en lugar de devolver el valor, esto a veces devuelve el índice junto con el valor que arruina el procesamiento. Recurrí a df.col.unique () [0].
gorrión
15

Otra forma de hacer esto:

first_value = df['Btime'].values[0]

Esta forma parece ser más rápida que usar .iloc:

In [1]: %timeit -n 1000 df['Btime'].values[20]
5.82 µs ± 142 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [2]: %timeit -n 1000 df['Btime'].iloc[20]
29.2 µs ± 1.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Abdulrahman Bres
fuente
12
  1. df.iloc[0].head(1) - Primer conjunto de datos solo de toda la primera fila.
  2. df.iloc[0] - Toda la primera fila en la columna.
nikhil
fuente
8

De manera general, si desea recoger las primeras N filas de la columna J de pandas dataframela mejor manera de hacer esto es:

data = dataframe[0:N][:,J]
anis
fuente
2
@anis: Para este propósito, habría sido mejor escribir una nueva pregunta solicitando la solución más general y respondiendo por su cuenta, creo.
jonathan.scholbach
3

Para obtener, por ejemplo, el valor de la columna 'prueba' y la fila 1, funciona como

df[['test']].values[0][0]

ya que solo df[['test']].values[0]devuelve una matriz

Alex Ortner
fuente
1

Otra forma de obtener la primera fila y preservar el índice:

x = df.first('d') # Returns the first day. '3d' gives first three days.
Hunaphu
fuente