Recherche de site Web

Comment réinitialiser un index DataFrame pandas


Dans ce didacticiel, vous apprendrez comment réinitialiser un index Pandas DataFrame, les raisons pour lesquelles vous souhaiterez peut-être le faire et les problèmes qui pourraient survenir si vous ne le faites pas.

Avant de commencer votre parcours d'apprentissage, vous devez vous familiariser avec la création d'un DataFrame pandas. Connaître la différence entre un DataFrame et une série pandas vous sera également utile.

De plus, vous souhaiterez peut-être utiliser l'outil d'analyse de données Jupyter Notebook pendant que vous parcourez les exemples de ce didacticiel. Alternativement, JupyterLab vous offrira une expérience de notebook améliorée, mais n'hésitez pas à utiliser n'importe quel environnement Python de votre choix.

Pour commencer, vous aurez besoin de quelques données. Pour commencer, vous utiliserez le fichier band_members.csv inclus dans les documents téléchargeables auxquels vous pouvez accéder en cliquant sur le lien ci-dessous :

Le tableau ci-dessous décrit les données de band_members.csv avec lesquelles vous commencerez :

Column Name PyArrow Data Type Description
first_name string First name of member
last_name string Last name of member
instrument string Main instrument played
date_of_birth string Member’s date of birth

Comme vous le verrez, les données contiennent des détails sur les membres du groupe de rock The Beach Boys. Chaque ligne contient des informations sur ses différents membres passés et présents.

Tout au long de ce didacticiel, vous utiliserez la bibliothèque pandas pour vous permettre de travailler avec des DataFrames, ainsi qu'avec la nouvelle bibliothèque PyArrow. La bibliothèque PyArrow fournit aux pandas ses propres types de données optimisés, qui sont plus rapides et moins gourmands en mémoire que les types NumPy traditionnels que les pandas utilisent par défaut.

Si vous travaillez en ligne de commande, vous pouvez installer à la fois pandas et pyarrow en utilisant la seule commande python -m pip install pandas pyarrow. Si vous travaillez dans un notebook Jupyter, vous devez utiliser !python -m pip install pandas pyarrow. Quoi qu'il en soit, vous devez le faire dans un environnement virtuel pour éviter les conflits avec les bibliothèques que vous utilisez dans votre environnement global.

Une fois les bibliothèques en place, il est temps de lire vos données dans un DataFrame :

>>> import pandas as pd

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

Tout d'abord, vous avez utilisé import pandas pour rendre la bibliothèque disponible dans votre code. Pour construire le DataFrame et le lire dans la variable beach_boys, vous avez utilisé la fonction read_csv() de pandas, en passant band_members.csv comme fichier à lire. Enfin, en passant dtype_backend="pyarrow" à .convert_dtypes() vous convertissez toutes les colonnes en types pyarrow.

Si vous souhaitez vérifier que les types de données pyarrow sont bien utilisés, alors beach_boys.dtypes satisfera votre curiosité :

>>> beach_boys.dtypes
first_name            string[pyarrow]
last_name             string[pyarrow]
instrument            string[pyarrow]
date_of_birth         string[pyarrow]
dtype: object

Comme vous pouvez le voir, chaque type de données contient [pyarrow] dans son nom.

Si vous souhaitez analyser les informations de date de manière approfondie, vous analyserez la colonne date_of_birth pour vous assurer que les dates sont lues comme un type de date pyarrow approprié. Cela vous permettrait d'analyser par jours, mois ou années spécifiques, etc., comme on le trouve couramment dans les tableaux croisés dynamiques.

La colonne date_of_birth n'est pas analysée dans ce tutoriel, donc le type de données string est lu comme le fera. Plus tard, vous aurez l’occasion de perfectionner vos compétences grâce à quelques exercices. Les solutions incluent le code d’analyse de date si vous voulez voir comment cela se fait.

Maintenant que le fichier a été chargé dans un DataFrame, vous voudrez probablement y jeter un œil :

>>> beach_boys
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
3      Bruce  Johnston       Bass   27-Jun-1942
4       Carl    Wilson     Guitar   21-Dec-1946
5     Dennis    Wilson      Drums   04-Dec-1944
6      David     Marks     Guitar   22-Aug-1948
7      Ricky    Fataar      Drums   05-Sep-1952
8    Blondie   Chaplin     Guitar   07-Jul-1951

Les DataFrames sont des structures de données bidimensionnelles similaires aux feuilles de calcul ou aux tables de base de données. Un DataFrame pandas peut être considéré comme un ensemble de colonnes, chaque colonne étant une série pandas. Chaque colonne possède également un en-tête, qui est la propriété name de la série, et chaque ligne possède une étiquette, qui est appelée élément de son objet d'index associé.

L'index du DataFrame est affiché à gauche du DataFrame. Il ne fait pas partie du fichier source band_members.csv d'origine, mais est ajouté dans le cadre du processus de création du DataFrame. C'est cet objet d'index que vous apprenez à réinitialiser.

L'index d'un DataFrame est une colonne supplémentaire d'étiquettes qui vous aide à identifier les lignes. Lorsqu'il est utilisé en combinaison avec des en-têtes de colonnes, il vous permet d'accéder à des données spécifiques au sein de votre DataFrame. Les étiquettes d'index par défaut sont une séquence d'entiers, mais vous pouvez utiliser des chaînes pour les rendre plus significatives. Vous pouvez en fait utiliser n'importe quel type hachable pour votre index, mais les entiers, les chaînes et les horodatages sont les plus courants.

Une fois ces préliminaires terminés, il est temps d'emmener votre Little Deuce Coupe à la plage, de créer un pop-up et de surfer grâce à un apprentissage. Vous allez maintenant étudier les principales façons de réindexer un DataFrame. Vous pouvez appliquer un objet Index directement à la propriété .index du DataFrame, ou utiliser la méthode .set_axis() du DataFrame. Pour commencer, vous utiliserez la méthode .reset_index() du DataFrame.

Comment réinitialiser un index DataFrame pandas avec .reset_index()

La méthode DataFrame.reset_index(), comme son nom l'indique, est utilisée pour réinitialiser l'index d'un DataFrame pandas à sa valeur par défaut. Vous pouvez également utiliser cette méthode pour réinitialiser le MultiIndex sur votre DataFrame s'il en a un. Vous en apprendrez plus sur la façon de réinitialiser les multi-index plus tard.

Supposons que vous ayez effectué un nettoyage des données sur votre DataFrame et que vous ayez décidé de le trier par ordre alphabétique par first_name. Vous pouvez le faire en utilisant .sort_values() :

>>> beach_boys.sort_values(by="first_name")
  first_name last_name instrument date_of_birth
2         Al   Jardine     Guitar   03-Sep-1942
8    Blondie   Chaplin     Guitar   07-Jul-1951
0      Brian    Wilson       Bass   20-Jun-1942
3      Bruce  Johnston       Bass   27-Jun-1942
4       Carl    Wilson     Guitar   21-Dec-1946
6      David     Marks     Guitar   22-Aug-1948
5     Dennis    Wilson      Drums   04-Dec-1944
1       Mike      Love  Saxophone   15-Mar-1941
7      Ricky    Fataar      Drums   05-Sep-1952

Même si vous êtes satisfait du fait que le tri a parfaitement fonctionné, vous n’êtes pas satisfait de l’état actuel de son index. L'index ne ressemble plus à l'ordre mis à jour des lignes.

Pour résoudre ce problème, votre première pensée pourrait être d'utiliser .reset_index() avec ses paramètres par défaut, mais le résultat pourrait ne pas être celui que vous souhaitez :

>>> beach_boys.sort_values(by="first_name").reset_index()
   index first_name last_name instrument date_of_birth
0      2         Al   Jardine     Guitar   03-Sep-1942
1      8    Blondie   Chaplin     Guitar   07-Jul-1951
2      0      Brian    Wilson       Bass   20-Jun-1942
3      3      Bruce  Johnston       Bass   27-Jun-1942
4      4       Carl    Wilson     Guitar   21-Dec-1946
5      6      David     Marks     Guitar   22-Aug-1948
6      5     Dennis    Wilson      Drums   04-Dec-1944
7      1       Mike      Love  Saxophone   15-Mar-1941
8      7      Ricky    Fataar      Drums   05-Sep-1952

Vous disposez désormais d'un nouvel index par défaut, qui est une série séquentielle de nombres commençant à zéro qui définit clairement l'ordre des lignes. Cependant, l'index d'origine est resté et a été déplacé vers une nouvelle colonne nommée de manière confuse index. Cela peut être acceptable si vous devez ultérieurement remettre le DataFrame à son ordre de tri d'origine, mais le plus souvent, son inclusion ne fait que gaspiller de la mémoire. Vous voudrez généralement vous en débarrasser.

Heureusement, c'est facile à faire. Par défaut, .reset_index() crée une copie du DataFrame d'origine, applique l'index par défaut à cette deuxième copie et vous renvoie cette deuxième copie. Cela signifie que l'index du DataFrame d'origine reste inchangé, donc aucun dommage ne lui a été causé.

Vous pouvez demander à .reset_index() de supprimer complètement l'index d'origine et de le remplacer par un nouveau par défaut en définissant son paramètre drop sur True. Vous pouvez également réaffecter la référence d'origine au nouveau DataFrame. La version mise à jour sera alors la seule qui existe à partir de maintenant :

>>> beach_boys = (
...     beach_boys.sort_values(by="first_name")
...     .reset_index(drop=True)
... )
>>> beach_boys
  first_name last_name instrument date_of_birth
0         Al   Jardine     Guitar   03-Sep-1942
1    Blondie   Chaplin     Guitar   07-Jul-1951
2      Brian    Wilson       Bass   20-Jun-1942
3      Bruce  Johnston       Bass   27-Jun-1942
4       Carl    Wilson     Guitar   21-Dec-1946
5      David     Marks     Guitar   22-Aug-1948
6     Dennis    Wilson      Drums   04-Dec-1944
7       Mike      Love  Saxophone   15-Mar-1941
8      Ricky    Fataar      Drums   05-Sep-1952

Vous avez maintenant rangé votre DataFrame comme vous le souhaitez. Vous avez également réaffecté la référence d'origine au nouveau DataFrame, ce qui signifie que la colonne index irritante a été coulée sans laisser de trace.

Il est maintenant temps pour vous de vous amuser et de vous amuser en relevant le défi suivant :

Vous avez déjà vu comment il est possible de réinitialiser un index tout en conservant l’ancien. Lorsque vous faites cela, pandas l'ajoute en tant que nouvelle colonne avec le titre index. Jetez un œil à la documentation de .reset_index() et voyez si vous pouvez comprendre comment personnaliser le nom de cette nouvelle colonne.

Relisez maintenant les données de band_members.csv dans un nouveau DataFrame et utilisez beach_boys.index=range(1, 10) pour mettre à jour son index. Enfin, utilisez .reset_index() pour voir si vous pouvez personnaliser votre DataFrame et le faire ressembler à ceci :

>>> beach_boys
   old_index first_name last_name instrument date_of_birth
0          1      Brian    Wilson       Bass   20-Jun-1942
1          2       Mike      Love  Saxophone   15-Mar-1941
2          3         Al   Jardine     Guitar   03-Sep-1942
3          4      Bruce  Johnston       Bass   27-Jun-1942
4          5       Carl    Wilson     Guitar   21-Dec-1946
5          6     Dennis    Wilson      Drums   04-Dec-1944
6          7      David     Marks     Guitar   22-Aug-1948
7          8      Ricky    Fataar      Drums   05-Sep-1952
8          9    Blondie   Chaplin     Guitar   07-Jul-1951

Vous souhaitez vous assurer que l’index existant n’est pas seulement conservé, mais également renommé.

Vous trouverez une solution dans le bloc-notes Solutions.ipynb fourni dans les documents téléchargeables.

Bien que la méthode .reset_index() que vous venez de découvrir soit le moyen le plus personnalisable de réinitialiser un index DataFrame pandas, vous permettant de gérer des multi-index, ce n'est certainement pas le seul moyen. Il est possible de le faire à la manière gremmie en utilisant les premiers principes.

Réinitialiser un index directement avec .index

Lorsque vous travaillez avec des DataFrames, vous pouvez identifier les lignes à l'aide de .loc[] ou .iloc[]. Chacun a son cas d’utilisation, bien que l’un ou l’autre puisse être utilisé sur n’importe quel DataFrame.

L'index d'un DataFrame est référencé à l'aide de sa propriété .index. Pour remplacer l'index actuel par l'un des vôtres, vous attribuez à .index un itérable contenant vos nouvelles étiquettes d'index. Cela vous permet de personnaliser vos index DataFrame au-delà des nombres incrémentiels par défaut.

Avant d'explorer .loc[] et .iloc[], vous ajouterez un index personnalisé à votre DataFrame qui contient les initiales des membres du groupe Beach Boys. Tout d'abord, vous allez lire les données des membres du groupe à partir d'un fichier CSV et les convertir en types de données pyarrow :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> initials = ["BW", "ML", "AJ", "BJ", "CW", "DW", "DM", "RF", "BC"]
>>> beach_boys.index = initials
>>> beach_boys
   first_name last_name instrument date_of_birth
BW      Brian    Wilson       Bass   20-Jun-1942
ML       Mike      Love  Saxophone   15-Mar-1941
AJ         Al   Jardine     Guitar   03-Sep-1942
BJ      Bruce  Johnston       Bass   27-Jun-1942
CW       Carl    Wilson     Guitar   21-Dec-1946
DW     Dennis    Wilson      Drums   04-Dec-1944
DM      David     Marks     Guitar   22-Aug-1948
RF      Ricky    Fataar      Drums   05-Sep-1952
BC    Blondie   Chaplin     Guitar   07-Jul-1951

Vous examinerez une autre manière de réinitialiser un index dans peu de temps, mais vous plongerez d’abord dans la sélection de lignes.

Sélectionnez les lignes à l'aide de .loc[] et .iloc[]

L'attribut .loc[] vous permet d'indexer les lignes par leur étiquette d'index. Ceci est particulièrement utile lorsque les étiquettes d'index sous-jacentes ont une signification intrinsèque dans le DataFrame, comme les noms d'utilisateur ou les horodatages.

Si vous découpez avec .loc[], il utilise un intervalle fermé, ce qui signifie que les valeurs d'index de début et de fin que vous spécifiez apparaîtront dans la sortie. Ainsi, en sélectionnant une tranche de lignes par nom d'utilisateur, votre sortie affichera la première, la dernière et tout le reste.

L'attribut .iloc[] vous permet de rechercher des lignes en fonction de leur position d'index quelle que soit la valeur de l'étiquette d'index. Lorsque vous utilisez .iloc[], vous utilisez une indexation de base zéro. En d'autres termes, la première ligne se trouve à l'emplacement 0, et non à 1 comme on pourrait s'y attendre. .iloc[] utilise un intervalle ouvert, ce qui signifie que même si la valeur de l'index de début que vous spécifiez apparaîtra dans la sortie, celle de fin ne le sera pas.

Bien que ces concepts vous soient très familiers si vous avez déjà découpé une chaîne ou une liste, il est important de noter que l'élément final .iloc[] apparaît pour sélectionner gagné 't réellement être sélectionné.

Bien sûr, peu importe que vous utilisiez .iloc[] ou .loc[] si vous utilisez des index par défaut car ceux-ci utilisent également des séquences de base zéro. , donc leurs étiquettes et leurs positions correspondent. Cependant, si votre index contient des chaînes ou une séquence numérique autre que celle par défaut, les paramètres passés à .iloc[] ne ressembleront pas à la valeur d'index réelle de la ligne à laquelle vous accédez, ce qui rendra votre code plus difficile. lire.

Maintenant que votre DataFrame a été mis à jour avec un nouvel index, vous pouvez l'utiliser pour sélectionner certaines lignes en utilisant à la fois .loc[] et .iloc[] :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> initials = ["BW", "ML", "AJ", "BJ", "CW", "DW", "DM", "RF", "BC"]
>>> beach_boys.index = initials

>>> beach_boys.loc[["BW"]]
   first_name last_name instrument date_of_birth
BW      Brian    Wilson       Bass   20-Jun-1942

>>> beach_boys.iloc[[1]]
   first_name last_name instrument date_of_birth
ML       Mike      Love  Saxophone   15-Mar-1941

>>> beach_boys.loc["BW":"BJ"]
   first_name last_name instrument date_of_birth
BW      Brian    Wilson       Bass   20-Jun-1942
ML       Mike      Love  Saxophone   15-Mar-1941
AJ         Al   Jardine     Guitar   03-Sep-1942
BJ      Bruce  Johnston       Bass   27-Jun-1942

>>> beach_boys.iloc[1:4]
   first_name last_name instrument date_of_birth
ML       Mike      Love  Saxophone   15-Mar-1941
AJ         Al   Jardine     Guitar   03-Sep-1942
BJ      Bruce  Johnston       Bass   27-Jun-1942

À la ligne 8, vous avez accédé à la première ligne dont la valeur d'index est BW en la passant sous forme de chaîne dans .loc[]. En le transmettant sous forme de liste à .loc[["BW"]], votre sortie devient un DataFrame. Vous auriez pu le transmettre directement, mais cela aurait produit une série pandas qui se comporte différemment. Le point principal à noter est qu'en passant une valeur d'index dans .loc[], vous avez renvoyé la ligne dont l'étiquette d'index est cette valeur.

Comparez cela à la sortie après la ligne 12. Le code accède au numéro de ligne 1, cette fois avec .iloc[[1]]. Remarquez à quel point le résultat est différent. L'utilisation de .iloc[[1]] signifie que vous avez sélectionné la deuxième ligne du DataFrame. N'oubliez pas que .iloc[] traite la première ligne du DataFrame comme 0, quelle que soit l'étiquette d'index réelle.

À la ligne 16, vous avez sélectionné les quatre premières lignes en passant les étiquettes des première et quatrième lignes dans .loc[].

Enfin, lorsque vous avez passé la tranche 1:4 dans .iloc[] à la ligne 23, vous avez sélectionné les lignes commençant à la première position d'index, en d'autres termes, la deuxième ligne. mais se terminant à la position d'index trois. Encore une fois, cela est dû à l'effet de numérotation de base zéro des lignes et au fait que le dernier paramètre de tranche de la position 4 est exclu. N'oubliez pas que .iloc[] suppose un intervalle ouvert.

Il est maintenant temps pour vous de tenter un autre défi. Si vous vous trompez, vous pouvez toujours le refaire :

Encore une fois, relisez les données de band_members.csv dans un nouveau DataFrame. Maintenant, voyez si vous pouvez créer le DataFrame ci-dessous en attribuant une liste appropriée à beach_boys.index, puis sélectionnez les deux lignes du bas en utilisant à la fois .loc[] et .iloc[] :

>>> beach_boys
   first_name last_name instrument date_of_birth
2       Brian    Wilson       Bass   20-Jun-1942
4        Mike      Love  Saxophone   15-Mar-1941
6          Al   Jardine     Guitar   03-Sep-1942
8       Bruce  Johnston       Bass   27-Jun-1942
10       Carl    Wilson     Guitar   21-Dec-1946
12     Dennis    Wilson      Drums   04-Dec-1944
14      David     Marks     Guitar   22-Aug-1948
16      Ricky    Fataar      Drums   05-Sep-1952
18    Blondie   Chaplin     Guitar   07-Jul-1951

Cette fois, votre index contient des nombres pairs commençant à 2.

Vous trouverez une solution dans le bloc-notes Solutions.ipynb fourni dans les documents téléchargeables.

Jusqu'à présent, vous avez utilisé .reset_index() et .index pour réinitialiser un index DataFrame pandas. Il est maintenant temps de faire un carve et d'envisager une autre alternative.

Réinitialiser un index directement avec .set_axis()

Une troisième façon de réinitialiser un index consiste à utiliser la méthode .set_axis() du DataFrame. Cette méthode vous permet d'attribuer un nouvel objet RangeIndex à votre DataFrame, et vous permet également de modifier les étiquettes des colonnes.

Pour modifier l'index existant d'un DataFrame, vous pouvez transmettre .set_axis() un objet range à l'aide du constructeur intégré range(). Cela attribuera un intervalle d'entiers croissants à l'index qui commence à zéro :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> beach_boys.set_axis(range(len(beach_boys)))
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
3      Bruce  Johnston       Bass   27-Jun-1942
4       Carl    Wilson     Guitar   21-Dec-1946
5     Dennis    Wilson      Drums   04-Dec-1944
6      David     Marks     Guitar   22-Aug-1948
7      Ricky    Fataar      Drums   05-Sep-1952
8    Blondie   Chaplin     Guitar   07-Jul-1951

Ici, vous avez utilisé .set_axis() pour réinitialiser l'index à sa valeur par défaut. Pour ce faire, vous avez passé à .set_axis() une range dont la longueur était égale à celle du DataFrame beach_boys d'origine. L'utilisation de len() garantit qu'il y a le nombre correct de nombres pour chaque ligne du DataFrame. Les nombres générés seront de base zéro et seront juste suffisants pour couvrir chaque ligne. Comme vous pouvez le constater, l'index a désormais été réinitialisé à sa valeur par défaut.

Encore une fois, il est temps de vérifier votre compréhension. N'hésitez pas à demander de l'aide à un ami, mais seulement s'il s'appelle Rhonda :

Relisez les données de band_members.csv Maintenant, utilisez .set_axis() pour voir si vous pouvez le faire ressembler à ceci :

>>> beach_boys
   first_name last_name instrument date_of_birth
0       Brian    Wilson       Bass   20-Jun-1942
1        Mike      Love  Saxophone   15-Mar-1941
4          Al   Jardine     Guitar   03-Sep-1942
9       Bruce  Johnston       Bass   27-Jun-1942
16       Carl    Wilson     Guitar   21-Dec-1946
25     Dennis    Wilson      Drums   04-Dec-1944
36      David     Marks     Guitar   22-Aug-1948
49      Ricky    Fataar      Drums   05-Sep-1952
64    Blondie   Chaplin     Guitar   07-Jul-1951

Cette fois, vous voulez que chaque valeur de l'index par défaut soit au carré.

Comme d'habitude, vous trouverez une solution dans le notebook Solutions.ipynb fourni dans les documents téléchargeables.

In [1]: import pandas as pd

In [2]: beach_boys = pd.read_csv(
   ...:     "band_members.csv"
   ...: ).convert_dtypes(dtype_backend="pyarrow")

In [3]: %timeit -n 1000 beach_boys.reset_index(drop=True)
22.5 µs ± 1.71 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [4]: %timeit -n 1000 beach_boys.index = pd.RangeIndex(len(beach_boys.index))
3.75 µs ± 307 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

In [5]: %timeit -n 1000 beach_boys.set_axis(range(len(beach_boys)))
28.1 µs ± 1.89 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

Comme vous pouvez le voir sur ces trois timings, si tout ce dont vous avez besoin est de réinitialiser un index à sa valeur par défaut, l'attribution d'un objet RangeIndex directement à la propriété .index de votre DataFrame est la méthode la plus rapide. des trois. C'est également le seul moyen de réinitialiser l'index sur le DataFrame d'origine. Les deux autres méthodes créent une copie que vous pouvez réattribuer à la variable beach_boys. Cependant, .reset_index(), bien que lent, offre plus d'options de configuration.

Notez que vos chiffres de timing exacts seront différents de ceux présentés ici, mais ils devraient montrer la même tendance.

Maintenant que vous savez comment réinitialiser l'index d'un DataFrame, vous allez passer à autre chose et découvrir pourquoi vous voudriez faire cela. Il n’est pas encore temps de se détendre.

Restaurer un index séquentiel

Lorsque vous nettoyez les données avant l'analyse, vous devez souvent supprimer certaines lignes d'un DataFrame. Par exemple, vous devrez peut-être supprimer les lignes en double ou indésirables. Lorsque vous les supprimez, les valeurs d'index des lignes sont également supprimées. Cela pourrait entraîner l'apparition de lacunes dans l'indice. En réinitialisant l'index, vous pouvez résoudre ce problème.

Plus tard, dans la section sur l'alignement des index de plusieurs DataFrames, vous apprendrez comment les valeurs manquantes dans l'index d'un DataFrame peuvent faire des ravages lorsque vous devez analyser ses données. Pour l'instant, vous allez gâcher l'index de votre adorable DataFrame beach_boys :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> beach_boys
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
3      Bruce  Johnston       Bass   27-Jun-1942
4       Carl    Wilson     Guitar   21-Dec-1946
5     Dennis    Wilson      Drums   04-Dec-1944
6      David     Marks     Guitar   22-Aug-1948
7      Ricky    Fataar      Drums   05-Sep-1952
8    Blondie   Chaplin     Guitar   07-Jul-1951

>>> beach_boys.drop(labels=[3, 5])
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
4       Carl    Wilson     Guitar   21-Dec-1946
6      David     Marks     Guitar   22-Aug-1948
7      Ricky    Fataar      Drums   05-Sep-1952
8    Blondie   Chaplin     Guitar   07-Jul-1951

Comme vous pouvez le voir, le DataFrame contient les neuf lignes originales de membres du groupe avec un index par défaut. Pour supprimer certaines lignes, vous avez utilisé la méthode .drop() du DataFrame. Les lignes à supprimer ont été définies dans la liste Python fournie à son paramètre labels. Dans ce cas, les lignes dont l'étiquette d'index est 3 ou 5 ont toutes deux été supprimées. Regardez attentivement l'index dans le résultat produit sous la ligne 17 et vous verrez que l'index n'est plus séquentiel.

Pour résoudre ce problème, vous pouvez utiliser l’une des techniques que vous avez apprises jusqu’à présent. Ici, vous utiliserez .reset_index() qui, parce qu'il ne modifie pas le DataFrame sous-jacent, signifie que vous pouvez réutiliser le DataFrame d'origine proprement indexé dans des exemples ultérieurs :

>>> (
...     beach_boys
...     .drop(labels=[3, 5])
...     .reset_index()
... )
   index first_name last_name instrument date_of_birth
0      0      Brian    Wilson       Bass   20-Jun-1942
1      1       Mike      Love  Saxophone   15-Mar-1941
2      2         Al   Jardine     Guitar   03-Sep-1942
3      4       Carl    Wilson     Guitar   21-Dec-1946
4      6      David     Marks     Guitar   22-Aug-1948
5      7      Ricky    Fataar      Drums   05-Sep-1952
6      8    Blondie   Chaplin     Guitar   07-Jul-1951

Comme vous l'avez vu précédemment, .reset_index() a ajouté un nouvel index par défaut à votre DataFrame. Cependant, vous n’êtes pas encore satisfait car votre index d’origine reste toujours, bien que dans une nouvelle colonne. Encore une fois, vous devez ajuster le paramètre drop de .reset_index() pour terminer le travail :

>>> (
...     beach_boys
...     .drop(labels=[3, 5])
...     .reset_index(drop=True)
... )
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
3       Carl    Wilson     Guitar   21-Dec-1946
4      David     Marks     Guitar   22-Aug-1948
5      Ricky    Fataar      Drums   05-Sep-1952
6    Blondie   Chaplin     Guitar   07-Jul-1951

Comme vous pouvez le voir, en définissant drop=True, l'index d'origine est désormais introuvable, mais votre nouveau brillant a l'air, enfin, neuf et brillant.

Encore une fois, il est temps de vérifier votre compréhension. Oh, et si vous n'arrivez pas à comprendre, Ne vous inquiétez pas bébé :

Pour commencer, relisez les données de band_members.csv, puis utilisez beach_boys.drop(labels=[3, 5]) pour supprimer certaines lignes. Vous venez d'apprendre comment réinitialiser l'index à sa valeur par défaut en utilisant .reset_index(drop=True). Voyez si vous pouvez recommencer en utilisant l’une des deux autres techniques que vous avez apprises. Votre réponse devrait ressembler à ceci :

>>> beach_boys
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2         Al   Jardine     Guitar   03-Sep-1942
3       Carl    Wilson     Guitar   21-Dec-1946
4      David     Marks     Guitar   22-Aug-1948
5      Ricky    Fataar      Drums   05-Sep-1952
6    Blondie   Chaplin     Guitar   07-Jul-1951

Comme vous pouvez le constater, l'index par défaut a été restauré et l'original est introuvable.

Comme pour les autres exercices, vous trouverez une solution dans le cahier Solutions.ipynb fourni dans les supports téléchargeables.

Tous vos efforts jusqu'à présent peuvent signifier que vous voyez maintenant une nageoire jumelle. Ensuite, vous reviendrez sur votre tableau et vous débarrasserez de ces doublons.

Supprimer les valeurs d'index en double

Vous serez peut-être surpris d'apprendre que les index peuvent parfois avoir des valeurs en double. Il ne doit pas nécessairement s’agir d’identifiants uniques. Cependant, les doublons sont généralement quelque chose que vous souhaitez éviter car ils peuvent causer des problèmes. Heureusement, .reset_index() peut gérer cela pour vous.

Des valeurs d'index en double surviennent souvent lorsque deux DataFrames sont fusionnés. La duplication peut entraîner des problèmes de sélection, de découpage et de filtrage de lignes incorrects. Avant de voir ces problèmes, vous devez d’abord appliquer des valeurs en double à votre index :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> guitar_players = beach_boys.query(
...     "instrument == 'Guitar'"
... ).reset_index(drop=True)

>>> guitar_players
  first_name last_name instrument date_of_birth
0         Al   Jardine     Guitar   03-Sep-1942
1       Carl    Wilson     Guitar   21-Dec-1946
2      David     Marks     Guitar   22-Aug-1948
3    Blondie   Chaplin     Guitar   07-Jul-1951

>>> others = beach_boys.query(
...     "instrument != 'Guitar'"
... ).reset_index(drop=True)

>>> others
  first_name last_name instrument date_of_birth
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2      Bruce  Johnston       Bass   27-Jun-1942
3     Dennis    Wilson      Drums   04-Dec-1944
4      Ricky    Fataar      Drums   05-Sep-1952

Ici, vous avez divisé le DataFrame d'origine en deux nouveaux. Le DataFrame guitar_players, illustré sous la ligne 9, contient les enregistrements des membres du groupe qui jouent de la guitare. Le DataFrame others, affiché sous la ligne 20, contient le reste des membres.

Pour sélectionner les guitaristes, vous avez transmis la chaîne de requête "instrument == 'Guitar'" dans .query() aux lignes 5 à 7, qui extrait toutes les lignes où le Les valeurs de la colonne instrument correspondent à "Guitare".

Les lignes 16 à 18 utilisent un code similaire qui crée un deuxième DataFrame contenant les autres lignes. Dans ce cas, il s’agit de musiciens qui ne sont pas marqués comme guitaristes.

Dans les deux cas, .reset_index() a été utilisé pour garantir que l'index dans les deux nouveaux DataFrames était séquentiel. Cela garantissait que certaines valeurs d'index identiques apparaissaient dans les deux DataFrames. Lorsque vous fusionnez les deux, vous pourriez penser que vous reviendrez à votre DataFrame d’origine, mais vous ne le ferez pas :

>>> all_beach_boys = pd.concat([guitar_players, others])

>>> all_beach_boys
  first_name last_name instrument date_of_birth
0         Al   Jardine     Guitar   03-Sep-1942
1       Carl    Wilson     Guitar   21-Dec-1946
2      David     Marks     Guitar   22-Aug-1948
3    Blondie   Chaplin     Guitar   07-Jul-1951
0      Brian    Wilson       Bass   20-Jun-1942
1       Mike      Love  Saxophone   15-Mar-1941
2      Bruce  Johnston       Bass   27-Jun-1942
3     Dennis    Wilson      Drums   04-Dec-1944
4      Ricky    Fataar      Drums   05-Sep-1952

Vous avez créé un seul nouveau DataFrame en utilisant concat(). En lui transmettant à la fois guitar_players et others, votre nouveau DataFrame all_beach_boys affiche à nouveau les neuf membres originaux du groupe, mais l'index contient des doublons. Maintenant que vous disposez d’un DataFrame avec des index en double, vous allez étudier les problèmes que cela peut causer.

Supposons que vous souhaitiez sélectionner la quatrième ligne, la ligne dont la position d'index est 3. Vous ne pouvez pas utiliser .loc[] pour ce faire car l'index en double provoque des problèmes. Exécutez le code ci-dessous et vous verrez le problème :

>>> all_beach_boys.loc[3]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951
3     Dennis    Wilson      Drums   04-Dec-1944

>>> all_beach_boys.iloc[[3]]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951

Jetez un œil aux lignes en surbrillance. Comme vous pouvez le constater, étant donné que .loc[] a sélectionné des lignes dont l'étiquette d'index est 3, deux enregistrements ont été renvoyés. Pour résoudre ce problème, vous devrez utiliser .iloc[] pour sélectionner la seule ligne requise.

Les valeurs d'index en double provoquent également des ravages lorsque vous essayez de sélectionner des lignes contiguës à l'aide du découpage. Supposons que vous vouliez voir les lignes aux positions d'index trois et quatre. Votre première tentative pourrait être d'essayer .loc[] :

>>> all_beach_boys.loc[3:4]
Traceback (most recent call last):
  ...
KeyError: 'Cannot get left slice bound for non-unique label: 3'

>>> all_beach_boys.iloc[3:5]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951
0      Brian    Wilson       Bass   20-Jun-1942

Comme vous pouvez le voir, lorsque vous essayez de transmettre les positions d'index requises dans .loc[], une exception KeyError est générée car vous avez une étiquette non unique. Pour résoudre ce problème, vous devrez plutôt utiliser .iloc[].

>>> all_beach_boys.sort_index().loc[3:4]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951
3     Dennis    Wilson      Drums   04-Dec-1944
4      Ricky    Fataar      Drums   05-Sep-1952

Comme vous pouvez le voir, les lignes avec les étiquettes d'index 3 et 4 ont été renvoyées.

Supposons que vous souhaitiez maintenant voir ces éléments avec les étiquettes d'index 1 et 3. Cette fois, vous utilisez la méthode .filter() du DataFrame :

>>> all_beach_boys.filter(items=[1, 3], axis="index")
Traceback (most recent call last):
  ...
ValueError: cannot reindex on an axis with duplicate labels

Vous avez essayé de filtrer le DataFrame avec les étiquettes d'index 1 et 3 en les transmettant sous forme de liste au paramètre items de .filter(). Vous avez également défini le paramètre axis sur "index" pour appliquer le filtre à l'index. Bien que votre code soit techniquement correct, le résultat est une exception ValueError en raison des étiquettes en double.

En ce moment, vous vous sentez probablement un peu en chiffon avec tous ces revers. Il est temps de remonter sur votre tableau et de résoudre les problèmes :

Voyez si vous pouvez corriger ce code afin que .loc[] et .iloc[] produisent les mêmes résultats, et ainsi .filter() fonctionne comme prévu lorsqu'il est appliqué à all_beach_boys. Assurez-vous également que l’ancien index problématique a été supprimé :

>>> all_beach_boys.loc[[3]]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951

>>> all_beach_boys.iloc[[3]]
  first_name last_name instrument date_of_birth
3    Blondie   Chaplin     Guitar   07-Jul-1951

>>> all_beach_boys.filter(items=[1, 3], axis="index")
  first_name last_name instrument date_of_birth
1       Carl    Wilson     Guitar   21-Dec-1946
3    Blondie   Chaplin     Guitar   07-Jul-1951

Bien joué. Tout fonctionne !

Supposons maintenant que vous souhaitiez promouvoir une colonne existante en index. Est-ce possible ? Il est temps de passer, attraper une vague et voir.

Utiliser une colonne existante comme index

Bien que l'index numérique séquentiel par défaut fournisse un accesseur unique aux lignes de votre DataFrame, il est peu probable qu'il ait une signification inhérente. Par exemple, les numéros attribués à chaque ligne des DataFrames que vous avez utilisés jusqu'à présent n'ont aucune signification par rapport aux données qu'ils indexent.

Dans le DataFrame lu à partir de band_members.csv, le membre du groupe Brian Wilson a une valeur d'index de 0 simplement parce qu'il apparaît en premier dans le fichier. Cela n’a aucune signification inhérente, même si cela peut vous offenser si vous êtes un fan et pensez qu’il devrait être le numéro 1.

Bien que le concept d'utilisation d'un index séquentiel non lié vous soit familier si vous avez travaillé avec des clés dans une base de données relationnelle, vous souhaiterez peut-être quelque chose de plus significatif dans vos DataFrames.

Si vous souhaitez des étiquettes d'index plus conviviales, vous pouvez utiliser une colonne existante et la promouvoir dans l'index. Pour ce faire, vous utilisez la méthode .set_index(). Bien que vous puissiez promouvoir n'importe quelle colonne existante pour devenir l'index, gardez à l'esprit qu'à moins que la colonne prévue ne contienne des valeurs uniques, vous rencontrerez toujours les mêmes problèmes de doublons que ceux que vous avez vus précédemment.

Supposons que vous souhaitiez réinitialiser votre index pour qu'il contienne les étiquettes first_name. Vous pouvez procéder comme indiqué ici :

>>> beach_boys = pd.read_csv(
...     "band_members.csv"
... ).convert_dtypes(dtype_backend="pyarrow")

>>> (
...     beach_boys
...     .set_index("first_name")
...     .loc[["Brian", "Carl"]]
... )
           last_name instrument date_of_birth
first_name
Brian         Wilson       Bass   20-Jun-1942
Carl          Wilson     Guitar   21-Dec-1946

Lorsque vous appelez .set_index() sur beach_boys et transmettez "first_name", cette colonne est promue à l'index. Vous pouvez ensuite utiliser .loc[] pour sélectionner une ou plusieurs lignes en utilisant les prénoms des musiciens qui vous intéressent.

Dans certains cas, vous souhaiterez peut-être réinitialiser votre index afin que ses valeurs existantes deviennent plus significatives pour les données qu'elles indexent. Bien que vous ne puissiez pas utiliser .reset_index() pour cela, vous pouvez appliquer quelque chose de plus approprié à l'attribut .index du DataFrame.

Un exemple courant consiste à utiliser des identifiants d’employés au lieu de simples entiers séquentiels. Le code ci-dessous met à jour l'index séquentiel existant avec des valeurs plus contextuelles :

>>> beach_boys.index = [f"Employee_{x + 1}" for x in range(len(beach_boys))]

>>> beach_boys
           first_name last_name instrument date_of_birth
Employee_1      Brian    Wilson       Bass   20-Jun-1942
Employee_2       Mike      Love  Saxophone   15-Mar-1941
Employee_3         Al   Jardine     Guitar   03-Sep-1942
Employee_4      Bruce  Johnston       Bass   27-Jun-1942
Employee_5       Carl    Wilson     Guitar   21-Dec-1946
Employee_6     Dennis    Wilson      Drums   04-Dec-1944
Employee_7      David     Marks     Guitar   22-Aug-1948
Employee_8      Ricky    Fataar      Drums   05-Sep-1952
Employee_9    Blondie   Chaplin     Guitar   07-Jul-1951

Dans ce code, vous avez utilisé une compréhension de liste pour créer une liste de chaînes contenant ["Employee_1", "Employee_2", ...]. Ceci est ensuite attribué à l'attribut .index de beach_boys.

Maintenant que vous disposez d’un index plus significatif, vous pouvez l’utiliser de la même manière que vous avez utilisé l’index numérique par défaut. Par exemple, vous pouvez sélectionner des lignes en fonction de leurs nouvelles valeurs Employee_ :

>>> beach_boys.loc[["Employee_4"]]
           first_name last_name instrument date_of_birth
Employee_4      Bruce  Johnston       Bass   27-Jun-1942

Dans le code ci-dessus, vous avez utilisé .loc[] pour sélectionner l'enregistrement de Employee_4.

Maintenant, un peu de folie. Ne serait-ce pas bien si vous pouviez faire ceci :

À l'aide du DataFrame original beach_boys lu à partir de band_members.csv, créez un index composé des noms d'utilisateur du personnel au format . Votre résultat final devrait ressembler à ceci :

>>> beach_boys
          first_name last_name instrument date_of_birth
WilsonB        Brian    Wilson       Bass   20-Jun-1942
LoveM           Mike      Love  Saxophone   15-Mar-1941
JardineA          Al   Jardine     Guitar   03-Sep-1942
JohnstonB      Bruce  Johnston       Bass   27-Jun-1942
WilsonC         Carl    Wilson     Guitar   21-Dec-1946
WilsonD       Dennis    Wilson      Drums   04-Dec-1944
MarksD         David     Marks     Guitar   22-Aug-1948
FataarR        Ricky    Fataar      Drums   05-Sep-1952
ChaplinB     Blondie   Chaplin     Guitar   07-Jul-1951

Comme vous pouvez le constater, l'index contient désormais un format de nom d'utilisateur commun, ce qui facilitera la sélection des utilisateurs par leur nom d'utilisateur.

Ensuite, vous acquerrez une certaine expérience du surf en tandem. Il est temps d’utiliser non pas un, mais deux DataFrames ensemble.

Aligner les index de plusieurs DataFrames

L'une des fonctionnalités intéressantes de l'utilisation des pandas DataFrames est que vous pouvez utiliser les opérateurs arithmétiques de base pour additionner leurs données. Malheureusement, vous ne bénéficierez de cette commodité que si leurs index s’alignent. Sinon, vous rencontrerez des problèmes.

Supposons que vous analysiez les ventes hebdomadaires de disques d'un magasin de disques. Deux semaines de données de ventes sont stockées dans deux fichiers CSV nommés week1_record_sales.csv et week2_record_sales.csv. À des fins de démonstration, les deux fichiers contiennent des données de ventes identiques mais leurs index sont différents :

>>> week1_sales = pd.read_csv(
...     "week1_record_sales.csv"
... ).set_index("index")

>>> week2_sales = pd.read_csv(
...     "week2_record_sales.csv"
... ).set_index("index")

>>> week1_sales
       day  sales
index
0      Mon    100
1      Tue    150
2      Wed    200
3      Thu    250
4      Fri    300

>>> week2_sales
       day  sales
index
1      Mon    100
2      Tue    150
3      Wed    200
4      Thu    250
5      Fri    300

Chaque fichier est lu dans un DataFrame et contient des informations sur les ventes quotidiennes. Chaque ligne est identifiée par sa colonne index, qui a été définie comme index du DataFrame avec .set_index().

Supposons que vous souhaitiez maintenant connaître le total des ventes des deux semaines. Cela devrait être réalisable avec un peu plus qu’une simple opération arithmétique :

>>> week1_sales["sales"] + week2_sales["sales"]
index
0      NaN
1    250.0
2    350.0
3    450.0
4    550.0
5      NaN
Name: sales, dtype: float64

Comme vous pouvez le constater, quelque chose ne va pas. Étant donné que les deux DataFrames contiennent les mêmes données, vous vous attendez à ce que les réponses soient le double de leurs valeurs d'origine. Au lieu de cela, la première et la dernière réponse sont NaN, ce qui signifie qu'un calcul arithmétique n'a pas pu être effectué en raison de valeurs manquantes. De plus, les autres résultats sont incorrects.

Ces deux problèmes étaient causés par des index incompatibles. Les valeurs NaN sont apparues car ni l'index 0 ni l'index 5 n'apparaissent dans vos deux DataFrames. Les calculs sont erronés car, par exemple, le chiffre d'affaires du mercredi de 200 est indexé comme 2 dans votre premier DataFrame, alors que l'index 2 fait référence aux ventes du mardi de 150 dans votre deuxième DataFrame. Lorsque vous les ajoutez, le résultat n’a aucun sens.

Vous pouvez également fusionner deux DataFrames de la même manière que les tables de bases de données relationnelles peuvent être fusionnées. Cela vous permet de voir les données correspondantes des deux DataFrames au même endroit. Encore une fois, si vous rejoignez sur index, chaque valeur d'index doit faire référence aux données associées dans les deux DataFrames.

Par exemple, supposons que vous vouliez voir toutes les données des deux semaines de ventes. Pour ce faire, vous pouvez utiliser la méthode .merge() du DataFrame :

>>> week1_sales.merge(week2_sales, left_index=True, right_index=True)
      day_x  sales_x day_y  sales_y
index
1       Tue      150   Mon      100
2       Wed      200   Tue      150
3       Thu      250   Wed      200
4       Fri      300   Thu      250

Tout de suite, vous pouvez voir certains problèmes. Ni les enregistrements avec l'index 0 ni l'index 5 ne sont visibles nulle part. Les chiffres quotidiens ne correspondent pas non plus.

Ici, vous avez effectué une jointure interne des deux DataFrames, ce qui signifie que seuls les enregistrements dont les valeurs d'index apparaissent dans les deux DataFrames seront fusionnés. Étant donné que les valeurs d'index 0 et 5 n'apparaissent pas dans les deux, elles ne sont pas incluses dans la fusion. Les jours ne correspondent pas car le même index fait référence à des jours différents dans chaque DataFrame.

Pour résoudre ces deux problèmes, vous devez vous assurer que les deux DataFrames utilisent le même index. Une solution serait de réinitialiser l'index de week2_sales à sa valeur par défaut. Cela correspondra alors à celui utilisé par week1_sales, mais uniquement parce que les données quotidiennes des deux DataFrames sont déjà dans le même ordre :

>>> week2_sales = week2_sales.reset_index(drop=True)

Comme auparavant, pour réinitialiser l'index à sa valeur par défaut, vous utilisez .reset_index() et transmettez True à son paramètre drop pour supprimer le problème. indice d'origine. Désormais, lorsque vous exécutez les deux morceaux de code précédents, les résultats sont bien plus acceptables :

>>> week1_sales["sales"] + week2_sales["sales"]
index
0    200
1    300
2    400
3    500
4    600
Name: sales, dtype: int64

>>> week1_sales.merge(week2_sales, left_index=True, right_index=True)
      day_x  sales_x day_y  sales_y
index
0       Mon      100   Mon      100
1       Tue      150   Tue      150
2       Wed      200   Wed      200
3       Thu      250   Thu      250
4       Fri      300   Fri      300

Comme vous pouvez le constater, tout correspond désormais et rien ne manque. L’alignement des index a résolu les deux problèmes d’un seul coup. Cependant, cet exemple n'a fonctionné que parce que les lignes des DataFrames étaient dans le bon ordre au départ. Ce ne sera pas toujours le cas.

Cette fois, vous allez penser latéralement. Alors donnez un Wipeout à votre cerveau et voyez si vous pouvez résoudre cet exercice :

Supposons que vous soyez satisfait de l'index de week2_sales, mais pas de celui du DataFrame week1_sales. Voyez si vous pouvez utiliser l'une des techniques que vous avez apprises précédemment pour appliquer l'index de week2_sales à celui de week1_sales. N'oubliez pas de vous assurer que l'ajout et .merge() produisent toujours le résultat correct.

Jusqu'à présent, vous avez fusionné les DataFrames sur des index numériques. Pouvez-vous penser à une meilleure alternative qui fonctionnerait toujours même si les deux DataFrames d'origine avaient leurs lignes dans un ordre différent ? Encore une fois, assurez-vous que l'ajout et .merge() produisent le résultat correct.

N'oubliez pas que vous pouvez toujours consulter la solution dans vos documents téléchargés.

Pour compléter votre expérience d'apprentissage, vous terminerez par apprendre à réinitialiser les index multi-niveaux sur les DataFrames. Ce n’est pas quelque chose que font habituellement les surfeurs, à moins qu’ils ne soient des pythonistes comme vous.

Réinitialiser les multi-index

Chacun des DataFrames avec lesquels vous avez travaillé jusqu'à présent était constitué d'objets Index à une seule colonne. Les DataFrames prennent également en charge les objets MultiIndex, qui fournissent des index hiérarchiques ou multi-niveaux pour vos DataFrames.

Dans cette section, vous commencez à vous réveiller de votre Rêve californien des Beach Boys et décidez de prendre votre petit-déjeuner. Vous utiliserez le fichier cereals.csv pour vous aider à décider quelles céréales manger. Ce fichier contient des données sur diverses céréales pour petit-déjeuner populaires provenant de divers fabricants. Les données originales proviennent de Kaggle et sont disponibles gratuitement sous la licence Creative Commons. Ici, vous en utilisez une version réduite.

La première chose à faire est de lire les données des céréales dans un DataFrame :

>>> cereals = pd.read_csv("cereals.csv").convert_dtypes(
...     dtype_backend="pyarrow"
... )
>>> cereals.head()
                        name    manufacturer  type  fiber
0                  100% Bran         Nabisco  Cold   10.0
1          100% Natural Bran     Quaker Oats  Cold    2.0
2                   All-Bran        Kelloggs  Cold    9.0
3  All-Bran with Extra Fiber        Kelloggs  Cold   14.0
4             Almond Delight  Ralston Purina  Cold    1.0

Comme vous pouvez le constater, le fichier contient des détails sur différentes céréales pour petit-déjeuner. Lorsque vous appelez la méthode .head() du DataFrame, vous voyez les cinq premiers enregistrements qui révèlent le nom et le fabricant de la céréale. Vous pouvez également voir son type, qui vous indique si la céréale doit être consommée chaude ou froide, ainsi que sa teneur en fibres.

Sans surprise, ce DataFrame possède un index simple. Un moyen rapide de créer un MultiIndex consiste à créer un tableau croisé dynamique à partir de celui-ci :

>>> cereals.pivot_table(
...     values="fiber",
...     index=["manufacturer", "type"],
...     aggfunc="mean",
... )
                                     fiber
manufacturer                type
American Home Food Products Hot        0.0
General Mills               Cold  1.272727
Kelloggs                    Cold   2.73913
Nabisco                     Cold       4.6
                            Hot        1.0
Post                        Cold  2.777778
Quaker Oats                 Cold  1.142857
                            Hot        2.7
Ralston Purina              Cold     1.875

Ce tableau croisé dynamique, qui est en fait un autre DataFrame, analyse les données brutes en calculant la teneur moyenne en fibres pour chaque type de céréale pour chaque fabricant. L’index de ce DataFrame est un peu différent de ce que vous avez l’habitude de voir :

>>> cereals.pivot_table(
...     values="fiber",
...     index=["manufacturer", "type"],
...     aggfunc="mean",
... ).index
MultiIndex([('American Home Food Products',  'Hot'),
            (              'General Mills', 'Cold'),
            (                   'Kelloggs', 'Cold'),
            (                    'Nabisco', 'Cold'),
            (                    'Nabisco',  'Hot'),
            (                       'Post', 'Cold'),
            (                'Quaker Oats', 'Cold'),
            (                'Quaker Oats',  'Hot'),
            (             'Ralston Purina', 'Cold')],
           names=['manufacturer', 'type'])

Le MultiIndex dans ce tableau croisé dynamique se compose à la fois des colonnes fabricant et type. Au lieu des simples colonnes uniques que vous avez vues jusqu’à présent, vous disposez désormais d’une structure à plusieurs niveaux plus complexe.

Dans cet exemple, vous avez créé un MultiIndex composé de deux niveaux. Ceux-ci sont définis en passant "manufacturer" et "type" au paramètre index de .pivot_table().

Dans l'objet MultiIndex, fabricant est connu comme niveau 0, tandis que type est niveau 1.. Ces numéros de niveau sont importants si vous devez réinitialiser l'index car ils vous permettent de le faire à un niveau spécifique, voire de le réinitialiser complètement.

Supposons que vous souhaitiez réinitialiser uniquement le niveau 1, correspondant au type, ce qui le relègue dans une colonne distincte avant de le supprimer complètement :

>>> cereals = pd.read_csv("cereals.csv").convert_dtypes(dtype_backend="pyarrow")
>>> cereals.pivot_table(
...     values="fiber",
...     index=["manufacturer", "type"],
...     aggfunc="mean"
... ).reset_index(level=1, drop=True)

>>> cereals
                                fiber
manufacturer
American Home Food Products       0.0
General Mills                1.272727
Kelloggs                      2.73913
Nabisco                           4.6
Nabisco                           1.0
Post                         2.777778
Quaker Oats                  1.142857
Quaker Oats                       2.7
Ralston Purina                  1.875

En passant à la fois level=1 et drop=True à .reset_index(), vous supprimez les détails type, en conservant uniquement les informations fabricant sous la forme d'un simple Index.

Faites attention lorsque vous faites cela, car vous avez maintenant créé des valeurs d'index en double avec tous les problèmes que vous avez vus précédemment. De plus, vos données ont désormais perdu un peu de leur sens. Par exemple, il existe une confusion quant à ce que les étiquettes Nabisco et Quaker Oats vous montrent. Vous ne savez plus laquelle fait référence aux céréales chaudes et laquelle aux céréales froides.

Sachez que la réinitialisation d'une partie d'un MultiIndex peut avoir des effets secondaires indésirables qui ne sont pas toujours évidents.

Il est temps de Attraper une vague et de partir en Surfin' Safari à travers votre avant-dernier défi :

En utilisant le code précédent à titre indicatif, voyez si vous pouvez produire ce résultat exact pour clarifier la confusion entre Nabisco et Quaker Oats :

>>> cereals
                     manufacturer     fiber
type
Cold                General Mills  1.272727
Cold                     Kelloggs   2.73913
Cold                      Nabisco       4.6
Cold                         Post  2.777778
Cold                  Quaker Oats  1.142857
Cold               Ralston Purina     1.875
Hot   American Home Food Products       0.0
Hot                       Nabisco       1.0
Hot                   Quaker Oats       2.7

Les informations type forment l'index tandis que les informations fabricant sont de retour dans une colonne.

Parfois, il est préférable de réinitialiser tous les niveaux d'un MultiIndex mais de conserver toutes les données. Lorsque vous appliquez .reset_index() à un MultiIndex en utilisant ses paramètres par défaut, vous remplacez l'index complet par une version simple par défaut et créez des colonnes supplémentaires à partir de l'index d'origine à l'intérieur. votre DataFrame :

>>> cereals.pivot_table(
...     values="fiber",
...     index=["manufacturer", "type"],
...     aggfunc="mean",
... ).reset_index()
                  manufacturer  type     fiber
0  American Home Food Products   Hot       0.0
1                General Mills  Cold  1.272727
2                     Kelloggs  Cold   2.73913
3                      Nabisco  Cold       4.6
4                      Nabisco   Hot       1.0
5                         Post  Cold  2.777778
6                  Quaker Oats  Cold  1.142857
7                  Quaker Oats   Hot       2.7
8               Ralston Purina  Cold     1.875

Cette fois, votre DataFrame a un index par défaut qui lui est appliqué, mais il a également de nouvelles colonnes manufacturer et type, ainsi que les colonnes agrégées fibre données. Surtout, les données n’ont rien perdu de leur sens.

Ce dernier défi testera les bonnes vibrations que vous possédez désormais concernant votre capacité à travailler avec les index DataFrame.

Voyez si vous pouvez résoudre les effets secondaires indésirables de votre tableau croisé dynamique d'origine en aplatissant le MultiIndex. Peut-être que cela ressemblera à ceci :

>>> cereals
                                       fiber
(American Home Food Products, Hot)       0.0
(General Mills, Cold)               1.272727
(Kelloggs, Cold)                     2.73913
(Nabisco, Cold)                          4.6
(Nabisco, Hot)                           1.0
(Post, Cold)                        2.777778
(Quaker Oats, Cold)                 1.142857
(Quaker Oats, Hot)                       2.7
(Ralston Purina, Cold)                 1.875

L'index se compose désormais d'un niveau au lieu de deux, mais chaque niveau est un tuple.

C'est ça! Vous devriez être ravi de savoir désormais comment réinitialiser l'index de vos DataFrames à l'aide de plusieurs techniques. Vous avez également suivi une leçon bonus sur la façon d'incorporer des titres de chansons des Beach Boys et des références de surf ringardes dans un didacticiel Python. Un original vraiment rad de la part de vos amis de Real Python.

Conclusion

Dans ce didacticiel, vous avez appris que même si la méthode .reset_index() constitue le moyen le plus personnalisable de réinitialiser un index, ce n'est pas l'option la plus rapide. Cependant, cela est utile lorsque vous travaillez avec des réinitialisations MultiIndex.

Vous avez également appris que l'application directe de l'index à la propriété .index du DataFrame est le moyen le plus rapide de réinitialiser un index et qu'elle modifie le DataFrame d'origine dans le processus. De plus, vous avez découvert comment la méthode .set_axis() vous permet de réinitialiser et de réétiqueter votre index si vous le souhaitez.

Félicitations pour avoir terminé ce didacticiel et profitez de l'application de ces nouvelles compétences pour mieux préparer vos DataFrames pour l'analyse. Bon surf !