Pandas - Récupère la valeur de la première ligne d'une colonne donnée

301

Cela semble être une question ridiculement facile ... mais je ne vois pas la réponse facile que j'attendais.

Alors, comment puis-je obtenir la valeur à une nième ligne d'une colonne donnée dans Pandas? (Je suis particulièrement intéressé par la première ligne, mais je serais également intéressé par une pratique plus générale).

Par exemple, disons que je veux extraire la valeur 1.2 dans Btime en tant que variable.

Quelle est la bonne façon de procéder?

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
la source
7
Si vous vouliez simplement que la première ligne df_test.head(1)fonctionne, le formulaire plus général est d'utiliser iloccomme répondu par unutbu
EdChum
1
Voulez-vous juste la valeur 1.2? ou la série de longueur 1 que vous obtenez df_test.head(1), qui contiendra également l'index? Pour obtenir juste la valeur faire df_test.head(1).item(), ou tolist()alors tranche.
smci

Réponses:

473

Pour sélectionner la ithligne, utiliseziloc :

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

Pour sélectionner la ième valeur dans la Btimecolonne, vous pouvez utiliser:

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

Il y a une différence entre df_test['Btime'].iloc[0](recommandé) et df_test.iloc[0]['Btime']:

Les DataFrames stockent les données dans des blocs basés sur des colonnes (où chaque bloc a un seul type). Si vous sélectionnez d'abord par colonne, une vue peut être renvoyée (ce qui est plus rapide que le renvoi d'une copie) et le type d'origine est conservé. En revanche, si vous sélectionnez d'abord par ligne et si le DataFrame a des colonnes de dtypes différents, Pandas copie les données dans une nouvelle série de dtype d'objet. La sélection de colonnes est donc un peu plus rapide que la sélection de lignes. Ainsi, bien que df_test.iloc[0]['Btime']fonctionne, df_test['Btime'].iloc[0]est un peu plus efficace.

Il y a une grande différence entre les deux en ce qui concerne l'affectation. df_test['Btime'].iloc[0] = xaffecte df_test, mais df_test.iloc[0]['Btime'] peut ne pas. Voir ci-dessous pour une explication de pourquoi. Étant donné qu'une différence subtile dans l'ordre d'indexation fait une grande différence de comportement, il est préférable d'utiliser une affectation d'indexation unique:

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

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

La façon recommandée d'affecter de nouvelles valeurs à un DataFrame est d' éviter l'indexation chaînée et d'utiliser à la place la méthode indiquée par andrew ,

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

ou

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

Cette dernière méthode est un peu plus rapide, car df.locelle doit convertir les étiquettes de ligne et de colonne en indices positionnels, il y a donc un peu moins de conversion nécessaire si vous utilisez à la df.ilocplace.


df['Btime'].iloc[0] = x fonctionne, mais n'est pas recommandé:

Bien que cela fonctionne, il tire parti de la façon dont les DataFrames sont actuellement implémentés. Il n'y a aucune garantie que les Pandas doivent fonctionner de cette façon à l'avenir. En particulier, il profite du fait que (actuellement) df['Btime']renvoie toujours une vue (pas une copie) et df['Btime'].iloc[n] = xpeut donc être utilisé pour affecter une nouvelle valeur au nième emplacement de la Btimecolonne de df.

Étant donné que Pandas ne donne aucune garantie explicite sur le moment où les indexeurs retournent une vue par rapport à une copie, les affectations qui utilisent l'indexation chaînée génèrent généralement toujours un SettingWithCopyWarningmême si dans ce cas, l'affectation réussit à modifier 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 ne marche pas:

En revanche, l'affectation avec df.iloc[0]['bar'] = 123ne fonctionne pas car df.iloc[0]renvoie une copie:

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

Avertissement : j'avais déjà suggéré df_test.ix[i, 'Btime']. Mais cela n'est pas garanti pour vous donner la ithvaleur car ixessaie d'indexer par étiquette avant d'essayer d'indexer par position . Donc, si le DataFrame a un index entier qui n'est pas dans l'ordre trié à partir de 0, alors l'utilisation ix[i]retournera la ligne étiquetée i plutôt que la ithligne. Par exemple,

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
la source
1
@CristianCiupitu: les DataFrames stockent les données dans des blocs basés sur des colonnes (où chaque bloc a un seul type) .Si vous sélectionnez d'abord par colonne, une vue peut être renvoyée (ce qui est plus rapide que de renvoyer une copie) et le type d'origine est conservé. En revanche, si vous sélectionnez d'abord par ligne et si le DataFrame a des colonnes de dtypes différents, Pandas copie les données dans une nouvelle série de dtype d'objet. La sélection de colonnes est donc un peu plus rapide que la sélection de lignes. Ainsi, bien que df_test.iloc[0]['Btime']fonctionne, df_test.iloc['Btime'][0]est un peu plus efficace.
unutbu
@unutbu, est df['Btime'].iloc[0]préféré à df['Btime'].values[0]? je peux voir dans la documentation qu'il dit "Avertissement: Nous vous recommandons d'utiliser Series.array ou Series.to_numpy (), selon que vous avez besoin d'une référence aux données sous-jacentes ou d'un tableau NumPy." mais je ne sais pas exactement ce que cela signifie
aydow
28

Notez que la réponse de @unutbu sera correcte jusqu'à ce que vous souhaitiez définir la valeur sur quelque chose de nouveau, alors cela ne fonctionnera pas si votre trame de données est une vue.

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)

Une autre approche qui fonctionnera de manière cohérente avec la définition et l'obtention est la suivante:

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
la source
1
Je passe en revue un tas de fichiers .csv et je lis la première valeur d'une certaine colonne dans chacun. Pour une raison que je ne peux pas expliquer au lieu de renvoyer la valeur, cela renvoie parfois l'index avec la valeur qui gâche le traitement. J'ai eu recours à df.col.unique () [0].
moineau
15

Une autre façon de procéder:

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

Cette façon semble être plus rapide que d'utiliser .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
la source
12
  1. df.iloc[0].head(1) - Premier ensemble de données uniquement à partir de la première ligne entière.
  2. df.iloc[0] - Première ligne entière dans la colonne.
nikhil
la source
8

De manière générale, si vous souhaitez récupérer les N premières lignes de la colonne J de pandas dataframela meilleure façon de procéder, procédez comme suit:

data = dataframe[0:N][:,J]
anis
la source
2
@anis: À cette fin, vous auriez mieux fait d'écrire une nouvelle question en demandant la solution plus générale et en y répondant par vous-même, je crois.
jonathan.scholbach
3

Pour obtenir par exemple la valeur de la colonne 'test' et de la ligne 1, cela fonctionne comme

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

comme df[['test']].values[0]redonne seulement un tableau

Alex Ortner
la source
1

Une autre façon d'obtenir la première ligne et de conserver l'index:

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