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.
.loc
ou .iloc
sur l'option la plus générale .ix
?.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..ix
? 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.
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)
_
pandas utilise deux méthodes principales pour effectuer des sélections à partir d'un DataFrame.
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 ...
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 uniquementJe 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 uniquementOutre la sélection par libellé et emplacement entier, sélection booléenne également appelée index booléen existe.
.loc
_, _.iloc
_, sélection booléenne et _.at
_ et _.iat
_ sont indiqués ci-dessousNous 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'])
_
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.
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
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:
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']
_
Les tranches complexes peuvent être prises de la même manière que les listes Python.
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
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:
Sélection de plusieurs lignes avec .iloc avec notation slice
_df.iloc[:5:3]
_
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':]
_
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
_
_.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]]
_
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]]
_
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]
_
[]
_, 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']]
_
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
_
_df[2:6:2] # slice rows by integer location
_
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'
_
.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'
_
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
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
:-)