Cours Python en ligne
Que vous veniez tout juste de commencer à travailler avec Pandas et que vous souhaitiez maîtriser l’un de ses principaux équipements, ou que vous cherchiez à combler certaines lacunes dans votre compréhension de .par groupe()
, ce tutoriel vous aidera à décomposer et à visualiser un Pandas GroupBy opération du début à la fin.
Ce tutoriel est destiné à compléter la documentation officielle, dans laquelle vous verrez des exemples autonomes et concis. Ici, cependant, vous allez vous concentrer sur trois autres visites détaillées qui utilisent des ensembles de données du monde réel.
Dans ce tutoriel, vous allez couvrir:
- Comment utiliser les opérations Pandas GroupBy sur des données réelles
- Comment le split-apply-combine chaîne d'opérations fonctionne
- Comment décomposer la chaîne diviser-appliquer-combiner en étapes
- Comment les méthodes d'un objet Pandas GroupBy peuvent être placées dans différentes catégories en fonction de leur intention et de leur résultat
Ce didacticiel suppose que vous avez une expérience des Pandas eux-mêmes, y compris comment lire des fichiers CSV en mémoire en tant qu’objets Pandas avec read_csv ()
. Si vous avez besoin d'un rappel, consultez Reading CSVs With Pandas.
Vous pouvez télécharger le code source de tous les exemples de ce tutoriel en cliquant sur le lien ci-dessous:
Ménagère
Tout le code de ce didacticiel a été généré dans un shell CPython 3.7.2 utilisant Pandas 0.25.0. Avant de poursuivre, assurez-vous de disposer de la dernière version de Pandas dans un nouvel environnement virtuel:
$ python -m venv pandas-gb-tut
$ la source ./pandas-gb-tut/bin/activate
$ python -m pip installer des pandas
Les exemples ici utilisent également quelques options de pandas modifiées pour une sortie plus conviviale:
importation pandas comme pd
# Utilisez 3 décimales dans l'affichage en sortie
pd.set_option("display.precision", 3)
# Ne pas encapsuler repr (DataFrame) sur des lignes supplémentaires
pd.set_option("display.expand_frame_repr", Faux)
# Définir le nombre maximal de lignes affichées dans la sortie sur 25
pd.set_option("display.max_rows", 25)
Vous pouvez les ajouter à un fichier de démarrage pour les définir automatiquement à chaque démarrage de votre interprète.
Dans ce tutoriel, vous allez vous concentrer sur trois jeux de données:
- Le jeu de données du Congrès américain contient des informations publiques sur les membres historiques du Congrès et illustre plusieurs capacités fondamentales du
.par groupe()
. - L'ensemble de données sur la qualité de l'air contient des lectures périodiques du capteur de gaz. Cela vous permettra de travailler avec des données flottantes et des séries chronologiques.
- L'ensemble de données d'agrégateur de nouvelles qui contient des métadonnées sur plusieurs centaines de milliers d'articles. Vous travaillerez avec des chaînes et ferez du texte groupé.
Vous pouvez télécharger le code source de tous les exemples de ce tutoriel en cliquant sur le lien ci-dessous:
Une fois que vous avez téléchargé le .Zip *: français
, vous pouvez le décompresser dans votre répertoire actuel:
$ décompressez -q -d groupby-data groupby-data.zip
le -ré
Cette option vous permet d’extraire le contenu dans un nouveau dossier:
./
│
└── groupby-data /
│
├── legislators-historical.csv
Qual airqual.csv
└── news.csv
Avec cette configuration, vous êtes prêt à intervenir!
Exemple 1: Jeu de données du Congrès américain
Vous allez entrer directement dans les choses en disséquant un ensemble de données de membres historiques du Congrès. Vous pouvez lire le fichier CSV dans un Pandas Trame de données
avec read_csv ()
:
importation pandas comme pd
types =
"Prénom": "Catégorie",
"Le sexe HOMME ou FEMME": "Catégorie",
"type": "Catégorie",
"Etat": "Catégorie",
"fête": "Catégorie",
df = pd.read_csv(
"groupby-data / legislators-historical.csv",
type=types,
Usecols=liste(types) + [[[["anniversaire", "nom de famille"],
parse_dates=[[[["anniversaire"]
)
Le jeu de données contient les noms et prénoms des membres, leur date de naissance, leur sexe, leur type ("représentant"
pour la Chambre des représentants ou "sen"
pour le Sénat), l’État américain et le parti politique. Vous pouvez utiliser df.tail ()
pour afficher les dernières lignes du jeu de données:
>>> df.queue()
prénom_nom prénom_anniversaire anniversaire genre type État partie
11970 Garrett Thomas 1972-03-27 Représentant VA Républicain
11971 Handel Karen 1962-04-18 représentant rep républicain
11972 Jones Brenda 1959-10-24 Représentant F Démocrate MI
11973 Marino Tom 1952-08-15 Représentant PA Républicain
11974 Jones Walter 1943-02-10 Représentant NC Républicain
le Trame de données
utilise catégorique types pour l'efficacité de l'espace:
>>> df.types
nom de famille
catégorie prénom
date d'anniversaire64[ns]
catégorie de genre
type de catégorie
catégorie d'état
catégorie de parti
dtype: objet
Vous pouvez voir que la plupart des colonnes de l’ensemble de données ont le type Catégorie
, ce qui réduit la charge de mémoire sur votre machine.
Le “Hello, World!” De Pandas GroupBy
Maintenant que vous êtes familiarisé avec l'ensemble de données, vous commencerez par «Hello, World!» Pour l'opération Pandas GroupBy. Quel est le nombre de membres du Congrès, État par État, sur l’ensemble de l’historique de l’ensemble de données? En SQL, vous pouvez trouver cette réponse avec un SÉLECTIONNER
déclaration:
SÉLECTIONNER Etat, compter(Nom)
DE df
GROUPE PAR Etat
ORDRE PAR Etat;
Voici l'équivalent quasi-équivalent chez les Pandas:
>>> n_by_state = df.par groupe("Etat")[[[["nom de famille"].compter()
>>> n_by_state.tête(dix)
Etat
AK 16
AL 206
AR 117
AS 2
AZ 48
CA 361
CO 90
CT 240
DC 2
DE 97
Nom: nom de famille, type: int64
Tu appelles .par groupe()
et passez le nom de la colonne que vous souhaitez grouper, qui est "Etat"
. Ensuite, vous utilisez ["last_name"]
pour spécifier les colonnes sur lesquelles vous voulez effectuer l'agrégation réelle.
Vous pouvez transmettre beaucoup plus qu'un simple nom de colonne à .par groupe()
comme premier argument. Vous pouvez également spécifier l’un des éléments suivants:
- UNE
liste
de plusieurs noms de colonnes - UNE
dict
ou des pandasSéries
- Un tableau NumPy ou des pandas
Indice
, ou un tableau semblable à ceux-ci
Voici un exemple de regroupement conjoint sur deux colonnes, qui répertorie le nombre de membres du Congrès ventilé par État, puis par sexe:
>>> df.par groupe([[[["Etat", "Le sexe HOMME ou FEMME"])[[[["nom de famille"].compter()
sexe de l'état
AK M 16
AL F 3
M 203
AR F 5
M 112
...
WI M 196
WV F 1
M 119
WY F 2
M 38
Nom: nom, longueur: 104, type: int64
La requête SQL analogue ressemblerait à ceci:
SÉLECTIONNER Etat, Le sexe HOMME ou FEMME, compter(Nom)
DE df
GROUPE PAR Etat, Le sexe HOMME ou FEMME
ORDRE PAR Etat, Le sexe HOMME ou FEMME;
Comme vous le verrez ensuite, .par groupe()
et les instructions SQL comparables sont des cousins proches, mais elles ne sont pas fonctionnellement identiques.
Remarque: Il existe encore une toute petite différence entre la comparaison entre Pandas et SQL de Pandas: dans la version Pandas, certains États n’affichent qu’un seul sexe. Au cours de la mise au point de ce didacticiel, nous avons rencontré un bogue petit mais délicat dans la source Pandas qui ne gère pas la observé
paramètre bien avec certains types de données. Jamais peur! Il existe quelques solutions de contournement dans ce cas particulier.
Pandas GroupBy vs SQL
C'est le bon moment pour introduire une différence importante entre l'opération Pandas GroupBy et la requête SQL ci-dessus. Le jeu de résultats de la requête SQL contient trois colonnes:
Etat
Le sexe HOMME ou FEMME
compter
Dans la version Pandas, les colonnes groupées sont poussées dans la MultiIndex
de la résultante Séries
par défaut:
>>> n_by_state_gender = df.par groupe([[[["Etat", "Le sexe HOMME ou FEMME"])[[[["nom de famille"].compter()
>>> type(n_by_state_gender)
>>> n_by_state_gender.indice[:[:[:[:5]
MultiIndex ([('AK''M')[('AK''M')[('AK''M')[('AK''M')
('AL', 'F'),
('AL', 'M'),
('AR', 'F'),
('BRAS')],
noms =['state', 'gender'])
Pour émuler plus étroitement le résultat SQL et repousser les colonnes groupées sur dans les colonnes du résultat, vous utilisez as_index = False
:
>>> df.par groupe([[[["Etat", "Le sexe HOMME ou FEMME"], as_index=Faux)[[[["nom de famille"].compter()
indiquer le genre last_name
0 AK F NaN
1 AK M 16.0
2 AL F 3.0
3 AL M 203.0
4 AR F 5.0
... ... ... ...
111 WI M 196.0
112 WV 1.0
113 WV M 119,0
114 WY F 2.0
115 WY M 38.0
[116 rows x 3 columns]
Cela produit un Trame de données
avec trois colonnes et un RangeIndex
, Plutôt qu'un Séries
avec un MultiIndex
. En bref, en utilisant as_index = False
rendra votre résultat plus proche de la sortie SQL par défaut pour une opération similaire.
Remarque: Dans df.groupby (["state", "gender"])["last_name"].compter()
, vous pouvez aussi utiliser .Taille()
au lieu de .compter()
, puisque vous savez qu'il n'y a pas NaN
noms de famille. En utilisant .compter()
exclut NaN
valeurs, tout en .Taille()
comprend tout, NaN
ou pas.
Notez également que les requêtes SQL ci-dessus utilisent explicitement COMMANDÉ PAR
, tandis que .par groupe()
ne fait pas. C'est parce que .par groupe()
fait-il cela par défaut à travers son paramètre Trier
, lequel est Vrai
sauf indication contraire de votre part:
>>> # Ne pas trier les résultats par les clés de tri
>>> df.par groupe("Etat", Trier=Faux)[[[["nom de famille"].compter()
Etat
DE 97
VA 432
SC 251
MD 305
PA 1053
...
AK 16
PI 13
VI 4
GU 4
AS 2
Nom: nom, longueur: 58, type: int64
Ensuite, vous plongerez dans l’objet qui .par groupe()
produit effectivement.
Comment Pandas GroupBy fonctionne
Avant d’entrer dans les détails, reculez pour regarder. .par groupe()
lui-même:
>>> par_etat = df.par groupe("Etat")
>>> impression(par_etat)
Qu'est-ce que c'est DataFrameGroupBy
chose? Ses .__ str __ ()
ne vous donne pas beaucoup d’informations sur ce qu’il est réellement ou comment cela fonctionne. La raison pour laquelle DataFrameGroupBy
L’objet peut être difficile à comprendre, c’est que c’est paresseux dans la nature. Il n’existe aucune opération permettant de produire un résultat utile tant que vous ne le dites pas.
Un terme fréquemment utilisé à côté de .par groupe()
est split-apply-combine. Cela fait référence à une chaîne de trois étapes:
- Divisé une table en groupes
- Appliquer certaines opérations à chacune de ces petites tables
- Combiner Les resultats
Il peut être difficile d'inspecter df.groupby ("state")
car il ne fait pratiquement rien de tout cela jusqu'à ce que vous fassiez quelque chose avec l'objet obtenu. Encore une fois, un objet Pandas GroupBy est paresseux. Il retarde pratiquement chaque partie du processus de combinaison application / division jusqu'à ce que vous invoquiez une méthode dessus.
Alors, comment pouvez-vous séparer mentalement la scission, appliquer et combiner des étapes si vous ne pouvez voir aucune d’elles se dérouler de manière isolée? Une méthode utile pour inspecter un objet Pandas GroupBy et voir la division en action consiste à effectuer une itération sur celui-ci. Ceci est mis en œuvre dans DataFrameGroupBy .__ iter __ ()
et produit un itérateur de (groupe, Trame de données
) paires pour DataFrames:
>>> pour Etat, Cadre dans par_etat:
... impression(F"2 premières entrées pour état! r")
... impression("------------------------")
... impression(Cadre.tête(2), fin=" n n")
...
2 premières entrées pour 'AK'
------------------------
prénom_nom prénom_anniversaire anniversaire genre type État partie
6619 Waskey Frank 1875-04-20 Représentant AK Démocrate
6647 Cale Thomas 1848-09-17 Représentant AK Indépendant
2 premières entrées pour 'AL'
------------------------
prénom_nom prénom_anniversaire anniversaire genre type État partie
912 Crowell John 1780-09-18 rep rep républicain
991 Walker John 1783-08-12 M sen AL Républicain
Si vous travaillez sur un problème d’agrégation difficile, itérer sur l’objet Pandas GroupBy peut être un excellent moyen de visualiser la Divisé partie de split-apply-combine.
Il existe quelques autres méthodes et propriétés qui vous permettent d'examiner les groupes individuels et leurs divisions. le .groupes
attribut vous donnera un dictionnaire de nom du groupe: étiquette du groupe
paires. Par exemple, par_etat
est un dict
avec des états comme clés. Voici la valeur pour le "PENNSYLVANIE"
clé:
>>> par_etat.groupes[[[["PENNSYLVANIE"]
Int64Index ([41921273857697684[41921273857697684[41921273857697684[41921273857697684
88
...
11842, 11866, 11875, 11877, 11887, 11891, 11932, 11945, 11959,
11973],
dtype = 'int64', length = 1053)
Chaque valeur est une séquence des emplacements d'index pour les lignes appartenant à ce groupe particulier. Dans la sortie ci-dessus, 4, 19, et 21 sont les premiers indices dans df
à laquelle l'état est égal à «PA».
Vous pouvez aussi utiliser .get_group ()
pour accéder à la sous-table à partir d'un seul groupe:
>>> par_etat.get_group("PENNSYLVANIE")
prénom_nom prénom_anniversaire anniversaire genre type État partie
4 Clymer George 1739-03-16 Représentant M NaN
19 Maclay William 1737-07-20 M sen PA anti-administration
21 Morris Robert 1734-01-20 M sen PA Pro-Administration
27 Wynkoop Henry 1737-03-02 représentant rep PA NaN
38 Jacobs Israel 1726-06-09 Représentant PA NaN
... ... ... ... ... ... ... ...
11891 Brady Robert 1945-04-07 représentant représentant démocrate
11932 Shuster Bill 1961-01-10 Représentant PA Républicain
11945 Rothfus Keith 1962-04-25 Représentant PA Républicain
11959 Costello Ryan 1976-09-07 Représentant PA Républicain
11973 Marino Tom 1952-08-15 Représentant PA Républicain
Ceci est pratiquement équivalent à utiliser .loc[]
. Vous pourriez obtenir le même résultat avec quelque chose comme df.loc[df["state"] == "PA"]
.
Remarque: J'utilise le terme générique Objet Pandas GroupBy se référer à la fois un DataFrameGroupBy
objet ou un SeriesGroupBy
objet, qui ont beaucoup de points communs entre eux.
Il convient également de mentionner que .par groupe()
ne fait certains, mais pas tous, des travaux de scission en construisant un Regroupement
instance de classe pour chaque clé que vous passez. Cependant, beaucoup de méthodes du BaseGrouper
classe qui détient ces groupes sont appelés paresseux plutôt que à __init __ ()
, et beaucoup utilisent également une conception de propriété en cache.
Ensuite, qu'en est-il de la appliquer partie? Vous pouvez considérer cette étape du processus comme appliquant la même opération (ou appelable) à chaque "sous-table" générée par l'étape de fractionnement. (Je ne sais pas si “sous-table” est le terme technique, mais je n’en ai pas trouvé de meilleur)
À partir de l'objet Pandas GroupBy par_etat
, vous pouvez saisir l’état initial des États-Unis et Trame de données
avec suivant()
. Lorsque vous parcourez un objet Pandas GroupBy, vous obtenez des paires que vous pouvez décompresser en deux variables:
>>> Etat, Cadre = suivant(iter(par_etat)) # Premier tuple d'itérateur
>>> Etat
'AK'
>>> Cadre.tête(3)
prénom_nom prénom_anniversaire anniversaire genre type État partie
6619 Waskey Frank 1875-04-20 Représentant AK Démocrate
6647 Cale Thomas 1848-09-17 Représentant AK Indépendant
7442 Grigsby George 1874-12-02 représentant rep AK NaN
Maintenant, repensez à votre opération initiale complète:
>>> df.par groupe("Etat")[[[["nom de famille"].compter()
Etat
AK 16
AL 206
AR 117
AS 2
AZ 48
...
le appliquer stade, lorsqu'il est appliqué à votre unique, sous-réglé Trame de données
, ressemblerait à ceci:
>>> Cadre[[[["nom de famille"].compter() # Compter pour l'état == 'AK'
16
Vous pouvez voir que le résultat, 16, correspond à la valeur de AK
dans le résultat combiné.
La dernière étape, combiner, est le plus explicite. Il prend simplement les résultats de toutes les opérations appliquées sur toutes les sous-tables et les combine de manière intuitive.
Exemple 2: Jeu de données sur la qualité de l'air
L'ensemble de données sur la qualité de l'air contient les lectures horaires d'un capteur de gaz en Italie. Les valeurs manquantes sont désignées par -200 dans le fichier CSV. Vous pouvez utiliser read_csv ()
pour combiner deux colonnes dans un horodatage tout en utilisant un sous-ensemble des autres colonnes:
importation pandas comme pd
df = pd.read_csv(
"groupby-data / airqual.csv",
parse_dates=[[[[[[[["Date", "Temps"]],
na_values=[[[[-200],
Usecols=[[[["Date", "Temps", "CO (GT)", "T", "RH", "AH"]
).Renommer(
Colonnes=
"CO (GT)": "co",
"Date_Time": "timbre",
"T": "temp_c",
"RH": "rel_hum",
"AH": "abs_hum",
).set_index("timbre")
Cela produit un Trame de données
avec un DatetimeIndex
et quatre flotte
Colonnes:
>>> df.tête()
co temp_c rel_hum abs_hum
timbre
2004-03-10 18:00:00 2.6 13.6 48.9 0.758
2004-03-10 19:00:00 2,0 13,3 47,7 0,726
2004-03-10 20:00:00 2.2 11.9 54.0 0.750
2004-03-10 21:00:00 2.2 11.0 60.0 0.787
2004-03-10 22:00:00 1,6 11,2 59,6 0,789
Ici, co
est la lecture moyenne de monoxyde de carbone de cette heure, temp_c
, rel_hum
, et abs_hum
sont la température moyenne en degrés Celsius, l'humidité relative et l'humidité absolue au cours de cette heure, respectivement. Les observations vont de mars 2004 à avril 2005:
>>> df.indice.min()
Horodatage ('2004-03-10 18:00:00')
>>> df.indice.max()
Horodatage ('2005-04-04 14:00:00')
Jusqu’à présent, vous avez regroupé des colonnes en spécifiant leurs noms str
, tel que df.groupby ("state")
. Mais .par groupe()
est beaucoup plus flexible que cela! Vous verrez comment ensuite.
Regroupement sur des tableaux dérivés
Plus tôt, vous avez vu que le premier paramètre à .par groupe()
peut accepter plusieurs arguments différents:
- Une colonne ou une liste de colonnes
- UNE
dict
ou des pandasSéries
- Un tableau NumPy ou des pandas
Indice
, ou un tableau semblable à ceux-ci
Vous pouvez profiter de la dernière option pour grouper par jour de la semaine. Vous pouvez utiliser les index .day_name ()
produire un pandas Indice
de cordes. Voici les dix premières observations:
>>> jour_noms = df.indice.nom_jour()
>>> type(jour_noms)
>>> jour_noms[:[:[:[:dix]
Indice([Mercredi«Mercredi»Mercredi»Mercredi»[Mercredi«Mercredi»Mercredi»Mercredi»['Wednesday''Wednesday''Wednesday''Wednesday''Wednesday'['Wednesday''Wednesday''Wednesday''Wednesday''Wednesday'
'Mercredi', 'jeudi', 'jeudi', 'jeudi', 'jeudi'],
dtype = 'object', name = 'tstamp')
Vous pouvez ensuite prendre cet objet et l'utiliser comme .par groupe()
clé. En Pandas-parler, jour_noms
est comme un tableau. C’est une séquence d’étiquettes à une dimension.
Remarque: Pour un pandas Séries
plutôt qu'un Indice
, vous aurez besoin du .dt
accesseur pour avoir accès à des méthodes telles que .day_name ()
. Si ser
est ton Séries
alors vous aurez besoin ser.dt.day_name ()
.
Maintenant, passez cet objet à .par groupe()
trouver le monoxyde de carbone moyen ()co
) lecture par jour de la semaine:
>>> df.par groupe(jour_noms)[[[["co"].signifier()
timbre
Vendredi 2.543
Lundi 2,017
Samedi 1.861
Dimanche 14h38
Jeudi 2.456
Mardi 2,382
Mercredi 2.401
Nom: co, type: float64
Le processus split-apply-combine se comporte en grande partie de la même manière qu'avant, à l'exception du fait que cette division est effectuée sur une colonne créée artificiellement. Cette colonne n’existe pas dans le DataFrame lui-même, mais en est dérivée.
Et si vous vouliez grouper non seulement par jour de la semaine, mais par heure de la journée? Ce résultat devrait avoir 7 * 24 = 168
observations. Pour ce faire, vous pouvez passer une liste d'objets ressemblant à des tableaux. Dans ce cas, vous passerez des pandas Int64Index
objets:
>>> heure = df.indice.heure
>>> df.par groupe([[[[jour_noms, heure])[[[["co"].signifier().rename_axis([[[["Dow", "heure"])
dow hr
Vendredi 0 1.936
1 1.609
2 1,172
3 0,887
4 0,823
...
Mercredi 19 4.147
20 3,845
21 2,898
22 2,102
23 1.938
Nom: co, Longueur: 168, type: float64
Voici encore un cas similaire qui utilise .Couper()
pour séparer les valeurs de température en intervalles discrets:
>>> bacs = pd.Couper(df[[[["temp_c"], bacs=3, Étiquettes=("cool", "chaud", "chaud"))
>>> df[[[[[[[["rel_hum", "abs_hum"]].par groupe(bacs).agg([[[["signifier", "médian"])
rel_hum abs_hum
médiane moyenne médiane
temp_c
cool 57.651 59.2 0.666 0.658
chaud 49.383 49.3 1.183 1.145
chaud 24.994 24.1 1.293 1.274
Dans ce cas, bacs
est en fait un Séries
:
>>> type(bacs)
>>> bacs.tête()
timbre
2004-03-10 18:00:00 cool
2004-03-10 19:00:00 cool
2004-03-10 20:00:00 cool
2004-03-10 21:00:00 cool
2004-03-10 22:00:00 cool
Nom: temp_c, dtype: catégorie
Catégories (3, objets): [cool < warm < hot]
Que ce soit un Séries
, NumPy tableau, ou la liste n'a pas d'importance. L’important est que bacs
sert toujours de séquence d'étiquettes, l'une des cool
, chaud
, ou chaud
. Si tu le voulais vraiment, tu pourrais aussi utiliser un Catégorique
tableau ou même un vieux-vieux liste
:
- Liste Python native:
df.groupby (bins.tolist ())
- Tableau catégorique des pandas:
df.groupby (bin.values)
Comme vous pouvez le voir, .par groupe()
est intelligent et peut gérer beaucoup de types d’entrées différents. N'importe lequel d'entre eux produirait le même résultat, car ils fonctionnent tous comme une séquence d'étiquettes sur lesquelles effectuer le regroupement et le fractionnement.
Rééchantillonnage
Vous avez groupé df
par jour de la semaine avec df.groupby (day_names)["co"].signifier()
. Considérons maintenant quelque chose de différent. Et si vous vouliez regrouper par année d’observation et par trimestre? Voici un moyen d’y parvenir:
>>> # Voir une alternative plus facile ci-dessous
>>> df.par groupe([[[[df.indice.année, df.indice.trimestre])[[[["co"].agg(
... [[[["max", "min"]
... ).rename_axis([[[["année", "trimestre"])
maximum minimum
trimestre de l'année
2004 1 8,1 0,3
2 7,3 0,1
3 7,5 0,1
4 11,9 0,1
2005 1 8,7 0,1
2 5,0 0,3
Toute cette opération peut aussi être exprimée par le biais de rééchantillonnage. Une des utilisations du ré-échantillonnage est comme groupe basé sur le temps. Tout ce que vous devez faire est de passer une chaîne de fréquence, telle que "Q"
pour "trimestriel"
, et les pandas feront le reste:
>>> df.rééchantillonner("Q")[[[["co"].agg([[[["max", "min"])
maximum minimum
timbre
2004-03-31 8.1 0.3
2004-06-30 7.3 0.1
2004-09-30 7,5 0,1
2004-12-31 11,9 0,1
2005-03-31 8,7 0,1
2005-06-30 5.0 0.3
Souvent, lorsque vous utilisez .resample ()
vous pouvez exprimer des opérations de regroupement basées sur le temps de manière beaucoup plus succincte. Le résultat peut être un peu différent de celui plus détaillé .par groupe()
équivalent, mais vous constaterez souvent que .resample ()
vous donne exactement ce que vous recherchez.
Exemple 3: jeu de données d'agrégateur de nouvelles
Vous allez maintenant travailler avec le troisième et dernier jeu de données, qui contient des métadonnées sur plusieurs centaines de milliers d'articles de nouvelles et les regroupe en groupes de sujets:
importation date / heure comme dt
importation pandas comme pd
def parse_millisecond_timestamp(ts: int) -> dt.date / heure:
"" "Convertissez ms depuis l'époque Unix en instance datetime UTC." ""
revenir dt.date / heure.à partir de l'horodatage(ts / 1000, tz=dt.fuseau horaire.UTC)
df = pd.read_csv(
"groupby-data / news.csv",
SEP=" t",
entête=Aucun,
index_col=0,
des noms=[[[["Titre", "url", "sortie", "Catégorie", "grappe", "hôte", "timbre"],
parse_dates=[[[["timbre"],
date_parser=parse_millisecond_timestamp,
type=
"sortie": "Catégorie",
"Catégorie": "Catégorie",
"grappe": "Catégorie",
"hôte": "Catégorie",
,
)
Pour le lire en mémoire avec le bon dyptes
, vous avez besoin d’une fonction d’aide pour analyser la colonne d’horodatage. En effet, il s’agit du nombre de millisecondes écoulées depuis l’époque Unix, plutôt que de quelques fractions de seconde, ce qui est la convention. Semblable à ce que vous avez fait auparavant, vous pouvez utiliser le logiciel catégorique. type
coder efficacement les colonnes qui ont un nombre relativement petit de valeurs uniques par rapport à la longueur de la colonne.
Chaque ligne du jeu de données contient le titre, l’URL, le nom du point de publication, le domaine, ainsi que l’horodatage de publication. grappe
est un identifiant aléatoire pour le cluster de sujets auquel un article appartient. Catégorie
est la catégorie nouvelles et contient les options suivantes:
b
pour le businesst
pour la science et la technologiee
pour le divertissementm
pour la santé
Voici la première rangée:
>>> df.iloc[[[[0]
titre officiel de la Fed dit wea ...
URL http: //www.latimes.co ...
outlet Los Angeles Times
catégorie b
cluster ddUyU0VZz0BRneMioxUPQ ...
hébergeur www.latimes.com
tstamp 2014-03-10 16: 52: 50.6 ...
Nom: 1, type: objet
Maintenant que vous avez un aperçu des données, vous pouvez commencer à poser des questions plus complexes à ce sujet.
Utiliser les fonctions Lambda dans .par groupe()
Cet ensemble de données invite beaucoup plus de questions potentiellement impliquées. Je vais en lancer un, aléatoire mais significatif: quels médias parlent le plus de la Réserve fédérale? Supposons, pour simplifier, que cela implique de rechercher des mentions sensibles à la casse de "Nourris"
. N'oubliez pas que cela peut générer des faux positifs avec des termes tels que «gouvernement fédéral».
Pour compter les mentions par point de vente, vous pouvez appeler .par groupe()
sur la sortie, puis littéralement .appliquer()
une fonction sur chaque groupe:
>>> df.par groupe("sortie", Trier=Faux)[[[["Titre"].appliquer(
... lambda ser: ser.str.contient("Nourris").somme()
... ).plus grand(dix)
sortie
Reuters 161
NASDAQ 103
Semaine d'affaires 93
Investing.com 66
Wall Street Journal (blog ) 61
MarketWatch 56
Moneynews 55
Bloomberg 53
GlobalPost 51
Economic Times 44
Nom: titre, type: int64
Décomposons cela car il y a plusieurs appels de méthode effectués successivement. Comme auparavant, vous pouvez extraire le premier groupe et son objet Pandas correspondant en prenant le premier tuple
du groupe PandasPar itérateur:
>>> Titre, ser = suivant(iter(df.par groupe("sortie", Trier=Faux)[[[["Titre"]))
>>> Titre
'Los Angeles Times'
>>> ser.tête()
Un responsable de la Fed a déclaré que les données météorologiques ...
486 actions tombent sur des nouvelles décourageantes en provenance d'Asie
1124 Indices de la montée de Gengis Khan, écrits dans l ...
1146 Les éléphants distinguent les voix humaines par sexe, âge ...
1237 Honda divise Acura en une division distincte pour ...
Nom: titre, type: objet
Dans ce cas, ser
est un pandas Séries
Plutôt qu'un Trame de données
. C’est parce que vous avez suivi la .par groupe()
appeler avec ["title"]
. Cela sélectionne effectivement cette colonne unique dans chaque sous-table.
Vient ensuite .str.contains ("Fed")
. Cela retourne un booléen Séries
C'est Vrai
lorsqu'un titre d'article enregistre une correspondance dans la recherche. Effectivement, la première ligne commence par "Un responsable de la Fed dit que les données sont faibles en raison de la météo, ..."
et s'allume comme Vrai
:
>>> ser.str.contient("Nourris")
1 vrai
486 Faux
1124 Faux
1146 Faux
1237 Faux
...
421547 Faux
421584 Faux
421972 Faux
422226 Faux
422905 Faux
Nom: titre, longueur: 1976, type: bool
La prochaine étape consiste à .somme()
cette Séries
. Puisque bool
est techniquement juste un type spécialisé de int
, vous pouvez résumer un Séries
de Vrai
et Faux
tout comme vous résumer une séquence de 1
et 0
:
>>> ser.str.contient("Nourris").somme()
17
Le résultat est le nombre de mentions de "Nourris"
par le Los Angeles Times dans le jeu de données. La même procédure est appliquée pour Reuters, NASDAQ, Businessweek et le reste du lot.
Améliorer la performance de .par groupe()
Revenons à nouveau à .groupby (...). apply ()
pour voir pourquoi ce modèle peut être sous-optimal. Pour obtenir des informations de base, consultez Comment accélérer vos projets Pandas. Que peut-il arriver avec .appliquer()
est qu'il va effectivement effectuer une boucle Python sur chaque groupe. Tandis que le .groupby (...). apply ()
pattern peut fournir une certaine flexibilité, il peut également empêcher Pandas d’utiliser ses optimisations basées sur Cython.
Tout cela pour dire que chaque fois que vous vous trouvez à penser à utiliser .appliquer()
, demandez-vous s’il existe un moyen d’exprimer l’opération de manière vectorielle. Dans ce cas, vous pouvez tirer parti du fait que .par groupe()
accepte non seulement un ou plusieurs noms de colonnes, mais aussi de nombreux comme un tableau structures:
- Un tableau NumPy à 1 dimension
- Une liste
- Un pandas
Séries
ouIndice
Notez également que .par groupe()
est une méthode d'instance valide pour un Séries
, pas seulement un Trame de données
, donc vous pouvez essentiellement inverser la logique de division. Dans cet esprit, vous pouvez d’abord construire un Séries
de booléens indiquant si le titre contient ou non "Nourris"
:
>>> mentions_fed = df[[[["Titre"].str.contient("Nourris")
>>> type(mentions_fed)
Maintenant, .par groupe()
est aussi une méthode de Séries
pour pouvoir en grouper un Séries
sur un autre:
>>> importation numpy comme np
>>> mentions_fed.par groupe(
... df[[[["sortie"], Trier=Faux
... ).somme().plus grand(dix).type(np.uintc)
sortie
Reuters 161
NASDAQ 103
Semaine d'affaires 93
Investing.com 66
Wall Street Journal (blog ) 61
MarketWatch 56
Moneynews 55
Bloomberg 53
GlobalPost 51
Economic Times 44
Nom: titre, type: uint32
Les deux Séries
ne pas avoir besoin d'être des colonnes de la même Trame de données
objet. Ils doivent simplement avoir la même forme:
>>> mentions_fed.forme
(422419,)
>>> df[[[["sortie"].forme
(422419,)
Enfin, vous pouvez convertir le résultat en un entier non signé avec np.uintc
si vous êtes déterminé à obtenir le résultat le plus compact possible. Voici une comparaison tête-à-tête des deux versions qui produiront le même résultat:
# Version 1: utilisation de `.apply ()`
df.par groupe("sortie", Trier=Faux)[[[["Titre"].appliquer(
lambda ser: ser.str.contient("Nourris").somme()
).plus grand(dix)
# Version 2: utilisation de la vectorisation
mentions_fed.par groupe(
df[[[["sortie"], Trier=Faux
).somme().plus grand(dix).type(np.uintc)
Sur mon ordinateur portable, la version 1 prend 4,01 secondes, tandis que la version 2 ne prend que 292 millisecondes. C'est une différence impressionnante de 14 fois le temps de calcul pour quelques centaines de milliers de lignes. Considérez à quel point la différence devient dramatique lorsque votre ensemble de données atteint quelques millions de lignes!
Remarque: Cet exemple présente quelques détails dans les données dans un souci de simplicité. À savoir, le terme de recherche "Nourris"
pourrait également trouver des mentions de choses comme «gouvernement fédéral».
Series.str.contains ()
prend également une expression régulière compilée en tant qu’argument si vous voulez avoir l’imagination et utiliser une expression impliquant un aspect négatif.
Vous voudrez peut-être aussi compter non seulement le nombre brut de mentions, mais également la proportion de mentions par rapport à tous les articles produits par un média.
Pandas GroupBy: Tout rassembler
Si vous appelez dir ()
sur un objet Pandas GroupBy, vous y verrez suffisamment de méthodes pour vous faire tourner la tête! Il peut être difficile de suivre toutes les fonctionnalités d’un objet Pandas GroupBy. Une façon de dissiper le brouillard consiste à compartimenter les différentes méthodes en ce qu’elles font et comment elles se comportent.
De manière générale, les méthodes d'un objet Pandas GroupBy appartiennent à une poignée de catégories:
-
Méthodes d'agrégation (aussi appelé méthodes de réduction) “Smush” de nombreux points de données dans une statistique agrégée sur ces points de données. Par exemple, prenons la somme, la moyenne ou la médiane de 10 nombres, pour lesquels le résultat n’est qu’un seul chiffre.
-
Méthodes de filtrage revenir à vous avec un sous-ensemble de l'original
Trame de données
. Cela signifie le plus souvent en utilisant.filtre()
supprimer des groupes entiers en se basant sur des statistiques comparatives concernant ce groupe et son sous-tableau. Il est également judicieux d’inclure dans cette définition un certain nombre de méthodes permettant d’exclure des lignes particulières de chaque groupe. -
Méthodes de transformation retourner un
Trame de données
avec la même forme et les mêmes indices que l'original, mais avec des valeurs différentes. Avec les méthodes d’agrégation et de filtrage, le résultatTrame de données
sera généralement de plus petite taille que l'entréeTrame de données
. Ce n'est pas le cas d'une transformation qui transforme les valeurs individuelles elles-mêmes tout en conservant la forme de l'original.Trame de données
. -
Méta méthodes sont moins concernés par l'objet original sur lequel vous avez appelé
.par groupe()
, et plus axé sur la fourniture d’informations de haut niveau telles que le nombre de groupes et les indices de ces groupes. -
Méthodes de traçage imiter l'API de tracer pour un pandas
Séries
ouTrame de données
, mais généralement diviser la sortie en plusieurs sous-parcelles.
La documentation officielle a sa propre explication de ces catégories. Elles sont, dans une certaine mesure, sujettes à interprétation et ce didacticiel pourrait diverger légèrement en classant quelle méthode tombe où.
Remarque: Il existe également une autre table séparée dans la documentation Pandas avec son propre système de classification. Choisissez celui qui vous convient et qui semble le plus intuitif!
Vous pouvez consulter une ventilation plus détaillée de chaque catégorie et des différentes méthodes de .par groupe()
qui tombent sous eux:
Méthodes d'agrégation (aussi appelé méthodes de réduction) “Smush” de nombreux points de données dans une statistique agrégée sur ces points de données. Par exemple, prenons la somme, la moyenne ou la médiane de 10 nombres, pour lesquels le résultat n’est qu’un seul chiffre. Voici quelques méthodes d'agrégation:
Méthodes de filtrage revenir à vous avec un sous-ensemble de l'original Trame de données
. Cela signifie le plus souvent en utilisant .filtre()
supprimer des groupes entiers en se basant sur des statistiques comparatives concernant ce groupe et son sous-tableau. Il est également judicieux d’inclure dans cette définition un certain nombre de méthodes permettant d’exclure des lignes particulières de chaque groupe. Voici quelques méthodes de filtrage:
Méthodes de transformation retourner un Trame de données
avec la même forme et les mêmes indices que l'original, mais avec des valeurs différentes. Avec les méthodes d’agrégation et de filtrage, le résultat Trame de données
sera généralement de plus petite taille que l'entrée Trame de données
. Ce n'est pas le cas d'une transformation qui transforme les valeurs individuelles elles-mêmes tout en conservant la forme de l'original. Trame de données
. Voici quelques méthodes de transformation:
Méta méthodes sont moins concernés par l'objet original sur lequel vous avez appelé .par groupe()
, et plus axé sur la fourniture d’informations de haut niveau telles que le nombre de groupes et les indices de ces groupes. Voici quelques méthodes méta:
Il existe quelques méthodes d’objets Pandas GroupBy qui ne tombent pas bien dans les catégories ci-dessus. Ces méthodes produisent généralement un objet intermédiaire qui est ne pas une Trame de données
ou Séries
. Par exemple, df.groupby (...). roulant (...)
produit un RollingGroupby
objet, que vous pouvez ensuite appeler des méthodes d'agrégation, de filtrage ou de transformation sur:
.expansion()
.tuyau()
.resample ()
.roulant()
Conclusion
Dans ce tutoriel, vous avez parcouru une tonne de terrain sur .par groupe()
, y compris sa conception, son API et comment enchaîner des méthodes pour obtenir des données dans une sortie adaptée à vos besoins.
Vous avez appris:
- Comment utiliser les opérations Pandas GroupBy sur des données réelles
- Comment le split-apply-combine chaîne d'opérations fonctionne et comment vous pouvez la décomposer en étapes
- Comment les méthodes d'un Pandas GroupBy peuvent être classées dans différentes catégories en fonction de leur intention et de leur résultat
Il y a beaucoup plus à .par groupe()
que vous pouvez couvrir dans un tutoriel. Check out the resources below and use the example datasets here as a starting point for further exploration!
You can download the source code for all the examples in this tutorial by clicking on the link below:
More Resources on Pandas GroupBy
Pandas documentation guides are user-friendly walk-throughs to different aspects of Pandas. Here are some portions of the documentation that you can check out to learn more about Pandas GroupBy:
The API documentation is a fuller technical reference to methods and objects:
[ad_2]