Utilisation de Pandas et de Python pour explorer votre ensemble de données – Real Python

By | janvier 6, 2020

Formation Python

Vous disposez d'un grand ensemble de données riche en informations intéressantes, mais vous ne savez pas par où commencer à l'explorer? Votre patron vous a-t-il demandé de générer des statistiques à partir de celui-ci, mais elles ne sont pas si faciles à extraire? Ce sont précisément les cas d'utilisation où Pandas et Python peut vous aider! Avec ces outils, vous serez en mesure de découper un grand ensemble de données en parties gérables et de tirer un aperçu de ces informations.

Dans ce didacticiel, vous apprendrez à:

  • Calculer métriques sur vos données
  • Effectuer requêtes de base et agrégations
  • Découvrir et gérer les données incorrectes, les incohérences et les valeurs manquantes
  • Visualiser vos données avec des tracés

Vous découvrirez également les différences entre les principales structures de données utilisées par Pandas et Python. Pour suivre, vous pouvez obtenir tous les exemples de code dans ce tutoriel sur le lien ci-dessous:

Configuration de votre environnement

Il y a quelques éléments dont vous aurez besoin pour commencer ce didacticiel. La première est une familiarité avec les structures de données intégrées de Python, en particulier les listes et les dictionnaires. Pour plus d'informations, consultez Listes et Tuples en Python et Dictionnaires en Python.

La deuxième chose dont vous aurez besoin est un environnement Python fonctionnel. Vous pouvez suivre dans n'importe quel terminal sur lequel Python 3 est installé. Si vous souhaitez voir une sortie plus agréable, en particulier pour le grand ensemble de données NBA avec lequel vous allez travailler, vous pouvez exécuter les exemples dans un bloc-notes Jupyter.

La dernière chose dont vous aurez besoin est la bibliothèque Pandas Python, que vous pouvez installer avec pip:

$ python -m pip installe des pandas

Vous pouvez également utiliser le gestionnaire de packages Conda:

Si vous utilisez la distribution Anaconda, alors vous êtes prêt à partir! Anaconda est déjà livré avec la bibliothèque Pandas Python installée.

Les exemples de ce didacticiel ont été testés avec Python 3.7 et Pandas 0.25.0, mais ils devraient également fonctionner dans les anciennes versions. Vous pouvez obtenir tous les exemples de code que vous verrez dans ce didacticiel dans un cahier Jupyter en cliquant sur le lien ci-dessous:

Commençons!

Utilisation de la bibliothèque Pandas Python

Maintenant que vous avez installé Pandas, il est temps de jeter un œil à un ensemble de données. Dans ce didacticiel, vous allez analyser les résultats NBA fournis par FiveThirtyEight dans un fichier CSV de 17 Mo. Créer un script download_nba_all_elo.py pour télécharger les données:

importation demandes

download_url = "https://raw.githubusercontent.com/fivethirtyeight/data/master/nba-elo/nbaallelo.csv"
target_csv_path = "nba_all_elo.csv"

réponse = demandes.avoir(download_url)
réponse.raise_for_status()    # Vérifiez que la demande a abouti
avec ouvert(target_csv_path, "wb") comme F:
    F.écrire(réponse.contenu)
impression("Téléchargement prêt.")

Lorsque vous exécutez le script, il enregistre le fichier nba_all_elo.csv dans votre répertoire de travail actuel.

Vous pouvez maintenant utiliser la bibliothèque Pandas Python pour jeter un œil à vos données:

>>>

>>> importation pandas comme pd
>>> nba = pd.read_csv("nba_all_elo.csv")
>>> type(nba)

Ici, vous suivez la convention d'importation de Pandas en Python avec le pd alias. Ensuite, vous utilisez .read_csv () pour lire dans votre jeu de données et le stocker en tant que Trame de données objet dans la variable nba.

Vous pouvez voir la quantité de données nba contient:

>>>

>>> len(nba)
126314
>>> nba.forme
(126314, 23)

Vous utilisez la fonction intégrée Python len () pour déterminer le nombre de lignes. Vous utilisez également le .forme attribut de Trame de données pour voir son dimensionnalité. Le résultat est un tuple contenant le nombre de lignes et de colonnes.

Vous savez maintenant qu'il y a 126 314 lignes et 23 colonnes dans votre jeu de données. Mais comment pouvez-vous être sûr que l'ensemble de données contient vraiment des statistiques de basket-ball? Vous pouvez consulter les cinq premières lignes avec .tête():

Si vous suivez un cahier Jupyter, vous verrez un résultat comme celui-ci:

Pandas DataFrame .head ()

À moins que votre écran ne soit assez grand, votre sortie n'affichera probablement pas les 23 colonnes. Quelque part au milieu, vous verrez une colonne d'ellipses (...) indiquant les données manquantes. Si vous travaillez dans un terminal, cela est probablement plus lisible que d'habiller de longues lignes. Cependant, les cahiers Jupyter vous permettront de faire défiler. Vous pouvez configurer Pandas pour afficher les 23 colonnes comme ceci:

>>>

>>> pd.set_option("display.max.columns", Aucun)

Bien qu'il soit pratique de voir toutes les colonnes, vous n'aurez probablement pas besoin de six décimales! Remplacez-le par deux:

>>>

>>> pd.set_option("display.precision", 2)

Pour vérifier que vous avez correctement modifié les options, vous pouvez exécuter .tête() à nouveau, ou vous pouvez afficher les cinq dernières lignes avec .queue() au lieu:

Maintenant, vous devriez voir toutes les colonnes et vos données doivent afficher deux décimales:

Pandas DataFrame .tail ()

Vous pouvez découvrir d'autres possibilités de .tête() et .queue() avec un petit exercice. Pouvez-vous imprimer les trois dernières lignes de votre Trame de données? Développez le bloc de code ci-dessous pour voir la solution:

Voici comment imprimer les trois dernières lignes de nba:

Votre sortie devrait ressembler à ceci:

Pandas DataFrame .tail () avec paramètre

Vous pouvez voir les trois dernières lignes de votre jeu de données avec les options que vous avez définies ci-dessus.

Semblable à la bibliothèque standard Python, les fonctions dans Pandas sont également livrées avec plusieurs paramètres facultatifs. Chaque fois que vous tombez sur un exemple qui semble pertinent mais légèrement différent de votre cas d'utilisation, consultez la documentation officielle. Il y a de fortes chances que vous trouviez une solution en modifiant certains paramètres facultatifs!

Apprendre à connaître vos données

Vous avez importé un fichier CSV avec la bibliothèque Pandas Python et vous avez d'abord examiné le contenu de votre ensemble de données. Jusqu'à présent, vous n'avez vu que la taille de votre ensemble de données et ses première et dernière lignes. Ensuite, vous apprendrez à examinez vos données plus systématiquement.

Affichage des types de données

La première étape pour connaître vos données consiste à découvrir les différents types de données qu'elles contiennent. Bien que vous puissiez mettre quoi que ce soit dans une liste, les colonnes d'un Trame de données contiennent des valeurs d'un type de données spécifique. Lorsque vous comparez les structures de données Pandas et Python, vous verrez que ce comportement accélère beaucoup plus les Pandas!

Vous pouvez afficher toutes les colonnes et leurs types de données avec .Info():

Cela produira la sortie suivante:

Pandas DataFrame .info ()

Vous verrez une liste de toutes les colonnes de votre ensemble de données et le type de données que contient chaque colonne. Ici, vous pouvez voir les types de données int64, float64, et objet. Pandas utilise la bibliothèque NumPy pour travailler avec ces types. Plus tard, vous rencontrerez les plus complexes catégorique type de données, que la bibliothèque Pandas Python implémente elle-même.

le objet le type de données est spécial. Selon le Pandas Cookbook, les objet le type de données est «un fourre-tout pour les colonnes que Pandas ne reconnaît pas comme tout autre type spécifique». En pratique, cela signifie souvent que toutes les valeurs de la colonne sont des chaînes.

Bien que vous puissiez stocker des objets Python arbitraires dans le objet type de données, vous devez être conscient des inconvénients de le faire. Des valeurs étranges dans un objet peut endommager les performances de Pandas et son interopérabilité avec d'autres bibliothèques. Pour plus d'informations, consultez le guide de démarrage officiel.

Affichage des statistiques de base

Maintenant que vous avez vu quels types de données se trouvent dans votre ensemble de données, il est temps d'obtenir une vue d'ensemble des valeurs que contient chaque colonne. Vous pouvez le faire avec .décris():

Cette fonction vous montre quelques statistiques descriptives de base pour toutes les colonnes numériques:

Pandas DataFrame .describe ()

.décris() analyse uniquement les colonnes numériques par défaut, mais vous pouvez fournir d'autres types de données si vous utilisez le comprendre paramètre:

>>>

>>> importation engourdi comme np
>>> nba.décris(comprendre=np.objet)

.décris() n'essayera pas de calculer une moyenne ou un écart type pour le objet colonnes, car ils comprennent principalement des chaînes de texte. Cependant, il affichera toujours quelques statistiques descriptives:

Pandas DataFrame .describe () avec include = np.object

Jetez un oeil à la team_id et fran_id Colonnes. Votre jeu de données contient 104 ID d'équipe différents, mais seulement 53 ID de franchise différents. De plus, l'ID d'équipe le plus fréquent est BOS, mais l'ID de franchise le plus fréquent Lakers. Comment est-ce possible? Vous devrez explorer un peu plus votre ensemble de données pour répondre à cette question.

Explorer votre jeu de données

L'analyse exploratoire des données peut vous aider à répondre aux questions sur votre ensemble de données. Par exemple, vous pouvez examiner la fréquence à laquelle des valeurs spécifiques se produisent dans une colonne:

>>>

>>> nba[[[["team_id"].value_counts()
BOS 5997
NYK 5769
LAL 5078
...
SDS 11
>>> nba[[[["fran_id"].value_counts()
Nom: team_id, Longueur: 104, dtype: int64
Lakers 6024
Celtics 5997
Knicks 5769
...
Huskies 60
Nom: fran_id, dtype: int64

Il semble qu'une équipe nommée "Lakers" joué 6024 matchs, mais seulement 5078 d'entre eux ont été joués par les Los Angeles Lakers. Découvrez qui est l'autre "Lakers" l'équipe est:

>>>

>>> nba.loc[[[[nba[[[["fran_id"] == "Lakers", "team_id"].value_counts()
LAL 5078
MNL 946
Nom: team_id, dtype: int64

En effet, les Lakers de Minneapolis ("MNL") a joué 946 matchs. Vous pouvez même savoir quand ils ont joué à ces jeux:

>>>

>>> nba.loc[[[[nba[[[["team_id"] == "MNL", "date_game"].min()
«1/1/1949»
>>> nba.loc[[[[nba[[[["team_id"] == "MNL", "date_game"].max()
«09/04/1959»
>>> nba.loc[[[[nba[[[["team_id"] == "MNL", "date_game"].agg(("min", "max"))
min 1/1/1949
max 4/9/1959
Nom: date_game, dtype: object

On dirait que les Lakers de Minneapolis ont joué entre les années 1949 et 1959. Cela explique pourquoi vous pourriez ne pas reconnaître cette équipe!

Vous avez également découvert pourquoi l'équipe des Celtics de Boston "BOS" joué le plus de jeux dans l'ensemble de données. Analysons également un peu leur histoire. Découvrez combien de points les Boston Celtics ont marqués lors de tous les matchs contenus dans cet ensemble de données. Développez le bloc de code ci-dessous pour la solution:

Semblable à la .min () et .max () fonctions d'agrégation, vous pouvez également utiliser .somme():

>>>

>>> nba.loc[[[[nba[[[["team_id"] == "BOS", "pts"].somme()
626484

Les Boston Celtics ont marqué un total de 626 484 points.

Vous avez un avant-goût des capacités d'un Pandas Trame de données. Dans les sections suivantes, vous développerez les techniques que vous venez d'utiliser, mais d'abord, vous zoomerez et apprendrez comment cette puissante structure de données fonctionne.

Apprendre à connaître les structures de données de Pandas

Alors qu’un Trame de données fournit des fonctions qui peuvent sembler assez intuitives, les concepts sous-jacents sont un peu plus difficiles à comprendre. Pour cette raison, vous allez mettre de côté le vaste NBA Trame de données et construire à partir de zéro des objets Pandas plus petits.

Comprendre les objets de série

La structure de données la plus élémentaire de Python est la liste, qui est également un bon point de départ pour se familiariser pandas.Series objets. Créer un nouveau Séries objet basé sur une liste:

>>>

>>> revenus = pd.Séries([[[[5555, 7000, 1980])
>>> revenus
0 5555
1 7000
2 1980
dtype: int64

Vous avez utilisé la liste [5555, 7000, 1980] créer un Séries objet appelé revenus. UNE Séries objet encapsule deux composants:

  1. Une séquence de valeurs
  2. Une séquence de identifiants, qui est l'indice

Vous pouvez accéder à ces composants avec .valeurs et .indice, respectivement:

>>>

>>> revenus.valeurs
tableau ([5555, 7000, 1980])
>>> revenus.indice
RangeIndex (start = 0, stop = 3, step = 1)

revenus.valeurs renvoie les valeurs dans le Séries, tandis que revenue.index renvoie l'indice de position.

Alors que Pandas s'appuie sur NumPy, une différence significative réside dans leur indexage. Tout comme un tableau NumPy, un Pandas Séries possède également un indice entier implicitement défini. Cet indice implicite indique la position de l'élément dans le Séries.

Cependant, un Séries peut également avoir un type d'index arbitraire. Vous pouvez considérer cet index explicite comme des étiquettes pour une ligne spécifique:

>>>

>>> city_revenues = pd.Séries(
...     [[[[4200, 8000, 6500],
...     indice=[[[["Amsterdam", "Toronto", "Tokyo"]
... )
>>> city_revenues
Amsterdam 4200
Toronto 8000
Tokyo 6500
dtype: int64

Ici, l'index est une liste de noms de villes représentés par des chaînes. Vous avez peut-être remarqué que les dictionnaires Python utilisent également des indices de chaîne, et c'est une analogie pratique à garder à l'esprit! Vous pouvez utiliser les blocs de code ci-dessus pour distinguer deux types de Séries:

  1. revenus: Cette Séries se comporte comme une liste Python car elle n'a qu'un index positionnel.
  2. city_revenues: Cette Séries agit comme un dictionnaire Python car il comporte à la fois un index positionnel et un index d'étiquette.

Voici comment construire un Séries avec un index d'étiquette d'un dictionnaire Python:

>>>

>>> city_employee_count = pd.Séries("Amsterdam": 5, "Tokyo": 8)
>>> city_employee_count
Amsterdam 5
Tokyo 8
dtype: int64

Les clés du dictionnaire deviennent l'index et les valeurs du dictionnaire sont les Séries valeurs.

Tout comme les dictionnaires, Séries également soutenir .clés() et le dans mot-clé:

>>>

>>> city_employee_count.clés()
Indice(['Amsterdam', 'Tokyo'], dtype = 'objet')
>>> "Tokyo" dans city_employee_count
Vrai
>>> "New York" dans city_employee_count
Faux

Vous pouvez utiliser ces méthodes pour répondre rapidement aux questions sur votre jeu de données.

Comprendre les objets DataFrame

Alors qu’un Séries est une structure de données assez puissante, elle a ses limites. Par exemple, vous ne pouvez stocker qu'un seul attribut par clé. Comme vous l’avez vu avec nba de données, qui comprend 23 colonnes, la bibliothèque Pandas Python a plus à offrir avec son Trame de données. Cette structure de données est une séquence de Séries objets qui partagent le même index.

Si vous avez suivi le Séries exemples, alors vous devriez déjà avoir deux Séries objets avec des villes comme clés:

  1. city_revenues
  2. city_employee_count

Vous pouvez combiner ces objets en un Trame de données en fournissant un dictionnaire dans le constructeur. Les clés du dictionnaire deviendront les noms des colonnes et les valeurs devraient contenir le Séries objets:

>>>

>>> city_data = pd.Trame de données(
...     "revenu": city_revenues,
...     "employee_count": city_employee_count
... )
>>> city_data
                                            chiffre_employé
Amsterdam 4200 5,0
Tokyo 6500 8.0
Toronto 8000 NaN

Notez comment les pandas ont remplacé les disparus employee_count valeur pour Toronto avec NaN.

Le nouveau Trame de données l'indice est l'union des deux Séries indices:

>>>

>>> city_data.indice
Indice(['Amsterdam', 'Tokyo', 'Toronto'], dtype = 'objet')

Comme un Séries, une Trame de données stocke également ses valeurs dans un tableau NumPy:

>>>

>>> city_data.valeurs
tableau ([[4.2e+03, 5.0e+00],
       [6.5e+03, 8.0e+00],
       [8.0e+03,     nan]])

Vous pouvez également vous référer aux 2 dimensions d'un Trame de données comme axes:

>>>

>>> city_data.axes
[Indice([Indice([Index([Index(['Amsterdam', 'Tokyo', 'Toronto'], dtype = 'object'),
    Indice(['revenue', 'employee_count'], dtype = 'object')]
>>> city_data.axes[[[[0]
    Indice(['Amsterdam', 'Tokyo', 'Toronto'], dtype = 'objet')
>>> city_data.axes[[[[1]
    Indice(['revenue', 'employee_count'], dtype = 'objet')

L'axe marqué par 0 est le index des lignes, et l'axe marqué par 1 est le index des colonnes. Il est important de connaître cette terminologie car vous rencontrerez plusieurs Trame de données méthodes qui acceptent un axe paramètre.

UNE Trame de données est également une structure de données de type dictionnaire, il prend donc également en charge .clés() et le dans mot-clé. Cependant, pour un Trame de données ceux-ci ne se rapportent pas à l'index, mais aux colonnes:

>>>

>>> city_data.clés()
Indice(['revenue', 'employee_count'], dtype = 'objet')
>>> "Amsterdam" dans city_data
Faux
>>> "revenu" dans city_data
Vrai

Vous pouvez voir ces concepts en action avec le plus grand ensemble de données NBA. Contient-il une colonne appelée "points"ou s'appelait-il "pts"? Pour répondre à cette question, affichez l'index et les axes du nba jeu de données, puis développez le bloc de code ci-dessous pour la solution:

Parce que vous n'avez pas spécifié de colonne d'index lorsque vous lisez le fichier CSV, Pandas a attribué un RangeIndex à la Trame de données:

>>>

>>> nba.indice
RangeIndex (start = 0, stop = 126314, step = 1)

nba, comme tout Trame de données objets, a deux axes:

>>>

>>> nba.axes
[RangeIndex(start=0stop=126314step=1)[RangeIndex(start=0stop=126314step=1)[RangeIndex(start=0stop=126314step=1)[RangeIndex(start=0stop=126314step=1)
    Indice(['gameorder''game_id''lg_id''_iscopy''year_id''date_game'['gameorder''game_id''lg_id''_iscopy''year_id''date_game'['gameorder''game_id''lg_id''_iscopy''year_id''date_game'['gameorder''game_id''lg_id''_iscopy''year_id''date_game'
                                'seasongame', 'is_playoffs', 'team_id', 'fran_id', 'pts', 'elo_i',
                                'elo_n', 'win_equiv', 'opp_id', 'opp_fran', 'opp_pts', 'opp_elo_i',
                                'opp_elo_n', 'game_location', 'game_result', 'prévision', 'notes'],
                            dtype = 'object')]

Vous pouvez vérifier l'existence d'une colonne avec .clés():

>>>

>>> "points" dans nba.clés()
Faux
>>> "pts" dans nba.clés()
Vrai

La colonne s'appelle "pts", ne pas "points".

Lorsque vous utilisez ces méthodes pour répondre à des questions sur votre jeu de données, n'oubliez pas de savoir si vous travaillez avec un Séries ou un Trame de données afin que votre interprétation soit exacte.

Accès aux éléments de série

Dans la section ci-dessus, vous avez créé un Pandas Séries basé sur une liste Python et a comparé les deux structures de données. Vous avez vu comment un Séries l'objet est similaire aux listes et aux dictionnaires de plusieurs manières. Une autre similitude est que vous pouvez utiliser le opérateur d'indexation ([]) pour Séries ainsi que.

Vous apprendrez également à utiliser deux pandas spécifiques méthodes d'accès:

  1. .loc
  2. .iloc

Vous verrez que ces méthodes d'accès aux données peuvent être beaucoup plus lisibles que l'opérateur d'indexation.

Utilisation de l'opérateur d'indexation

Rappelons qu'un Séries a deux indices:

  1. Un index positionnel ou implicite, qui est toujours un RangeIndex
  2. Une étiquette ou un index explicite, qui peut contenir tout objet lavable

Ensuite, revisitez le city_revenues objet:

>>>

>>> city_revenues
Amsterdam 4200
Toronto 8000
Tokyo 6500
dtype: int64

Vous pouvez facilement accéder aux valeurs dans un Séries avec les indices label et positionnels:

>>>

>>> city_revenues[[[["Toronto"]
8000
>>> city_revenues[[[[1]
8000

Vous pouvez également utiliser des indices et des tranches négatifs, comme vous le feriez pour une liste:

>>>

>>> city_revenues[[[[-1]
6500
>>> city_revenues[[[[1:]
Toronto 8000
Tokyo 6500
dtype: int64
>>> city_revenues[[[["Toronto":]
Toronto 8000
Tokyo 6500
dtype: int64

Si vous souhaitez en savoir plus sur les possibilités de l'opérateur d'indexation, consultez Lists and Tuples in Python.

En utilisant .loc et .iloc

L'opérateur d'indexation ([]) est pratique, mais il y a une mise en garde. Et si les étiquettes sont également des nombres? Dites que vous devez travailler avec un Séries objet comme ceci:

>>>

>>> couleurs = pd.Séries(
...     [[[["rouge", "violet", "bleu", "vert", "Jaune"],
...     indice=[[[[1, 2, 3, 5, 8]
... )
>>> couleurs
1 rouge
2 pourpres
3 bleu
5 verts
8 jaune
dtype: objet

Ce qui sera couleurs[1] revenir? Pour un indice positionnel, couleurs[1] est "violet". Cependant, si vous passez par l'index d'étiquette, couleurs[1] fait référence à "rouge".

La bonne nouvelle est que vous n’avez pas à vous en rendre compte! Au lieu de cela, pour éviter toute confusion, la bibliothèque Pandas Python fournit deux méthodes d'accès aux données:

  1. .loc se réfère à la index des étiquettes.
  2. .iloc se réfère à la indice de position.

Ces méthodes d'accès aux données sont beaucoup plus lisibles:

>>>

>>> couleurs.loc[[[[1]
'rouge'
>>> couleurs.iloc[[[[1]
'violet'

colours.loc[1] revenu "rouge", l'élément avec l'étiquette 1. colours.iloc[1] revenu "violet", l'élément avec l'index 1.

La figure suivante montre quels éléments .loc et .iloc faire référence à:

Pandas Series iloc vs loc

Encore, .loc pointe vers l'index d'étiquette sur le côté droit de l'image. Pendant ce temps, .iloc pointe vers l'index de position sur le côté gauche de l'image.

Il est plus facile de garder à l’esprit la distinction entre .loc et .iloc que de comprendre ce que l'opérateur d'indexation retournera. Même si vous connaissez toutes les bizarreries de l'opérateur d'indexation, il peut être dangereux de supposer que tous ceux qui lisent votre code ont également internalisé ces règles!

.loc et .iloc prennent également en charge les fonctionnalités que vous attendez des opérateurs d'indexation, comme le découpage. Cependant, ces méthodes d'accès aux données ont une différence importante. Tandis que .iloc exclut l'élément de fermeture, .loc l'inclut. Jetez un oeil à ce bloc de code:

>>>

>>> # Renvoie les éléments avec l'index implicite: 1, 2
>>> couleurs.iloc[[[[1:3]
2 pourpres
3 bleu
dtype: objet

Si vous comparez ce code avec l'image ci-dessus, vous pouvez voir que colours.iloc[1:3] renvoie les éléments avec le indices de position de 1 et 2. L'élément de clôture "vert" avec un indice de position de 3 est exclu.

D'autre part, .loc comprend l'élément de fermeture:

>>>

>>> # Renvoie les éléments avec l'index explicite entre 3 et 8
>>> couleurs.loc[[[[3:8]
3 bleu
5 verts
8 jaune
dtype: objet

Ce bloc de code dit de retourner tous les éléments avec un index des étiquettes entre 3 et 8. Ici, le point de clôture "Jaune" a un indice d'étiquette de 8 et est inclus dans la sortie.

Vous pouvez également transmettre un indice positionnel négatif à .iloc:

>>>

>>> couleurs.iloc[[[[-2]
'vert'

Vous commencez à la fin de la Séries et retourner le deuxième élément.

Vous pouvez utiliser les blocs de code ci-dessus pour distinguer deux Séries comportements:

  1. Vous pouvez utiliser .iloc sur un Séries similaire à l'utilisation [] sur un liste.
  2. Vous pouvez utiliser .loc sur un Séries similaire à l'utilisation [] sur un dictionnaire.

N'oubliez pas ces distinctions lorsque vous accédez à des éléments de votre Séries objets.

Accès aux éléments DataFrame

Depuis un Trame de données consiste en Séries objets, vous pouvez utiliser les mêmes outils pour accéder à ses éléments. La différence cruciale est la dimension du Trame de données. Vous utiliserez l'opérateur d'indexation pour les colonnes et les méthodes d'accès .loc et .iloc sur les rangées.

Utilisation de l'opérateur d'indexation

Si vous pensez à un Trame de données comme un dictionnaire dont les valeurs sont Séries, il est donc logique que vous puissiez accéder à ses colonnes avec l'opérateur d'indexation:

>>>

>>> city_data[[[["revenu"]
Amsterdam 4200
Tokyo 6500
Toronto 8000
Nom: revenue, dtype: int64
>>> type(city_data[[[["revenu"])
pandas.core.series.Series

Ici, vous utilisez l'opérateur d'indexation pour sélectionner la colonne intitulée "revenu".

Si le nom de la colonne est une chaîne, vous pouvez également utiliser l'accès de style attribut avec la notation par points:

>>>

>>> city_data.revenu
Amsterdam 4200
Tokyo 6500
Toronto 8000
Nom: revenue, dtype: int64

city_data["revenue"] et city_data.revenue retourner la même sortie.

Il y a une situation où l'accès Trame de données les éléments avec notation par points peuvent ne pas fonctionner ou peuvent créer des surprises. C'est quand un nom de colonne coïncide avec un Trame de données nom d'attribut ou de méthode:

>>>

>>> jouets = pd.Trame de données([[[[
...     "Nom": "Balle", "forme": "sphère",
...     "Nom": "Rubik's Cube", "forme": "cube"
... ])
>>> jouets[[[["forme"]
0 sphère
1 cube
Nom: forme, dtype: objet
>>> jouets.forme
(2, 2)

L'opération d'indexation jouets["shape"] renvoie les données correctes, mais l'opération de style attribut toys.shape renvoie toujours la forme du Trame de données. Vous ne devez utiliser l'accès de style attribut que dans des sessions interactives ou pour des opérations de lecture. Vous ne devez pas l'utiliser pour du code de production ou pour manipuler des données (telles que la définition de nouvelles colonnes).

En utilisant .loc et .iloc

Semblable à Séries, une Trame de données fournit également .loc et .iloc méthodes d'accès aux données. Rappelles toi, .loc utilise l'étiquette et .iloc l'indice de position:

>>>

>>> city_data.loc[[[["Amsterdam"]
chiffre d'affaires 4200,0
employee_count 5.0
Nom: Amsterdam, dtype: float64
>>> city_data.loc[[[["Tokyo": "Toronto"]
                                revenue employee_count
Tokyo 6500 8.0
Toronto 8000 NaN
>>> city_data.iloc[[[[1]
chiffre d'affaires 6500,0
employee_count 8.0
Nom: Tokyo, dtype: float64

Chaque ligne de code sélectionne une ligne différente de city_data:

  1. city_data.loc["Amsterdam"] sélectionne la ligne avec l'index d'étiquette "Amsterdam".
  2. city_data.loc["Tokyo": "Toronto"] sélectionne les lignes avec des indices d'étiquette "Tokyo" à "Toronto". Rappelles toi, .loc est inclusif.
  3. city_data.iloc[1] sélectionne la ligne avec l'indice de position 1, lequel est "Tokyo".

D'accord, vous avez utilisé .loc et .iloc sur les petites structures de données. Maintenant, il est temps de pratiquer avec quelque chose de plus grand! Utilisez une méthode d'accès aux données pour afficher l'avant-dernière ligne du nba base de données. Développez ensuite le bloc de code ci-dessous pour voir une solution:

L'avant-dernier rang est le rang avec le indice de position de -2. Vous pouvez l'afficher avec .iloc:

>>>

>>> nba.iloc[[[[-2]
gameorder 63157
game_id 201506170CLE
lg_id NBA
_écopie 0
year_id 2015
date_game 16/06/2015
seasongame 102
is_playoffs 1
team_id CLE
fran_id Cavaliers
pts 97
elo_i 1700.74
elo_n 1692.09
win_equiv 59.2902
opp_id GSW
opp_fran Warriors
opp_pts 105
opp_elo_i 1813.63
opp_elo_n 1822.29
emplacement_jeu H
game_result L
prévision 0,48145
note NaN
Nom: 126312, dtype: objet

Vous verrez la sortie comme Séries objet.

Pour un Trame de données, les méthodes d'accès aux données .loc et .iloc accepter également un deuxième paramètre. Alors que le premier paramètre sélectionne des lignes en fonction des indices, le deuxième paramètre sélectionne les colonnes. Vous pouvez utiliser ces paramètres ensemble pour sélectionner un sous-ensemble de lignes et de colonnes de votre Trame de données:

>>>

>>> city_data.loc[[[["Amsterdam": "Tokyo", "revenu"]
Amsterdam 4200
Tokyo 6500
Nom: revenue, dtype: int64

Notez que vous séparez les paramètres par une virgule (,). Le premier paramètre, "Amsterdam": "Tokyo" dit de sélectionner toutes les lignes entre ces deux étiquettes. Le deuxième paramètre vient après la virgule et dit de sélectionner le "revenu" colonne.

Il est temps de voir la même construction en action avec le plus grand nba base de données. Sélectionnez tous les jeux entre les étiquettes 5555 et 5559. Vous n'êtes intéressé que par les noms des équipes et les scores, alors sélectionnez également ces éléments. Développez le bloc de code ci-dessous pour voir une solution:

Tout d'abord, définissez les lignes que vous souhaitez voir, puis répertoriez les colonnes pertinentes:

>>>

>>> nba.loc[[[[5555:5559, [[[["fran_id", "opp_fran", "pts", "opp_pts"]]

Tu utilises .loc pour l'index d'étiquette et une virgule (,) pour séparer vos deux paramètres.

Vous devriez voir une petite partie de votre assez grand ensemble de données:

Pandas DataFrame .loc

La sortie est beaucoup plus facile à lire!

Avec des méthodes d'accès aux données comme .loc et .iloc, vous pouvez sélectionner juste le bon sous-ensemble de votre Trame de données pour vous aider à répondre aux questions sur votre jeu de données.

Interroger votre ensemble de données

Vous avez vu comment accéder à des sous-ensembles d'un énorme ensemble de données en fonction de ses indices. Maintenant, vous allez sélectionner des lignes en fonction des valeurs des colonnes de votre ensemble de données à requete vos données. Par exemple, vous pouvez créer un nouveau Trame de données qui ne contient que des jeux joués après 2010:

>>>

>>> current_decade = nba[[[[nba[[[["year_id"] > 2010]
>>> current_decade.forme
(12658, 23)

Vous avez toujours les 23 colonnes, mais votre nouveau Trame de données se compose uniquement de lignes où la valeur dans le "year_id" la colonne est supérieure à 2010.

Vous pouvez également sélectionner les lignes où un champ spécifique n'est pas nul:

>>>

>>> games_with_notes = nba[[[[nba[[[["Remarques"].pas nul()]
>>> games_with_notes.forme
(5424, 23)

Cela peut être utile si vous souhaitez éviter toute valeur manquante dans une colonne. Vous pouvez aussi utiliser .notna () pour atteindre le même objectif.

Vous pouvez même accéder aux valeurs de la objet type de données as str et effectuer des méthodes de chaîne sur eux:

>>>

>>> ers = nba[[[[nba[[[["fran_id"].str.se termine par("ers")]
>>> ers.forme
(27797, 23)

Tu utilises .str.endswith () pour filtrer votre jeu de données et trouver tous les jeux où le nom de l'équipe à domicile se termine par "ers".

Vous pouvez combiner plusieurs critères et interroger également votre ensemble de données. Pour ce faire, assurez-vous de mettre chacun entre parenthèses et d'utiliser les opérateurs logiques | et & pour les séparer.

Faites une recherche des matchs de Baltimore où les deux équipes ont marqué plus de 100 points. Pour voir chaque jeu une seule fois, vous devez exclure les doublons:

>>>

>>> nba[[[[
...     (nba[[[["_iscopy"] == 0) &
...     (nba[[[["pts"] > 100) &
...     (nba[[[["opp_pts"] > 100) &
...     (nba[[[["team_id"] == "BLB")
... ]

Ici, vous utilisez nba["_iscopy"] == 0 pour inclure uniquement les entrées qui ne sont pas des copies.

Votre sortie doit contenir cinq jeux mouvementés:

Requête Pandas DataFrame avec plusieurs critères

Essayez de créer une autre requête avec plusieurs critères. Au printemps 1992, les deux équipes de Los Angeles ont dû jouer un match à domicile sur un autre terrain. Recherchez votre jeu de données pour trouver ces deux jeux. Les deux équipes ont un ID commençant par "LA". Développez le bloc de code ci-dessous pour voir une solution:

Vous pouvez utiliser .str pour trouver les ID d'équipe commençant par "LA", et vous pouvez supposer qu'un jeu aussi inhabituel aurait quelques notes:

>>>

>>> nba[[[[
...     (nba[[[["_iscopy"] == 0) &
...     (nba[[[["team_id"].str.commence avec("LA")) &
...     (nba[[[["year_id"]==1992) &
...     (nba[[[["Remarques"].pas nul())
... ]

Votre sortie devrait montrer deux jeux le jour 5/3/1992:

Requête Pandas DataFrame avec plusieurs critères: solution de l'exercice

Belle trouvaille!

Lorsque vous savez comment interroger votre ensemble de données avec plusieurs critères, vous pourrez répondre à des questions plus spécifiques sur votre ensemble de données.

Regroupement et agrégation de vos données

Vous pouvez également vouloir découvrir d'autres fonctionnalités de votre ensemble de données, comme la somme, la moyenne ou la valeur moyenne d'un groupe d'éléments. Heureusement, la bibliothèque Pandas Python propose fonctions de regroupement et d'agrégation pour vous aider à accomplir cette tâche.

UNE Séries a plus de vingt méthodes différentes pour calculer les statistiques descriptives. Voici quelques exemples:

>>>

>>> city_revenues.somme()
18700
>>> city_revenues.max()
8000

La première méthode renvoie le total de city_revenues, tandis que la seconde renvoie la valeur maximale. Il existe d'autres méthodes que vous pouvez utiliser, comme .min () et .signifier().

Rappelez-vous, une colonne d'un Trame de données est en fait un Séries objet. Pour cette raison, vous pouvez utiliser ces mêmes fonctions sur les colonnes de nba:

>>>

>>> points = nba[[[["pts"]
>>> type(points)

>>> points.somme()
12976235

UNE Trame de données peut avoir plusieurs colonnes, ce qui introduit de nouvelles possibilités d'agrégation, comme regroupement:

>>>

>>> nba.par groupe("fran_id", Trier=Faux)[[[["pts"].somme()
fran_id
Huskies 3995
Knicks 582497
Cerfs 20398
Falcons 3797
Capitols 22387
...

Par défaut, Pandas trie les touches de groupe pendant l'appel à .par groupe(). Si vous ne voulez pas trier, passez sort = False. Ce paramètre peut entraîner des gains de performances.

Vous pouvez également regrouper par plusieurs colonnes:

>>>

>>> nba[[[[
...     (nba[[[["fran_id"] == "Éperons") &
...     (nba[[[["year_id"] > 2010)
... ].par groupe([[[["year_id", "game_result"])[[[["identifiant de jeu"].compter()
year_id game_result
2011 L 25
                                    W 63
2012 L 20
                                    W 60
2013 L 30
                                    W 73
2014 L 27
                                    W 78
2015 L 31
                                    W 58
Nom: game_id, dtype: int64

Vous pouvez pratiquer ces bases avec un exercice. Jetez un œil à la saison 2014-15 des Golden State Warriors (year_id: 2015). Combien de victoires et de défaites ont-ils marquées au cours de la saison régulière et des séries éliminatoires? Développez le bloc de code ci-dessous pour la solution:

Tout d'abord, vous pouvez regrouper par "is_playoffs" champ, puis par le résultat:

>>>

>>> nba[[[[
...     (nba[[[["fran_id"] == "Guerriers") &
...     (nba[[[["year_id"] == 2015)
... ].par groupe([[[["is_playoffs", "game_result"])[[[["identifiant de jeu"].compter()
is_playoffs game_result
0 L 15
                                                    W 67
1 L 5
                                                    W 16

is_playoffs = 0 montre les résultats de la saison régulière, et is_playoffs = 1 montre les résultats des éliminatoires.

Dans les exemples ci-dessus, vous n'avez fait qu'effleurer la surface des fonctions d'agrégation disponibles dans la bibliothèque Pandas Python. Pour voir plus d'exemples sur la façon de les utiliser, consultez Pandas GroupBy: Votre guide de regroupement des données en Python.

Manipulation des colonnes

Vous aurez besoin de savoir comment manipuler your dataset’s columns in different phases of the data analysis process. You can add and drop columns as part of the initial data cleaning phase, or later based on the insights of your analysis.

Create a copy of your original DataFrame to work with:

>>>

>>> df = nba.copie()
>>> df.forme
(126314, 23)

You can define new columns based on the existing ones:

>>>

>>> df[[[["difference"] = df.pts - df.opp_pts
>>> df.forme
(126314, 24)

Here, you used the "pts" et "opp_pts" columns to create a new one called "difference". This new column has the same functions as the old ones:

>>>

>>> df[[[["difference"].max()
68

Here, you used an aggregation function .max() to find the largest value of your new column.

You can also rename the columns of your dataset. It seems that "game_result" et "game_location" are too verbose, so go ahead and rename them now:

>>>

>>> renamed_df = df.rename(
...     columns="game_result": "result", "game_location": "location"
... )
>>> renamed_df.Info()

RangeIndex: 126314 entries, 0 to 126313
Data columns (total 24 columns):
gameorder      126314 non-null int64
...
location       126314 non-null object
result         126314 non-null object
forecast       126314 non-null float64
notes          5424 non-null object
difference     126314 non-null int64
dtypes: float64(6), int64(8), object(10)
memory usage: 23.1+ MB

Note that there’s a new object, renamed_df. Like several other data manipulation methods, .rename() returns a new DataFrame by default. If you want to manipulate the original DataFrame directly, then .rename() also provides an inplace parameter that you can set to Vrai.

Your dataset might contain columns that you don’t need. For example, Elo ratings may be a fascinating concept to some, but you won’t analyze them in this tutorial. You can delete the four columns related to Elo:

>>>

>>> df.forme
(126314, 24)
>>> elo_columns = [[[["elo_i", "elo_n", "opp_elo_i", "opp_elo_n"]
>>> df.laissez tomber(elo_columns, inplace=Vrai, axis=1)
>>> df.forme
(126314, 20)

Remember, you added the new column "difference" in a previous example, bringing the total number of columns to 24. When you remove the four Elo columns, the total number of columns drops to 20.

Specifying Data Types

When you create a new DataFrame, either by calling a constructor or reading a CSV file, Pandas assigns a data type to each column based on its values. While it does a pretty good job, it’s not perfect. If you choose the right data type for your columns upfront, then you can significantly improve your code’s performance.

Take another look at the columns of the nba dataset:

You’ll see the same output as before:

Pandas DataFrame .info()

Ten of your columns have the data type object. Most of these object columns contain arbitrary text, but there are also some candidates for data type conversion. For example, take a look at the date_game column:

>>>

>>> df[[[["date_game"] = pd.to_datetime(df[[[["date_game"])

Here, you use .to_datetime() to specify all game dates as datetime objects.

Other columns contain text that are a bit more structured. le game_location column can have only three different values:

>>>

>>> df[[[["game_location"].nunique()
3
>>> df[[[["game_location"].value_counts()
A    63138
H    63138
N       38
Name: game_location, dtype: int64

Which data type would you use in a relational database for such a column? You would probably not use a varchar type, but rather an enum. Pandas provides the categorical data type for the same purpose:

>>>

>>> df[[[["game_location"] = pd.Categorical(df[[[["game_location"])
>>> df[[[["game_location"].dtype
CategoricalDtype(categories=['A', 'H', 'N'], ordered=False)

categorical Les données has a few advantages over unstructured text. When you specify the categorical data type, you make validation easier and save a ton of memory, as Pandas will only use the unique values internally. The higher the ratio of total values to unique values, the more space savings you’ll get.

Run df.info() again. You should see that changing the game_location data type from object à categorical has decreased the memory usage.

You’ll often encounter datasets with too many text columns. An essential skill for data scientists to have is the ability to spot which columns they can convert to a more performant data type.

Take a moment to practice this now. Find another column in the nba dataset that has a generic data type and convert it to a more specific one. You can expand the code block below to see one potential solution:

game_result can take only two different values:

>>>

>>> df[[[["game_result"].nunique()
2
>>> df[[[["game_result"].value_counts()
L    63157
W    63157

To improve performance, you can convert it into a categorical column:

>>>

>>> df[[[["game_result"] = pd.Categorical(df[[[["game_result"])

Vous pouvez utiliser df.info() to check the memory usage.

As you work with more massive datasets, memory savings becomes especially crucial. Be sure to keep performance in mind as you continue to explore your datasets.

Cleaning Data

You may be surprised to find this section so late in the tutorial! Usually, you’d take a critical look at your dataset to fix any issues before you move on to a more sophisticated analysis. However, in this tutorial, you’ll rely on the techniques that you’ve learned in the previous sections to clean your dataset.

Missing Values

Have you ever wondered why .info() shows how many non-null values a column contains? The reason why is that this is vital information. Null values often indicate a problem in the data-gathering process. They can make several analysis techniques, like different types of machine learning, difficult or even impossible.

When you inspect the nba dataset with nba.info(), you’ll see that it’s quite neat. Only the column notes contains null values for the majority of its rows:

Pandas DataFrame .info()

This output shows that the notes column has only 5424 non-null values. That means that over 120,000 rows of your dataset have null values in this column.

Sometimes, the easiest way to deal with records containing missing values is to ignore them. You can remove all the rows with missing values using .dropna():

>>>

>>> rows_without_missing_data = nba.dropna()
>>> rows_without_missing_data.forme
(5424, 23)

Of course, this kind of data cleanup doesn’t make sense for your nba dataset, because it’s not a problem for a game to lack notes. But if your dataset contains a million valid records and a hundred where relevant data is missing, then dropping the incomplete records can be a reasonable solution.

You can also drop problematic columns if they’re not relevant for your analysis. Pour ce faire, utilisez .dropna() again and provide the axis=1 parameter:

>>>

>>> data_without_missing_columns = nba.dropna(axis=1)
>>> data_without_missing_columns.forme
(126314, 22)

Now, the resulting DataFrame contains all 126,314 games, but not the sometimes empty notes column.

If there’s a meaningful default value for your use case, then you can also replace the missing values with that:

>>>

>>> data_with_default_notes = nba.copie()
>>> data_with_default_notes[[[["notes"].fillna(
...     valeur="no notes at all",
...     inplace=Vrai
... )
>>> data_with_default_notes[[[["notes"].describe()
count              126314
unique                232
top       no notes at all
freq               120890
Name: notes, dtype: object

Here, you fill the empty notes rows with the string "no notes at all".

Invalid Values

Invalid values can be even more dangerous than missing values. Often, you can perform your data analysis as expected, but the results you get are peculiar. This is especially important if your dataset is enormous or used manual entry. Invalid values are often more challenging to detect, but you can implement some sanity checks with queries and aggregations.

One thing you can do is validate the ranges of your data. For this, .describe() is quite handy. Recall that it returns the following output:

Pandas DataFrame .describe()

le year_id varies between 1947 and 2015. That sounds plausible.

Qu'en est-il de pts? How can the minimum be 0? Let’s have a look at those games:

>>>

>>> nba[[[[nba[[[["pts"] == 0]

This query returns a single row:

Pandas DataFrame query

It seems the game was forfeited. Depending on your analysis, you may want to remove it from the dataset.

Inconsistent Values

Sometimes a value would be entirely realistic in and of itself, but it doesn’t fit with the values in the other columns. You can define some query criteria that are mutually exclusive and verify that these don’t occur together.

In the NBA dataset, the values of the fields pts, opp_pts et game_result should be consistent with each other. You can check this using the .empty attribute:

>>>

>>> nba[([([([(nba[[[["pts"] > nba[[[["opp_pts"]) & (nba[[[["game_result"] != 'W')].vide
Vrai
>>> nba[([([([(nba[[[["pts"] < nba[[[["opp_pts"]) & (nba[[[["game_result"] != 'L')].vide
Vrai

Fortunately, both of these queries return an empty DataFrame.

Be prepared for surprises whenever you’re working with raw datasets, especially if they were gathered from different sources or through a complex pipeline. You might see rows where a team scored more points than their opponent, but still didn’t win—at least, according to your dataset! To avoid situations like this, make sure you add further data cleaning techniques to your Pandas and Python arsenal.

Combining Multiple Datasets

In the previous section, you’ve learned how to clean a messy dataset. Another aspect of real-world data is that it often comes in multiple pieces. In this section, you’ll learn how to grab those pieces and combiner them into one dataset that’s ready for analysis.

Earlier, you combined two Series objects into a DataFrame based on their indices. Now, you’ll take this one step further and use .concat() to combine city_data with another DataFrame. Say you’ve managed to gather some data on two more cities:

>>>

>>> further_city_data = pd.DataFrame(
...     "revenue": [[[[7000, 3400], "employee_count":[[[[2, 2],
...     indice=[[[["New York", "Barcelona"]
... )

This second DataFrame contains info on the cities "New York" et "Barcelona".

You can add these cities to city_data en utilisant .concat():

>>>

>>> all_city_data = pd.concat([[[[city_data, further_city_data], sort=Faux)
>>> all_city_data
Amsterdam   4200    5.0
Tokyo       6500    8.0
Toronto     8000    NaN
New York    7000    2.0
Barcelona   3400    2.0

Now, the new variable all_city_data contains the values from both DataFrame objects.

By default, concat() combines along axis=0. In other words, it appends rows. You can also use it to append columns by supplying the parameter axis=1:

>>>

>>> city_countries = pd.DataFrame(
...     "country": [[[["Holland", "Japan", "Holland", "Canada", "Spain"],
...     "capital": [[[[1, 1, 0, 0, 0],
...     indice=[[[["Amsterdam", "Tokyo", "Rotterdam", "Toronto", "Barcelona"]
... )
>>> cities = pd.concat([[[[all_city_data, city_countries], axis=1, sort=Faux)
>>> cities
                                            revenue  employee_count  country  capital
Amsterdam   4200.0             5.0  Holland      1.0
Tokyo       6500.0             8.0    Japan      1.0
Toronto     8000.0             NaN   Canada      0.0
New York    7000.0             2.0      NaN      NaN
Barcelona   3400.0             2.0    Spain      0.0
Rotterdam      NaN             NaN  Holland      0.0

Note how Pandas added NaN for the missing values. If you want to combine only the cities that appear in both DataFrame objects, then you can set the join parameter to inner:

>>>

>>> pd.concat([[[[all_city_data, city_countries], axis=1, join="inner")
                                            revenue  employee_count  country  capital
Amsterdam     4200             5.0  Holland        1
Tokyo         6500             8.0    Japan        1
Toronto       8000             NaN   Canada        0
Barcelona     3400             2.0    Spain        0

While it’s most straightforward to combine data based on the index, it’s not the only possibility. Vous pouvez utiliser .merge() to implement a join operation similar to the one from SQL:

>>>

>>> des pays = pd.DataFrame(
...     "population_millions": [[[[17, 127, 37],
...     "continent": [[[["Europe", "Asia", "North America"]
... , indice= [[[["Holland", "Japan", "Canada"])
>>> pd.merge(cities, des pays, left_on="country", right_index=Vrai)

Here, you pass the parameter left_on="country" à .merge() to indicate what column you want to join on. The result is a bigger DataFrame that contains not only city data, but also the population and continent of the respective countries:

Pandas merge

Note that the result contains only the cities where the country is known and appears in the joined DataFrame.

.merge() performs an inner join by default. If you want to include all cities in the result, then you need to provide the Comment parameter:

>>>

>>> pd.merge(
...     cities,
...     des pays,
...     left_on="country",
...     right_index=Vrai,
...     Comment="left"
... )

Avec ça la gauche join, you’ll see all the cities, including those without country data:

Pandas merge left join

Welcome back, New York & Barcelona!

Visualizing Your Pandas DataFrame

Data visualization is one of the things that works much better in a Jupyter notebook than in a terminal, so go ahead and fire one up. If you need help getting started, then check out Jupyter Notebook: An Introduction. You can also access the Jupyter notebook that contains the examples from this tutorial by clicking the link below:

Include this line to show plots directly in the notebook:

>>>

>>> %matplotlib inline

Tous les deux Series et DataFrame objects have a .plot() method, which is a wrapper around matplotlib.pyplot.plot(). By default, it creates a line plot. Visualize how many points the Knicks scored throughout the seasons:

>>>

>>> nba[[[[nba[[[["fran_id"] == "Knicks"].groupby("year_id")[[[["pts"].sum().plot()

This shows a line plot with several peaks and two notable valleys around the years 2000 and 2010:

Pandas plot line

You can also create other types of plots, like a bar plot:

>>>

>>> nba[[[["fran_id"].value_counts().tête(dix).plot(kind="bar")

This will show the franchises with the most games played:

Pandas plot bar

The Lakers are leading the Celtics by a minimal edge, and there are six further teams with a game count above 5000.

Now try a more complicated exercise. In 2013, the Miami Heat won the championship. Create a pie plot showing the count of their wins and losses during that season. Then, expand the code block to see a solution:

First, you define a criteria to include only the Heat’s games from 2013. Then, you create a plot in the same way as you’ve seen above:

>>>

>>> nba[[[[
...     (nba[[[["fran_id"] == "Heat") &
...     (nba[[[["year_id"] == 2013)
... ][[[["game_result"].value_counts().plot(kind="pie")

Here’s what a champion pie looks like:

Pandas plot pie

The slice of wins is significantly larger than the slice of losses!

Sometimes, the numbers speak for themselves, but often a chart helps a lot with communicating your insights. To learn more about visualizing your data, check out Interactive Data Visualization in Python With Bokeh.

Conclusion

In this tutorial, you’ve learned how to start exploring a dataset with the Pandas Python library. You saw how you could access specific rows and columns to tame even the largest of datasets. Speaking of taming, you’ve also seen multiple techniques to prepare and clean your data, by specifying the data type of columns, dealing with missing values, and more. You’ve even created queries, aggregations, and plots based on those.

Now you can:

  • Work with Series et DataFrame objets
  • Subset your data with .loc, .iloc, and the indexing operator
  • Answer questions with queries, grouping, and aggregation
  • Handle missing, invalid, and inconsistent data
  • Visualize your dataset in a Jupyter notebook

This journey using the NBA stats only scratches the surface of what you can do with the Pandas Python library. You can power up your project with Pandas tricks, learn techniques to speed up Pandas in Python, and even dive deep to see how Pandas works behind the scenes. There are many more features for you to discover, so get out there and tackle those datasets!

You can get all the code examples you saw in this tutorial by clicking the link below: