Obtener el valor de la primera fila de una columna determinada
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 determinada en Pandas? (Estoy particularmente interesado en la primera fila, pero también me interesaría una práctica más general).
Por ejemplo, digamos que quiero introducir el valor 1,2 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
Para seleccionar la ith
fila, utiliceiloc
:
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 Btime
columna, puede 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 DataFrames almacenan datos en bloques basados en columnas (donde cada bloque tiene un único tipo). Si selecciona primero por columna, se puede devolver una vista (que es más rápido 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, Pandas copia los datos en una nueva serie de tipo de objeto. Entonces, seleccionar columnas es un poco más rápido que seleccionar filas. Así, aunque
df_test.iloc[0]['Btime']
funciona, df_test['Btime'].iloc[0]
es un poquito más eficiente.
Hay una gran diferencia entre los dos cuando se trata de asignación.
df_test['Btime'].iloc[0] = x
afecta df_test
, pero df_test.iloc[0]['Btime']
puede que no. Consulte a continuación una explicación del por qué. Debido a que una diferencia sutil en el orden de indexación genera una gran diferencia en el comportamiento, es mejor utilizar 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, utilizar 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, porque df.loc
tiene que convertir las etiquetas de filas y columnas en índices posicionales, por lo que se necesita un poco menos de conversión si lo usa
df.iloc
en su lugar.
df['Btime'].iloc[0] = x
Funciona, pero no se recomienda:
Aunque esto funciona, aprovecha la forma en que se implementan actualmente los DataFrames . No hay garantía de que Pandas tenga que funcionar de esta manera en el futuro. En particular, aprovecha el hecho de que (actualmente) df['Btime']
siempre devuelve una vista (no una copia), por lo que df['Btime'].iloc[n] = x
puede usarse para asignar un nuevo valor en la enésima ubicación de la Btime
columna de df
.
Dado que Pandas no ofrece garantías explícitas sobre cuándo los indexadores devuelven una vista versus una copia, las asignaciones que utilizan indexación encadenada generalmente siempre generan un SettingWithCopyWarning
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:
Por el contrario, la asignación con df.iloc[0]['bar'] = 123
no funciona porque df.iloc[0]
devuelve 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 : ya lo había sugerido anteriormente df_test.ix[i, 'Btime']
. Pero no se garantiza que esto le proporcione el ith
valor, ya que ix
intenta indexar por etiqueta antes de intentar indexar por posición . Entonces, si el DataFrame tiene un índice entero que no está ordenado comenzando en 0, entonces el uso ix[i]
devolverá la fila etiquetada i
en lugar de la ith
fila. 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'
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)