web-dev-qa-db-fra.com

pandas loc vs iloc vs ix vs at vs iat?

Récemment commencé à sortir de mon lieu sûr (R) dans Python et je suis un peu confus par la localisation/sélection de cellules dans Pandas. J'ai lu la documentation, mais j'ai du mal à comprendre les implications pratiques des différentes options de localisation/sélection.

  • Y a-t-il une raison pour laquelle je devrais jamais utiliser .loc ou .iloc sur l'option la plus générale .ix?
  • Je comprends que .loc, iloc, at et iat peuvent fournir une exactitude garantie que .ix ne peut pas offrir, mais j'ai également lu où .ix a tendance à être la solution la plus rapide.
  • Veuillez expliquer le raisonnement fondé sur les meilleures pratiques du monde réel utilisant autre chose que .ix?
149
user4613042

loc: ne fonctionne que sur l'index
iloc: travaille sur la position
ix: Vous pouvez obtenir des données à partir de la structure de données sans qu'elles soient dans l'index.
sur: obtenir des valeurs scalaires. C'est une loco très rapide
iat: Obtenir des valeurs scalaires. C'est un iloc très rapide

http://pyciencia.blogspot.com/2015/05/obtener-y-filtrar-datos-de-dataframe.html

Remarque: À partir de pandas 0.20.0, l'indexeur .ix est obsolète en faveur du plus strict .iloc et .loc indexeurs.

122
lautremont

Mis à jour pour pandas _0.20_ étant donné que ix est obsolète. Cela montre non seulement comment utiliser loc, iloc, at, iat, _set_value_, mais également comment réaliser une indexation mixte positionnée/basée sur des étiquettes.


loc - libellé
Vous permet de passer des tableaux à une dimension en tant qu’indexeurs. Les tableaux peuvent être des tranches (sous-ensembles) de l'index ou de la colonne, ou des tableaux booléens dont la longueur est égale à celle de l'index ou des colonnes.

Remarque spéciale: Lorsqu'un indexeur scalaire est passé, loc peut affecter un nouvel index ou une nouvelle valeur de colonne qui n'existait pas auparavant.

_# label based, but we can use position values
# to get the labels from the index object
df.loc[df.index[2], 'ColName'] = 3
_

_df.loc[df.index[1:3], 'ColName'] = 3
_

iloc - basé sur la position
Similaire à loc sauf qu’il s’agit de positions plutôt que de valeurs d’index. Cependant, vous ne pouvez pas affecter de nouvelles colonnes ou de nouveaux index.

_# position based, but we can get the position
# from the columns object via the `get_loc` method
df.iloc[2, df.columns.get_loc('ColName')] = 3
_

_df.iloc[2, 4] = 3
_

_df.iloc[:3, 2:4] = 3
_

at - libellé
Fonctionne de manière très similaire à loc pour les indexeurs scalaires. Ne peut pas opérer sur les indexeurs de tableaux. Can! assigner de nouveaux index et colonnes.

Avantage sur loc est que cela est plus rapide.
Inconvénient ​​est que vous ne pouvez pas utiliser de tableaux pour les indexeurs.

_# label based, but we can use position values
# to get the labels from the index object
df.at[df.index[2], 'ColName'] = 3
_

_df.at['C', 'ColName'] = 3
_

iat - basé sur la position
Fonctionne de la même façon que iloc. Ne peut pas travailler dans les indexeurs de tableaux. Cannot! assigner de nouveaux index et colonnes.

Avantage sur iloc est que cela est plus rapide.
Inconvénient ​​est que vous ne pouvez pas utiliser de tableaux pour les indexeurs.

_# position based, but we can get the position
# from the columns object via the `get_loc` method
IBM.iat[2, IBM.columns.get_loc('PNL')] = 3
_

set_value - label
Fonctionne de manière très similaire à loc pour les indexeurs scalaires. Ne peut pas opérer sur les indexeurs de tableaux. Can! assigner de nouveaux index et colonnes

Avantage Super rapide, car il y a très peu de frais généraux!
Inconvénient ​​Les frais généraux sont minimes, car pandas ne fait pas une série de contrôles de sécurité. Utilisez à vos risques et périls . En outre, cela n'est pas destiné à un usage public.

_# label based, but we can use position values
# to get the labels from the index object
df.set_value(df.index[2], 'ColName', 3)
_

set_value_ AVEC _takable=True - basé sur la position
Fonctionne de la même façon que iloc. Ne peut pas travailler dans les indexeurs de tableaux. Cannot! assigner de nouveaux index et colonnes.

Avantage Super rapide, car il y a très peu de frais généraux!
Inconvénient ​​Les frais généraux sont minimes, car pandas ne fait pas une série de contrôles de sécurité. Utilisez à vos risques et périls . En outre, cela n'est pas destiné à un usage public.

_# position based, but we can get the position
# from the columns object via the `get_loc` method
df.set_value(2, df.columns.get_loc('ColName'), 3, takable=True)
_
79
piRSquared

pandas utilise deux méthodes principales pour effectuer des sélections à partir d'un DataFrame.

  • Par Label
  • Par emplacement entier

La documentation utilise le terme position pour désigner emplacement entier. Je n'aime pas cette terminologie, qui me semble confuse. L'emplacement entier est plus descriptif et correspond exactement à ce que _.iloc_ représente. La clé Word ici est INTEGER - vous devez utiliser des entiers lors de la sélection par l'emplacement de l'entier.

Avant de montrer le résumé, assurons-nous tous que ...

.ix est obsolète et ambigu et ne devrait jamais être utilisé

Il existe trois principaux indexeurs pour les pandas. Nous avons l'opérateur d'indexation lui-même (les crochets []), .loc, et .iloc. Résumons-les:

  • [] - Sélectionne principalement des sous-ensembles de colonnes, mais peut également sélectionner des lignes. Impossible de sélectionner simultanément des lignes et des colonnes.
  • .loc - sélectionne des sous-ensembles de lignes et de colonnes uniquement par libellé
  • .iloc - sélectionne des sous-ensembles de lignes et de colonnes par emplacement entier uniquement

Je n’utilise presque jamais .at ou .iat car ils n’ajoutent aucune fonctionnalité supplémentaire et n'augmentent que légèrement les performances. Je déconseillerais leur utilisation sauf si vous avez une application très sensible au temps. Quoi qu'il en soit, nous avons leur résumé:

  • .at sélectionne une seule valeur scalaire dans le cadre de données par étiquette uniquement
  • .iat sélectionne une seule valeur scalaire dans le DataFrame par emplacement entier uniquement

Outre la sélection par libellé et emplacement entier, sélection booléenne également appelée index booléen existe.


Des exemples expliquant _.loc_, _.iloc_, sélection booléenne et _.at_ et _.iat_ sont indiqués ci-dessous

Nous allons d’abord nous concentrer sur les différences entre _.loc_ et _.iloc_. Avant de parler des différences, il est important de comprendre que les DataFrames ont des étiquettes qui aident à identifier chaque colonne et chaque ligne. Jetons un coup d'œil à un exemple de DataFrame:

_df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69],
                   'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'],
                   'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'],
                   'height':[165, 70, 120, 80, 180, 172, 150],
                   'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2],
                   'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX']
                   },
                  index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])
_

enter image description here

Tous les mots entre bold sont les étiquettes. Les étiquettes, age, color, food, height, score et state sont utilisées pour les colonnes . Les autres étiquettes, Jane, Nick, Aaron, Penelope, Dean, Christina, Cornelia sont utilisées comme étiquettes pour les rangées. Ensemble, ces étiquettes de lignes sont appelées index.


Les méthodes principales de sélection de lignes particulières dans un DataFrame sont les indexeurs _.loc_ et _.iloc_. Chacun de ces indexeurs peut également être utilisé pour sélectionner simultanément des colonnes, mais il est plus facile de se concentrer uniquement sur les lignes pour l'instant. De plus, chacun des indexeurs utilise un jeu de crochets qui suit immédiatement son nom pour effectuer ses sélections.

.loc sélectionne les données uniquement par étiquettes

Nous allons d’abord parler de l’indexeur _.loc_ qui ne sélectionne que les données en fonction des étiquettes d’index ou de colonne. Dans notre exemple DataFrame, nous avons fourni des noms significatifs en tant que valeurs pour l'index. Beaucoup de DataFrames n'auront aucun nom significatif et utiliseront par défaut uniquement les entiers compris entre 0 et n-1, où n est la longueur (nombre de lignes) du DataFrame.

Il y a beaucoup d'entrées différentes vous pouvez utiliser pour _.loc_ trois d'entre elles sont

  • Un string
  • Une liste de chaînes
  • Notation par tranches utilisant des chaînes comme valeurs de départ et d'arrêt

Sélection d'une seule ligne avec .loc avec une chaîne

Pour sélectionner une seule ligne de données, placez l'index à l'intérieur des crochets après _.loc_.

_df.loc['Penelope']
_

Ceci retourne la ligne de données en tant que série.

_age           4
color     white
food      Apple
height       80
score       3.3
state        AL
Name: Penelope, dtype: object
_

Sélection de plusieurs lignes avec .loc avec une liste de chaînes

_df.loc[['Cornelia', 'Jane', 'Dean']]
_

Cela renvoie un DataFrame avec les lignes dans l'ordre spécifié dans la liste:

enter image description here

Sélection de plusieurs lignes avec .loc avec notation slice

La notation de tranche est définie par les valeurs de départ, d'arrêt et d'étape. Lors du découpage par étiquette, pandas inclut la valeur d'arrêt dans la déclaration. Les tranches suivantes d'Aaron à Dean, inclus. Sa taille de pas n'est pas explicitement définie mais définie par défaut à 1.

_df.loc['Aaron':'Dean']
_

enter image description here

Les tranches complexes peuvent être prises de la même manière que les listes Python.

.iloc sélectionne les données uniquement par emplacement entier

Passons maintenant à _.iloc_. Chaque ligne et colonne de données d'un DataFrame a un emplacement entier qui le définit. Cela s'ajoute à l'étiquette affichée visuellement dans la sortie. L'emplacement entier est simplement le nombre de lignes/colonnes du haut/gauche commençant à 0.

Il y a beaucoup d'entrées différentes vous pouvez utiliser pour _.iloc_ trois d'entre elles sont

  • Un nombre entier
  • Une liste d'entiers
  • Notation par tranches utilisant des entiers comme valeurs de départ et d'arrêt

Sélection d'une seule ligne avec .iloc avec un entier

_df.iloc[4]
_

Ceci retourne la 5ème ligne (emplacement entier 4) en tant que série.

_age           32
color       gray
food      Cheese
height       180
score        1.8
state         AK
Name: Dean, dtype: object
_

Sélection de plusieurs lignes avec .iloc avec une liste d’entiers

_df.iloc[[2, -2]]
_

Cela retourne un DataFrame de la troisième et dernière ligne:

enter image description here

Sélection de plusieurs lignes avec .iloc avec notation slice

_df.iloc[:5:3]
_

enter image description here


Sélection simultanée de lignes et de colonnes avec .loc et .iloc

Une excellente capacité des deux _.loc/.iloc_ est leur capacité à sélectionner simultanément des lignes et des colonnes. Dans les exemples ci-dessus, toutes les colonnes ont été renvoyées pour chaque sélection. Nous pouvons choisir des colonnes avec les mêmes types d’entrées que pour les lignes. Nous devons simplement séparer la sélection des lignes et des colonnes avec un virgule.

Par exemple, nous pouvons sélectionner les lignes Jane et Dean avec uniquement la hauteur, le score et l’état des colonnes, comme suit:

_df.loc[['Jane', 'Dean'], 'height':]
_

enter image description here

Ceci utilise une liste d'étiquettes pour les lignes et la notation de tranche pour les colonnes.

Nous pouvons naturellement faire des opérations similaires avec _.iloc_ en utilisant uniquement des entiers.

_df.iloc[[1,4], 2]
Nick      Lamb
Dean    Cheese
Name: food, dtype: object
_

Sélection simultanée avec étiquettes et emplacement entier

_.ix_ a été utilisé pour faire des sélections simultanément avec des étiquettes et un emplacement entier, ce qui était utile mais parfois déroutant et ambigu. Heureusement, il est déconseillé. Si vous devez faire une sélection avec une combinaison d’étiquettes et d’emplacements d’entiers, vous devrez créer les deux étiquettes de sélection ou les emplacements d’entiers.

Par exemple, si nous voulons sélectionner les lignes Nick et Cornelia avec les colonnes 2 et 4, nous pourrions utiliser _.loc_ en convertissant les entiers en étiquettes avec les éléments suivants:

_col_names = df.columns[[2, 4]]
df.loc[['Nick', 'Cornelia'], col_names] 
_

Ou bien, convertissez les étiquettes d'index en entiers avec la méthode d'indexation _get_loc_.

_labels = ['Nick', 'Cornelia']
index_ints = [df.index.get_loc(label) for label in labels]
df.iloc[index_ints, [2, 4]]
_

Sélection booléenne

L'indexeur .loc peut également effectuer une sélection booléenne. Par exemple, si nous souhaitons rechercher toutes les lignes dont l'âge est supérieur à 30 ans et ne renvoyer que les colonnes food et score, nous pouvons procéder comme suit:

_df.loc[df['age'] > 30, ['food', 'score']] 
_

Vous pouvez répliquer ceci avec _.iloc_ mais vous ne pouvez pas lui transmettre une série booléenne. Vous devez convertir la série booléenne dans un tableau numpy comme ceci:

_df.iloc[(df['age'] > 30).values, [2, 4]] 
_

Sélection de toutes les lignes

Il est possible d'utiliser _.loc/.iloc_ uniquement pour la sélection de colonne. Vous pouvez sélectionner toutes les lignes en utilisant deux points comme ceci:

_df.loc[:, 'color':'score':2]
_

enter image description here


L'opérateur d'indexation, _[]_, peut trancher peut également sélectionner des lignes et des colonnes, mais pas simultanément.

La plupart des utilisateurs sont familiarisés avec l'objectif principal de l'opérateur d'indexation DataFrame, qui consiste à sélectionner des colonnes. Une chaîne sélectionne une seule colonne en tant que série et une liste de chaînes sélectionne plusieurs colonnes en tant que DataFrame.

_df['food']

Jane          Steak
Nick           Lamb
Aaron         Mango
Penelope      Apple
Dean         Cheese
Christina     Melon
Cornelia      Beans
Name: food, dtype: object
_

Utiliser une liste sélectionne plusieurs colonnes

_df[['food', 'score']]
_

enter image description here

Ce que les gens connaissent moins, c’est que, lorsque la notation par tranches est utilisée, la sélection se fait par libellés de lignes ou par emplacement d’entier. C'est très déroutant et quelque chose que je n'utilise presque jamais, mais cela fonctionne.

_df['Penelope':'Christina'] # slice rows by label
_

enter image description here

_df[2:6:2] # slice rows by integer location
_

enter image description here

Le caractère explicite de _.loc/.iloc_ pour la sélection de lignes est hautement préféré. L'opérateur d'indexation seul ne peut pas sélectionner des lignes et des colonnes simultanément.

_df[3:5, 'color']
TypeError: unhashable type: 'slice'
_

Sélection par _.at_ et _.iat_

La sélection avec _.at_ est presque identique à _.loc_ mais elle ne sélectionne qu'une seule "cellule" dans votre DataFrame. Nous appelons habituellement cette cellule une valeur scalaire. Pour utiliser _.at_, transmettez-lui une étiquette de ligne et une étiquette de colonne séparées par une virgule.

_df.at['Christina', 'color']
'black'
_

La sélection avec _.iat_ est presque identique à _.iloc_ mais elle ne sélectionne qu'une seule valeur scalaire. Vous devez lui transmettre un entier pour les emplacements des lignes et des colonnes.

_df.iat[2, 5]
'FL'
_
48
Ted Petrou
df = pd.DataFrame({'A':['a', 'b', 'c'], 'B':[54, 67, 89]}, index=[100, 200, 300])

df

                        A   B
                100     a   54
                200     b   67
                300     c   89
In [19]:    
df.loc[100]

Out[19]:
A     a
B    54
Name: 100, dtype: object

In [20]:    
df.iloc[0]

Out[20]:
A     a
B    54
Name: 100, dtype: object

In [24]:    
df2 = df.set_index([df.index,'A'])
df2

Out[24]:
        B
    A   
100 a   54
200 b   67
300 c   89

In [25]:    
df2.ix[100, 'a']

Out[25]:    
B    54
Name: (100, a), dtype: int64
31
Lydia

Commençons par ce petit df:

import pandas as pd
import time as tm
import numpy as np
n=10
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))

Nous aurons ainsi

df
Out[25]: 
        0   1   2   3   4   5   6   7   8   9
    0   0   1   2   3   4   5   6   7   8   9
    1  10  11  12  13  14  15  16  17  18  19
    2  20  21  22  23  24  25  26  27  28  29
    3  30  31  32  33  34  35  36  37  38  39
    4  40  41  42  43  44  45  46  47  48  49
    5  50  51  52  53  54  55  56  57  58  59
    6  60  61  62  63  64  65  66  67  68  69
    7  70  71  72  73  74  75  76  77  78  79
    8  80  81  82  83  84  85  86  87  88  89
    9  90  91  92  93  94  95  96  97  98  99

Avec cela nous avons:

df.iloc[3,3]
Out[33]: 33

df.iat[3,3]
Out[34]: 33

df.iloc[:3,:3]
Out[35]: 
    0   1   2   3
0   0   1   2   3
1  10  11  12  13
2  20  21  22  23
3  30  31  32  33



df.iat[:3,:3]
Traceback (most recent call last):
   ... omissis ...
ValueError: At based indexing on an integer index can only have integer indexers

Ainsi, nous ne pouvons pas utiliser .iat pour un sous-ensemble, où nous devons utiliser uniquement .iloc.

Mais essayons tous les deux de choisir un plus grand df et vérifions la vitesse ...

# -*- coding: utf-8 -*-
"""
Created on Wed Feb  7 09:58:39 2018

@author: Fabio Pomi
"""

import pandas as pd
import time as tm
import numpy as np
n=1000
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))
t1=tm.time()
for j in df.index:
    for i in df.columns:
        a=df.iloc[j,i]
t2=tm.time()
for j in df.index:
    for i in df.columns:
        a=df.iat[j,i]
t3=tm.time()
loc=t2-t1
at=t3-t2
prc = loc/at *100
print('\nloc:%f at:%f prc:%f' %(loc,at,prc))

loc:10.485600 at:7.395423 prc:141.784987

Donc, avec .loc nous pouvons gérer des sous-ensembles et avec .at seulement un seul scalaire, mais .at est plus rapide que .loc

:-)

4
Fabio Pomi