Quelqu'un peut-il expliquer en quoi ces trois méthodes de découpage sont différentes?
J'ai vu les documents , et j'ai vu ceux-ciréponses , mais je me trouve toujours incapable d'expliquer comment les trois sont différents. Pour moi, ils semblent en grande partie interchangeables, car ils se situent aux niveaux de découpage les plus bas.
Par exemple, supposons que nous voulions obtenir les cinq premières lignes d'un DataFrame
. Comment se fait-il que ces trois éléments fonctionnent?
df.loc[:5]
df.ix[:5]
df.iloc[:5]
Quelqu'un peut-il présenter trois cas où la distinction des utilisations est plus claire?
Remarque: dans pandas versions 0.20.0 et supérieures, ix
est obsolète et l'utilisation de loc
et iloc
est encouragé à la place. J'ai laissé les parties de cette réponse qui décrivent ix
intact à titre de référence pour les utilisateurs des versions antérieures de pandas. Des exemples ont été ajoutés ci-dessous pour illustrer des alternatives à ix
.
Tout d'abord, voici un récapitulatif des trois méthodes:
loc
obtient les lignes (ou colonnes) avec des étiquettes particulières de l'index.iloc
obtient des lignes (ou des colonnes) à des positions particulières dans l'index (il ne prend donc que des entiers).ix
essaye généralement de se comporter comme loc
mais retombe pour se comporter comme iloc
si une étiquette n'est pas présente dans l'index.Il est important de noter quelques subtilités qui peuvent rendre ix
un peu délicat à utiliser:
si l'index est de type entier, ix
n'utilisera que l'indexation basée sur une étiquette et ne retombera pas sur l'indexation basée sur la position. Si l'étiquette n'est pas dans l'index, une erreur est générée.
si l'index ne contient pas seulement entiers, alors étant donné un entier, ix
utilisera immédiatement l'indexation basée sur la position plutôt que l'indexation basée sur l'étiquette . Si, toutefois, ix
se voit attribuer un autre type (par exemple, une chaîne), il peut utiliser l'indexation basée sur une étiquette.
Pour illustrer les différences entre les trois méthodes, considérons les séries suivantes:
_>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
_
Nous allons examiner le découpage avec la valeur entière _3
_.
Dans ce cas, _s.iloc[:3]
_ nous renvoie les 3 premières lignes (puisqu'il traite 3 en tant que position) et _s.loc[:3]
_ nous renvoie les 8 premières lignes (puisqu'il traite 3 en tant qu'étiquette):
_>>> s.iloc[:3] # slice the first three rows
49 NaN
48 NaN
47 NaN
>>> s.loc[:3] # slice up to and including label 3
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
>>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
_
Remarque _s.ix[:3]
_ renvoie la même série que _s.loc[:3]
_ car elle recherche d'abord l'étiquette plutôt que de travailler sur la position (et l'index pour s
est de type entier).
Que faire si nous essayons avec une étiquette entière qui n'est pas dans l'index (disons _6
_)?
Ici _s.iloc[:6]
_ renvoie les 6 premières lignes de la série comme prévu. Toutefois, _s.loc[:6]
_ déclenche une erreur KeyError puisque _6
_ ne figure pas dans l'index.
_>>> s.iloc[:6]
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
>>> s.loc[:6]
KeyError: 6
>>> s.ix[:6]
KeyError: 6
_
Conformément aux subtilités mentionnées ci-dessus, _s.ix[:6]
_ génère maintenant une erreur KeyError car elle tente de fonctionner comme loc
mais ne trouve pas _6
_ dans l'index. Comme notre index est de type entier ix
, il ne se comporte pas comme iloc
.
Cependant, si notre index était de type mixte, un entier ix
se comporterait comme iloc
immédiatement au lieu de générer une erreur KeyError:
_>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now behaves like iloc given integer
a NaN
b NaN
c NaN
d NaN
e NaN
1 NaN
_
Gardez à l'esprit que ix
peut toujours accepter des non-entiers et se comporter comme loc
:
_>>> s2.ix[:'c'] # behaves like loc given non-integer
a NaN
b NaN
c NaN
_
En règle générale, si vous n'indexez qu'à l'aide d'étiquettes ou d'indexation à l'aide de positions entières, respectez loc
ou iloc
pour éviter des résultats inattendus - essayez de ne pas utiliser ix
.
Parfois, à l'aide d'un DataFrame, vous souhaiterez mélanger des méthodes d'indexation d'étiquette et de position pour les lignes et les colonnes.
Par exemple, considérons le DataFrame suivant. Quelle est la meilleure méthode pour découper les lignes jusqu'à et y compris 'c' et les quatre premières colonnes?
_>>> df = pd.DataFrame(np.nan,
index=list('abcde'),
columns=['x','y','z', 8, 9])
>>> df
x y z 8 9
a NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN
_
Dans les versions antérieures de pandas (avant la version.20.20) ix
vous permet de le faire très précisément - nous pouvons découper les lignes par libellé et les colonnes par position (notez que pour les colonnes, ix
utilisera par défaut le découpage basé sur la position car _4
_ n'est pas un nom de colonne):
_>>> df.ix[:'c', :4]
x y z 8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN
_
Dans les versions ultérieures de pandas, nous pouvons obtenir ce résultat en utilisant iloc
et en utilisant une autre méthode:
_>>> df.iloc[:df.index.get_loc('c') + 1, :4]
x y z 8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN
_
get_loc()
est une méthode d'indexation signifiant "obtenir la position du libellé dans cet index". Notez que puisque le découpage avec iloc
exclut son point de terminaison, nous devons ajouter 1 à cette valeur si nous voulons également la ligne 'c'.
Il y a d'autres exemples dans la documentation des pandas ici .
iloc
fonctionne sur la base du positionnement entier. Ainsi, quels que soient vos libellés de lignes, vous pouvez toujours, par exemple, obtenir la première ligne en faisant
df.iloc[0]
ou les cinq derniers rangs en faisant
df.iloc[-5:]
Vous pouvez également l'utiliser sur les colonnes. Ceci récupère la 3ème colonne:
df.iloc[:, 2] # the : in the first position indicates all rows
Vous pouvez les combiner pour obtenir des intersections de lignes et de colonnes:
df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)
Par contre, .loc
utilise des index nommés. Configurons un cadre de données avec des chaînes en tant qu'étiquettes de lignes et de colonnes:
df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])
Ensuite, nous pouvons obtenir la première ligne par
df.loc['a'] # equivalent to df.iloc[0]
et les deux autres lignes de la colonne 'date'
par
df.loc['b':, 'date'] # equivalent to df.iloc[1:, 1]
etc. Maintenant, il est probablement utile de préciser que les index de ligne et de colonne par défaut pour un DataFrame
sont des entiers de 0 et que, dans ce cas, iloc
et loc
fonctionneraient de la même manière. C'est pourquoi vos trois exemples sont équivalents. Si vous aviez un index non numérique tel que des chaînes ou des dates-heures, df.loc[:5]
provoquerait une erreur .
En outre, vous pouvez récupérer les colonnes simplement en utilisant le __getitem__
du bloc de données:
df['time'] # equivalent to df.loc[:, 'time']
Supposons maintenant que vous vouliez mélanger la position et l'indexation nommée, c'est-à-dire l'indexation en utilisant des noms sur des lignes et des positions sur des colonnes (pour préciser, sélectionnez un cadre de données, plutôt que de créer un cadre de données avec des chaînes dans l'index des lignes et des entiers dans l'index de colonne). C'est ici que .ix
entre:
df.ix[:2, 'time'] # the first two rows of the 'time' column
Je pense qu'il est également intéressant de mentionner que vous pouvez également transmettre des vecteurs booléens à la méthode loc
. Par exemple:
b = [True, False, True]
df.loc[b]
Retourne les 1ère et 3ème rangées de df
. Ceci équivaut à df[b]
pour la sélection, mais il peut également être utilisé pour affecter des vecteurs booléens:
df.loc[b, 'name'] = 'Mary', 'John'
À mon avis, la réponse acceptée est source de confusion, car elle utilise un DataFrame avec uniquement des valeurs manquantes. Je n'aime pas non plus le terme basé sur la position pour _.iloc
_ et préfère plutôt l'emplacement entier comme c'est beaucoup plus descriptif et exactement ce que _.iloc
_ représente. Le mot clé est INTEGER - _.iloc
_ nécessite INTEGERS.
Voir mon extrêmement détaillé série de blogs sur la sélection de sous-ensemble pour plus
Puisque _.ix
_ est obsolète, nous nous concentrerons uniquement 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 index. 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 en gras en gras sont les étiquettes. Les étiquettes, age
, color
, food
, height
, score
et state
sont utilisées pour le colonnes . Les autres étiquettes, Jane
, Nick
, Aaron
, Penelope
, Dean
, Christina
, Cornelia
sont utilisées pour le 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 du DataFrame.
Vous pouvez utiliser trois entrées différentes pour _.loc
_
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. Ceci est en plus de l'étiquette qui est affichée visuellement dans la sortie . L'emplacement entier est simplement le nombre de lignes/colonnes du haut/gauche commençant à 0.
Vous pouvez utiliser trois entrées différentes pour _.iloc
_
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 par une 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 é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'
_