Pandas - obtém o valor da primeira linha de uma determinada coluna

300

Parece uma pergunta ridiculamente fácil ... mas não estou vendo a resposta fácil que estava esperando.

Então, como obtenho o valor na enésima linha de uma determinada coluna no Pandas? (Estou particularmente interessado na primeira linha, mas também estaria interessado em uma prática mais geral).

Por exemplo, digamos que eu queira extrair o valor 1.2 no Btime como uma variável.

Qual é o caminho certo para fazer isso?

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
fonte
7
Se você simplesmente queria a primeira linha, em seguida, df_test.head(1)iria trabalhar, a forma mais geral é a utilização iloccomo respondidas por unutbu
EdChum
1
Você quer apenas o valor 1.2? ou a série de comprimento 1 fornecida df_test.head(1), que também conterá o índice? Para obter apenas o valor faça df_test.head(1).item()ou, em tolist()seguida, corte.
smci 3/09/18

Respostas:

472

Para selecionar a ithlinha, 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 selecionar o i-ésimo valor na Btimecoluna, você pode usar:

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

Há uma diferença entre df_test['Btime'].iloc[0](recomendado) e df_test.iloc[0]['Btime']:

Os DataFrames armazenam dados em blocos baseados em colunas (onde cada bloco tem um único tipo). Se você selecionar primeiro a coluna, uma exibição poderá ser retornada (o que é mais rápido que o retorno de uma cópia) e o dtype original é preservado. Por outro lado, se você selecionar primeiro a linha e se o DataFrame tiver colunas de diferentes tipos, o Pandas copiará os dados em uma nova série de tipos de objetos. Portanto, selecionar colunas é um pouco mais rápido que selecionar linhas. Assim, embora df_test.iloc[0]['Btime']funcione, df_test['Btime'].iloc[0]é um pouco mais eficiente.

Há uma grande diferença entre os dois quando se trata de atribuição. df_test['Btime'].iloc[0] = xafeta df_test, mas df_test.iloc[0]['Btime'] pode não. Veja abaixo uma explicação do porquê. Como uma diferença sutil na ordem da indexação faz uma grande diferença no comportamento, é melhor usar a atribuição de indexação única:

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

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

A maneira recomendada de atribuir novos valores a um DataFrame é evitar a indexação em cadeia e, em vez disso, use o método mostrado por andrew ,

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

ou

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

O último método é um pouco mais rápido, porque df.locé necessário converter os rótulos de linha e coluna em índices posicionais; portanto, é necessário um pouco menos de conversão se você usar df.iloc.


df['Btime'].iloc[0] = x funciona, mas não é recomendado:

Embora isso funcione, ele está aproveitando a maneira como os DataFrames são implementados atualmente . Não há garantia de que o Pandas funcione dessa maneira no futuro. Em particular, está aproveitando o fato de que (atualmente) df['Btime']sempre retorna uma visualização (não uma cópia), para que df['Btime'].iloc[n] = xpossa ser usado para atribuir um novo valor no enésimo local da Btimecoluna de df.

Como o Pandas não oferece garantias explícitas sobre quando os indexadores retornam uma visualização versus uma cópia, as atribuições que usam indexação encadeada geralmente sempre aumentam SettingWithCopyWarning, embora nesse caso a atribuição consiga 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 não funciona:

Por outro lado, a atribuição com df.iloc[0]['bar'] = 123não funciona porque df.iloc[0]está retornando uma cópia:

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

Aviso : eu havia sugerido anteriormente df_test.ix[i, 'Btime']. Mas isso não garante que você ofereça o ithvalor, pois ixtenta indexar por rótulo antes de tentar indexar por posição . Portanto, se o DataFrame tiver um índice inteiro que não esteja na ordem classificada, começando em 0, usar ix[i]retornará a linha rotulada i em vez da ithlinha. Por exemplo,

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
fonte
1
@CristianCiupitu: DataFrames armazenam dados em blocos baseados em colunas (onde cada bloco possui um único tipo) .Se você seleciona primeiro pela coluna, uma exibição pode ser retornada (que é mais rápida do que retornar uma cópia) e o tipo original é preservado. Por outro lado, se você selecionar primeiro a linha e se o DataFrame tiver colunas de diferentes tipos, o Pandas copiará os dados em uma nova série de tipos de objetos. Portanto, selecionar colunas é um pouco mais rápido que selecionar linhas. Assim, embora df_test.iloc[0]['Btime']funcione, df_test.iloc['Btime'][0]é um pouco mais eficiente.
Unutbu 03/08/19
@unutbu, é df['Btime'].iloc[0]preferido df['Btime'].values[0]? Eu posso ver na documentação que diz "Aviso: recomendamos o uso de Series.array ou Series.to_numpy (), dependendo se você precisa de uma referência aos dados subjacentes ou a uma matriz NumPy". mas não sei exatamente o que isso significa
aydow
28

Observe que a resposta de @unutbu estará correta até que você defina o valor como algo novo, e não funcionará se o seu quadro de dados for uma visualização.

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)

Outra abordagem que funcionará consistentemente com a configuração e a obtenção é:

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
andrew
fonte
1
Estou percorrendo um monte de arquivos .csv e lendo o primeiro valor de uma determinada coluna em cada um. Por alguma razão que não posso explicar, em vez de retornar o valor, isso às vezes retorna o índice junto com o valor que atrapalha o processamento. Eu recorri ao df.col.unique () [0].
pardal
15

Outra maneira de fazer isso:

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

Dessa maneira, parece ser mais rápido do 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
fonte
12
  1. df.iloc[0].head(1) - Primeiro conjunto de dados apenas da primeira linha inteira.
  2. df.iloc[0] - Primeira linha inteira na coluna.
Nikhil
fonte
8

De uma maneira geral, se você quiser pegar as primeiras N linhas da coluna Jpandas dataframe da melhor maneira de fazer isso é:

data = dataframe[0:N][:,J]
anis
fonte
2
@anis: Para esse propósito, você teria sido melhor escrevendo uma nova pergunta pedindo a solução mais geral e respondendo por conta própria, acredito.
jonathan.scholbach
3

Para obter, por exemplo, o valor da coluna 'test' e da linha 1, funciona como

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

como apenas df[['test']].values[0]devolve uma matriz

Alex Ortner
fonte
1

Outra maneira de obter a primeira linha e preservar o índice:

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