Python pas cher
L'un des emplois que tous les enseignants ont en commun est évaluer les étudiants. Que vous utilisiez des examens, des devoirs, des quiz ou des projets, vous devez généralement transformer les notes des élèves en classement par lettre à la fin du mandat. Cela implique souvent un tas de calculs que vous pourriez faire dans une feuille de calcul. Au lieu de cela, vous pouvez envisager d'utiliser Python et pandas.
Un problème avec l'utilisation d'une feuille de calcul est qu'il peut être difficile de voir quand vous faites une erreur dans une formule. Peut-être que vous avez sélectionné la mauvaise colonne et mis des questionnaires où les examens devraient aller. Vous avez peut-être trouvé au maximum deux valeurs incorrectes. Pour résoudre ce problème, vous pouvez utiliser Python et pandas pour faire tous vos calculs et trouver et corriger ces erreurs beaucoup plus rapidement.
Dans ce didacticiel, vous apprendrez à:
- Charge et fusionner des données provenant de plusieurs sources avec des pandas
- Filtre et groupe les données dans un pandas DataFrame
- Calculer et terrain notes dans un DataFrame pandas
Cliquez sur le lien ci-dessous pour télécharger le code de ce projet pandas et suivez-le pendant que vous créez votre script de carnet de notes:
Construit le: Dans ce didacticiel, vous allez construire un projet complet du début à la fin. Si vous souhaitez en savoir plus sur les pandas, consultez le parcours d'apprentissage des pandas.
Démo: ce que vous allez construire
Dans ce projet pandas, vous allez créer un script Python qui charge vos données de notes et calcule les notes des lettres pour vos élèves. Découvrez cette vidéo pour une démonstration du script en action:
Votre script s'exécutera à partir de la ligne de commande ou de votre IDE et produira des fichiers de sortie CSV afin que vous puissiez coller les notes dans le système de notation de votre école. Vous allez également produire quelques graphiques pour voir comment vos notes sont distribuées.
Aperçu du projet
Ce projet pandas comprend quatre étapes principales:
- Explorez les données vous utiliserez dans le projet pour déterminer le format et les données dont vous aurez besoin pour calculer vos notes finales.
- Charger les données dans les pandas DataFrames, en veillant à connecter les notes du même étudiant à toutes vos sources de données.
- Calculez les notes finales et enregistrez-les sous forme de fichiers CSV.
- Tracer la distribution des notes et découvrez comment les notes varient selon vos élèves.
Une fois ces étapes terminées, vous disposerez d'un script Python fonctionnel qui pourra calculer vos notes. Vos notes seront dans un format que vous devriez pouvoir télécharger dans le système de gestion des élèves de votre école.
Lecture de fond
Vous tirerez le meilleur parti de ce projet pandas si vous avez un peu d'expérience de travail avec les pandas. Si vous avez besoin d'une remise à niveau, ces tutoriels et cours vous permettront de vous familiariser avec ce projet:
Ne vous inquiétez pas trop de la mémorisation de tous les détails de ces didacticiels. Vous verrez une application pratique des sujets de ce projet pandas. Voyons maintenant les données que vous utiliserez dans ce projet!
Explorer les données de ce projet Pandas
Comme la plupart des enseignants, vous avez probablement utilisé une variété de services pour gérer votre classe ce trimestre, notamment:
- Le système de gestion des élèves de l'école
- Un service pour gérer l'attribution et la notation des devoirs et des examens
- Un service pour gérer l'attribution et la notation des quiz
Aux fins de ce projet, vous utiliserez des exemples de données qui représentent ce que vous pourriez retirer de ces systèmes. Les données sont dans des fichiers de valeurs séparées par des virgules (CSV). Quelques exemples de données sont présentés ici. Tout d'abord, il existe un fichier contenant les informations de la liste pour la classe. Cela proviendrait de votre système d'administration des étudiants:
Identifiant | Nom | NetID | Adresse électronique | Section |
---|---|---|---|---|
1234567 | «Barrera Jr., Woody» | WXB12345 | WOODY.BARRERA_JR@UNIV.EDU | 1 |
2345678 | «Lambert, Malaika» | MXL12345 | MALAIKA.LAMBERT@UNIV.EDU | 2 |
3456789 | "Joyce, Traci" | TXJ12345 | TRACI.JOYCE@UNIV.EDU | 1 |
4567890 | «Fleur, John Gregg» | JGF12345 | JOHN.G.2.FLOWER@UNIV.EDU | 3 |
Ce tableau indique le numéro d'identification, le nom, le NetID et l'adresse e-mail de chaque élève ainsi que la section de la classe à laquelle ils appartiennent. Dans ce terme, vous avez enseigné une classe qui s'est réunie à des moments différents, et chaque heure de classe a un numéro de section différent.
Ensuite, vous avez un fichier qui contient les devoirs et les résultats des examens. Celui-ci provient du service de devoirs et de notation des examens et a une disposition des colonnes légèrement différente de la liste:
SID | Prénom | Nom de famille | Devoirs 1 | Devoirs 1 – Max Points | Devoirs 1 – Heure de soumission | … |
---|---|---|---|---|---|---|
jgf12345 | Gregg | Fleur | 69 | 80 | 2019-08-29 08: 56: 02-07: 00 | … |
mxl12345 | Malaika | Lambert | 63 | 80 | 2019-08-29 08: 56: 02-07: 00 | … |
txj12345 | Traci | Joyce | 80 | 2019-08-29 08: 56: 02-07: 00 | … | |
wxb12345 | Boisé | Barrera | 55 | 80 | 2019-08-29 08: 56: 02-07: 00 | … |
Dans ce tableau, chaque élève a un SID, un prénom et un nom. De plus, trois valeurs sont rapportées pour chaque devoir et examen que vous avez donné:
- le But l'élève a reçu
- le score maximum pour cette affectation
- le temps l'étudiant a soumis le devoir
Enfin, vous avez des fichiers qui contiennent des informations sur les notes du quiz. Ces fichiers sont séparés de sorte qu'un quiz est stocké dans chaque fichier de données, et les informations dans ces fichiers sont différentes de la liste et des fichiers de devoirs:
Nom de famille | Prénom | Classe | |
---|---|---|---|
Barrera | Boisé | woody.barrera_jr@univ.edu | 4 |
Fleur | John | john.g.2.flower@univ.edu | 8 |
Joyce | Traci | traci.joyce@univ.edu | 8 |
Lambert | Malaika | malaika.lambert@univ.edu | 8 |
Dans le tableau du quiz, chaque élève a un nom, un prénom, un e-mail et une note de quiz. Notez que le score de quiz maximal possible n'est pas enregistré dans ce tableau. Vous verrez comment fournir ces informations ultérieurement.
En inspectant ces données, vous remarquerez peut-être plusieurs fonctionnalités:
-
Chaque tableau a différentes représentations des noms des élèves. Par exemple, dans le tableau de la liste, les noms sont sous la forme
"Nom Prénom"
avec des guillemets afin qu'un analyseur CSV n'interprète pas la virgule comme une nouvelle colonne. Cependant, dans le tableau des devoirs, les prénoms et les noms de famille obtiennent chacun leur propre colonne. -
Chaque élève peut utiliser un nom différent dans différentes sources de données. Par exemple, les tableaux de quiz n'incluent pas le suffixe
Jr.
au nom de Woody Barrera. Un autre exemple est que John Flower préfère être appelé par son deuxième prénom, Gregg, alors il a ajusté l'affichage dans le tableau des devoirs. -
L'adresse e-mail de chaque étudiant n'a pas les mêmes éléments. L'adresse e-mail de base d'un étudiant est
first.last@univ.edu
. Cependant, si un e-mail de ce formulaire appartient déjà à un autre étudiant, l'adresse e-mail est modifiée pour être unique. Cela signifie que vous ne pouvez pas prédire l'adresse e-mail d'un étudiant uniquement à partir de son nom. -
Chaque colonne peut utiliser un nom unique même si elle contient les mêmes données. Par exemple, tous les étudiants ont un identifiant du formulaire
abc12345
. La table de liste appelle cela leur NetID, tandis que la table des devoirs appelle cela leur SID. Les tables de quiz ne contiennent pas du tout ces informations. De même, certaines tables utilisent l'en-tête de colonneAdresse e-mail
, tandis que d'autres utilisent simplementEmail
. -
Chaque table trie les données différemment. Dans le tableau de liste, les données sont triées par
Identifiant
colonne. Dans le tableau des devoirs, les données sont triées par la première lettre du prénom. Dans les tableaux de quiz, les données sont triées dans un ordre aléatoire. -
Chacune des lignes ou colonnes des tableaux peut contenir des données manquantes. Par exemple, Traci Joyce n'a pas soumis son travail pour les devoirs 1, donc sa ligne est vide dans le tableau des devoirs.
Toutes ces fonctionnalités et bien plus sont présentes dans des données que vous verrez dans le monde réel. Dans le reste de ce projet pandas, vous verrez comment vous pouvez aborder chacune de ces fonctionnalités et vous assurer qu'elles ne perturbent pas votre analyse.
Décider du format final des données
Maintenant que vous avez vu les formats de données brutes, vous pouvez penser au format final des données. En fin de compte, vous devrez calculer une note pour chaque étudiant à partir de leurs notes brutes. Chaque ligne de votre tableau de données final contiendra toutes les données pour un seul élève. Le nombre de lignes sera alors égal au nombre d'élèves de votre classe.
Les colonnes représenteront chaque score de devoirs, score de quiz et score d'examen. Vous stockerez également des informations sur chaque élève, notamment son nom et son identifiant unique. Enfin, vous stockerez chacun de vos calculs et la note finale dans des colonnes distinctes.
Voici un échantillon de votre table finale:
Identifiant | Nom | Devoirs | Quiz | Examens | Score final | Note finale |
---|---|---|---|---|---|---|
Étudiant 1 | Derniers seront les premiers | # | # | # | # | UN F |
Étudiant 2 | Derniers seront les premiers | # | # | # | # | UN F |
… | … | … | … | … | … | … |
Chaque ligne du tableau stocke toutes les données d'un seul élève. La première colonne contient l'identifiant unique de l'élève et la deuxième colonne le nom de l'élève. Ensuite, une série de colonnes stocke les devoirs, le quiz, l'examen et les notes finales. Le dernier est une colonne pour la note finale.
Maintenant que vous avez vu quelle sera la forme finale des données, vous pouvez commencer à travailler avec les données. La première étape consiste à charger les données!
Chargement des données avec Pandas
Les pandas sont l'un des meilleurs packages pour travailler avec des données tabulaires en Python! Vous allez profiter de nombreuses fonctionnalités des pandas, en particulier pour fusionner des ensembles de données et effectuer des opérations mathématiques avec les données.
Les exemples de code présentés dans cette section sont collectés dans le 01-loading-the-data.py
fichier. Vous pouvez télécharger le code source en cliquant sur le lien ci-dessous:
Créez un script Python appelé gradebook.py
. Vous devrez également créer un dossier appelé Les données
qui stockera les fichiers de données d'entrée pour votre script de carnet de notes.
Puis dans gradebook.py
, commencez par ajouter une docstring au niveau du module qui explique le but du fichier. Vous pouvez également importer quelques bibliothèques dès maintenant:
"" "Calculez les notes des élèves en combinant des données provenant de nombreuses sources.
À l'aide de pandas, ce script combine les données de:
* Liste
* Devoirs et notes d'examen
* Grades de quiz
pour calculer les notes finales d'une classe.
"" "
de pathlib importer Chemin
importer pandas comme pd
Dans ce code, vous incluez une docstring qui décrit l'objectif du script. Ensuite, vous importez pathlib.Path
et pandas
.
Chargement du fichier de liste
Vous êtes maintenant prêt à charger les données, en commençant par la liste:
ICI = Chemin(__fichier__).parent
DATA_FOLDER = ICI / "Les données"
liste = pd.read_csv(
DATA_FOLDER / "roster.csv",
convertisseurs="NetID": str.inférieur, "Adresse électronique": str.inférieur,
usecols=[[[["Section", "Adresse électronique", "NetID"],
index_col="NetID",
)
Dans ce code, vous créez deux constantes, ICI
et DATA_FOLDER
, pour garder une trace de l'emplacement du fichier en cours d'exécution ainsi que du dossier dans lequel les données sont stockées. Ces constantes utilisent le pathlib
pour faciliter la consultation de différents dossiers.
Ensuite, vous lisez le fichier de liste en utilisant pd.read_csv ()
. Pour aider à traiter les données ultérieurement, vous définissez un index à l'aide de index_col
et inclure uniquement les colonnes utiles avec usecols
.
Pour vous assurer de pouvoir comparer les chaînes ultérieurement, vous passez également convertisseurs
argument pour convertir les colonnes en minuscules. Cela simplifiera les comparaisons de chaînes que vous ferez plus tard.
Vous pouvez voir certaines des données dans le liste
DataFrame ci-dessous:
NetID | Adresse électronique | Section |
---|---|---|
wxb12345 | woody.barrera_jr@univ.edu | 1 |
mxl12345 | malaika.lambert@univ.edu | 2 |
txj12345 | traci.joyce@univ.edu | 1 |
jgf12345 | john.g.2.flower@univ.edu | 3 |
Ce sont les quatre premières lignes de liste
, et ils correspondent aux lignes de la table de liste que vous avez consultée dans la section précédente. Cependant, le NetID
et Adresse électronique
les colonnes ont toutes deux été converties en chaînes minuscules car vous avez réussi str.lower
à convertisseurs
pour ces deux colonnes. Vous avez également omis le Nom
et Identifiant
Colonnes.
Chargement du fichier de devoirs et d'examen
Ensuite, vous pouvez charger le fichier CSV des devoirs et des notes d'examen. N'oubliez pas que ce fichier comprend le prénom et le nom et la colonne SID en plus de toutes les notes. Vous souhaitez ignorer les colonnes avec les heures de soumission:
hw_exam_grades = pd.read_csv(
DATA_FOLDER / "hw_exam_grades.csv",
convertisseurs="SID": str.inférieur,
usecols=lambda X: "Soumission" ne pas dans X,
index_col="SID",
)
Dans ce code, vous utilisez à nouveau le convertisseurs
argument pour convertir les données dans le SID
et Adresse électronique
colonnes en minuscules. Bien que les données de ces colonnes semblent être en minuscules lors de la première inspection, la meilleure pratique consiste à s'assurer que tout est cohérent. Vous devez également spécifier SID
comme colonne d'index pour correspondre à la liste
Trame de données.
Dans ce fichier CSV, il existe un certain nombre de colonnes contenant les heures de soumission des affectations que vous n'utiliserez dans aucune autre analyse. Cependant, il y a tellement d'autres colonnes que vous souhaitez conserver qu'il serait fastidieux de toutes les énumérer explicitement.
Pour contourner cela, usecols
accepte également les fonctions appelées avec un seul argument, le nom de la colonne. Si la fonction retourne Vrai
, la colonne est incluse. Sinon, la colonne est exclue. Avec le lambda
fonction que vous passez ici, si la chaîne "Soumission"
apparaît dans le nom de la colonne, la colonne sera exclue.
Voici un échantillon des hw_exam_grades
DataFrame pour vous donner une idée de l'apparence des données après leur chargement:
SID | … | Devoirs 1 | Devoirs 1 – Max Points | Devoirs 2 | … |
---|---|---|---|---|---|
jgf12345 | … | 69 | 80 | 52 | … |
mxl12345 | … | 63 | 80 | 57 | … |
txj12345 | … | nan | 80 | 77 | … |
wxb12345 | … | 55 | 80 | 62 | … |
Ce sont les lignes des exemples d'élèves dans le fichier CSV des devoirs et des notes d'examen que vous avez vu dans la section précédente. Notez que les données manquantes pour Traci Joyce (SID txj12345
) dans le Devoirs 1
la colonne a été lue comme nan
ou Pas un nombre, valeur. Vous verrez comment gérer ce type de données dans une section ultérieure. Les ellipses (...
) indiquent des colonnes de données qui ne figurent pas dans l'exemple ici mais qui sont chargées à partir des données réelles.
Chargement des fichiers de quiz
Enfin, vous devez charger les données des quiz. Il y a cinq questionnaires que vous devez lire, et la forme la plus utile de ces données est un DataFrame unique plutôt que cinq DataFrames distincts. Le format de données final ressemblera à ceci:
Quiz 5 | Quiz 2 | Quiz 4 | Quiz 1 | Quiz 3 | |
---|---|---|---|---|---|
woody.barrera_jr@univ.edu | dix | dix | 7 | 4 | 11 |
john.g.2.flower@univ.edu | 5 | 8 | 13 | 8 | 8 |
traci.joyce@univ.edu | 4 | 6 | 9 | 8 | 14 |
malaika.lambert@univ.edu | 6 | dix | 13 | 8 | dix |
Ce DataFrame a le Email
colonne comme index, et chaque quiz est dans une colonne distincte. Notez que les questionnaires sont hors service, mais vous verrez quand vous calculerez les notes finales que la commande n'a pas d'importance. Vous pouvez utiliser ce code pour charger les fichiers de quiz:
quiz_grades = pd.Trame de données()
pour chemin du fichier dans DATA_FOLDER.glob("quiz _ * _ grades.csv"):
quiz_name = "".joindre(chemin du fichier.tige.Titre().Divisé("_")[:[:[:[:2])
quiz = pd.read_csv(
chemin du fichier,
convertisseurs="Email": str.inférieur,
index_col=[[[["Email"],
usecols=[[[["Email", "Classe"],
).Renommer(Colonnes="Classe": quiz_name)
quiz_grades = pd.concat([[[[quiz_grades, quiz], axe=1)
Dans ce code, vous créez un DataFrame vide appelé quiz_grades
. Vous avez besoin du DataFrame vide pour la même raison que vous devez créer une liste vide avant d'utiliser list.append ()
.
Tu utilises Path.glob ()
pour trouver tous les fichiers CSV du quiz et les charger avec des pandas, en veillant à convertir les adresses e-mail en minuscules. Vous définissez également la colonne d'index pour chaque quiz sur les adresses e-mail des étudiants, qui pd.concat ()
utilise pour aligner les données de chaque élève.
Remarquez que vous passez axe = 1
à pd.concat ()
. Cela oblige les pandas à concaténer des colonnes plutôt que des lignes, en ajoutant chaque nouveau quiz dans une nouvelle colonne dans le DataFrame combiné.
Enfin, vous utilisez DataFrame.rename ()
pour changer le nom de la colonne de notes de Classe
à quelque chose de spécifique à chaque quiz.
Fusion des cadres de données de notes
Maintenant que toutes vos données sont chargées, vous pouvez combiner les données de vos trois DataFrames, liste
, hw_exam_grades
, et quiz_grades
. Cela vous permet d'utiliser un DataFrame pour tous vos calculs et d'enregistrer un carnet de notes complet dans un autre format à la fin.
Toutes les modifications apportées à gradebook.py
faites dans cette section sont collectées dans le 02-merging-dataframes.py
fichier. Vous pouvez télécharger le code source en cliquant sur le lien ci-dessous:
Vous allez fusionner les données en deux étapes:
- Fusionner
liste
ethw_exam_grades
ensemble dans un nouveau DataFrame appeléfinal_data
. - Fusionner
final_data
etquiz_grades
ensemble.
Vous utiliserez différentes colonnes dans chaque DataFrame comme clé de fusion, c'est ainsi que les pandas déterminent les lignes à conserver ensemble. Ce processus est nécessaire car chaque source de données utilise un identifiant unique différent pour chaque élève.
Fusionner la liste et les devoirs
Dans liste
et hw_exam_grades
, vous avez la colonne NetID ou SID comme identifiant unique pour un étudiant donné. Lorsque vous fusionnez ou rejoignez des DataFrames dans des pandas, il est très utile d'avoir un index. Vous avez déjà vu à quel point cela était utile lorsque vous chargiez les fichiers de quiz.
N'oubliez pas que vous avez réussi le index_col
argument à pd.read_csv ()
lorsque vous avez chargé la liste et les notes de devoirs. Vous pouvez maintenant fusionner ces deux DataFrames ensemble:
final_data = pd.fusionner(
liste, hw_exam_grades, left_index=Vrai, right_index=Vrai,
)
Dans ce code, vous utilisez pd.merge ()
pour combiner le liste
et hw_exam_grades
DataFrames.
Voici un exemple du DataFrame fusionné pour les quatre exemples d'étudiants:
NetID | Adresse électronique | … | Devoirs 1 | … |
---|---|---|---|---|
wxb12345 | woody.barrera_jr@univ.edu | … | 55 | … |
mxl12345 | malaika.lambert@univ.edu | … | 63 | … |
txj12345 | traci.joyce@univ.edu | … | nan | … |
jgf12345 | john.g.2.flower@univ.edu | … | 69 | … |
Comme vous l'avez vu précédemment, les ellipses indiquent des colonnes qui ne sont pas affichées dans l'exemple ici mais qui sont présentes dans le DataFrame réel. L'exemple de tableau montre que les élèves ayant le même NetID ou SID ont été fusionnés, de sorte que leurs adresses e-mail et notes de devoirs 1 correspondent aux tableaux que vous avez vus précédemment.
Fusion des notes du quiz
Lorsque vous avez chargé les données pour le quiz_grades
, vous avez utilisé l'adresse e-mail comme identifiant unique pour chaque élève. C'est différent de hw_exam_grades
et liste
, qui utilisaient respectivement le NetID et le SID.
Fusionner quiz_grades
dans final_data
, vous pouvez utiliser l'index à partir de quiz_grades
et le Adresse électronique
colonne de final_data
:
final_data = pd.fusionner(
final_data, quiz_grades, à gauche sur="Adresse électronique", right_index=Vrai
)
Dans ce code, vous utilisez le à gauche sur
argument à pd.merge ()
pour dire aux pandas d'utiliser le Adresse électronique
colonne dans final_data
dans la fusion. Vous utilisez également right_index
pour dire aux pandas d'utiliser l'index de quiz_grades
dans la fusion.
Voici un échantillon du DataFrame fusionné montrant les quatre exemples d'étudiants:
NetID | Adresse électronique | … | Devoirs 1 | … | Quiz 3 |
---|---|---|---|---|---|
wxb12345 | woody.barrera_jr@univ.edu | … | 55 | … | 11 |
mxl12345 | malaika.lambert@univ.edu | … | 63 | … | dix |
txj12345 | traci.joyce@univ.edu | … | nan | … | 14 |
jgf12345 | john.g.2.flower@univ.edu | … | 69 | … | 8 |
N'oubliez pas que les ellipses signifient que des colonnes sont manquantes dans l'exemple de table ici mais seront présentes dans le DataFrame fusionné. Vous pouvez revérifier les tableaux précédents pour vérifier que les nombres sont alignés pour les bons élèves.
Remplir nan
Valeurs
Maintenant, toutes vos données sont fusionnées en un seul DataFrame. Avant de pouvoir passer au calcul des notes, vous devez effectuer un nettoyage supplémentaire des données.
Vous pouvez voir dans le tableau ci-dessus que Traci Joyce a toujours un nan
valeur pour son devoir de devoirs 1. Vous ne pouvez pas utiliser nan
valeurs dans les calculs parce que, eh bien, ce ne sont pas un nombre! Vous pouvez utiliser DataFrame.fillna ()
d'attribuer un numéro à tous les nan
valeurs en final_data
:
final_data = final_data.fillna(0)
Dans ce code, vous utilisez DataFrame.fillna ()
pour tout remplir nan
valeurs en final_data
avec la valeur 0
. Il s'agit d'une résolution appropriée car le nan
dans la colonne Devoirs de Traci Joyce 1 indique que le score est manquant, ce qui signifie qu'elle n'a probablement pas remis le devoir.
Voici un échantillon du DataFrame modifié montrant les quatre exemples d'étudiants:
NetID | … | Prénom | Nom de famille | Devoirs 1 | … |
---|---|---|---|---|---|
wxb12345 | … | Boisé | Barrera | 55 | … |
mxl12345 | … | Malaika | Lambert | 63 | … |
txj12345 | … | Traci | Joyce | 0 | … |
jgf12345 | … | John | Fleur | 69 | … |
Comme vous pouvez le voir dans ce tableau, le score de Traci Joyce Homework 1 est désormais 0
au lieu de nan
, mais les notes des autres étudiants n'ont pas changé.
Calcul des notes avec des cadres de données Pandas
Il y a trois catégories de devoirs que vous aviez dans votre classe:
- Examens
- Devoirs
- Quiz
Chacune de ces catégories se voit attribuer un poids vers la note finale des élèves. Pour votre classe ce terme, vous avez attribué les poids suivants:
Catégorie | Pourcentage de la note finale | Poids |
---|---|---|
Examen 1 Score | 5 | 0,05 |
Score de l'examen 2 | dix | 0,10 |
Score de l'examen 3 | 15 | 0,15 |
Score du quiz | 30 | 0,30 |
Score de devoirs | 40 | 0,40 |
Le score final peut être calculé en multipliant le poids par le score total de chaque catégorie et en additionnant toutes ces valeurs. Le score final sera ensuite converti en une note finale.
Toutes les modifications apportées à gradebook.py
faites dans cette section sont collectées dans le 03-calculating-grades.py
fichier. Vous pouvez télécharger le code source en cliquant sur le lien ci-dessous:
Cela signifie que vous devez calculer le total de chaque catégorie. Le total de chaque catégorie est un nombre à virgule flottante de 0 à 1 qui représente le nombre de points qu'un élève a gagné par rapport au score maximum possible. Vous gérerez tour à tour chaque catégorie d'affectation.
Calcul du score total à l'examen
Vous calculerez d'abord les notes des examens. Étant donné que chaque examen a un poids unique, vous pouvez calculer le score total pour chaque examen individuellement. Il est plus judicieux d'utiliser un pour
boucle, que vous pouvez voir dans ce code:
n_exams = 3
pour n dans gamme(1, n_exams + 1):
final_data[[[[F"Examen n But"] = (
final_data[[[[F"Examen n"] / final_data[[[[F"Examen n - Max Points "]
)
Dans ce code, vous définissez n_exams
égal à 3
parce que vous avez passé trois examens pendant le trimestre. Ensuite, vous parcourez chaque examen pour calculer le score en divisant le score brut par le nombre maximal de points pour cet examen.
Voici un échantillon des données d'examen pour les quatre exemples d'étudiants:
NetID | Examen 1 Score | Score de l'examen 2 | Score de l'examen 3 |
---|---|---|---|
wxb12345 | 0,86 | 0,62 | 0,90 |
mxl12345 | 0,60 | 0,91 | 0,93 |
txj12345 | 1,00 | 0,84 | 0,64 |
jgf12345 | 0,72 | 0,83 | 0,77 |
Dans ce tableau, chaque élève a obtenu entre 0,0 et 1,0 pour chacun des examens. À la fin de votre script, vous multipliez ces scores par le poids pour déterminer la proportion de la note finale.
Calcul des scores de devoirs
Ensuite, vous devez calculer les scores des devoirs. Le nombre maximal de points pour chaque devoir varie de 50 à 100. Cela signifie qu'il existe deux façons de calculer le score des devoirs:
- Par score total: Additionnez les scores bruts et les points maximum indépendamment, puis prenez le rapport.
- Par score moyen: Divisez chaque score brut par ses points maximums respectifs, puis prenez la somme de ces ratios et divisez le total par le nombre d'affectations.
La première méthode donne un score plus élevé aux élèves qui ont obtenu des résultats constants, tandis que la deuxième méthode favorise les élèves qui ont bien réussi les travaux qui valaient plus de points. Pour aider les étudiants, vous leur donnerez le maximum de ces deux scores.
Le calcul de ces scores prendra quelques étapes:
- Collectez les colonnes avec des données de devoirs.
- Calculez le score total.
- Calculez le score moyen.
- Déterminez quel score est le plus grand et sera utilisé dans le calcul du score final.
Tout d'abord, vous devez collecter toutes les colonnes avec des données de devoirs. Vous pouvez utiliser DataFrame.filter ()
pour faire ça:
devoirs_scores = final_data.filtre(regex=r"^ Devoirs d d? $", axe=1)
homework_max_points = final_data.filtre(regex=r"^ Devoirs d d? -", axe=1)
Dans ce code, vous utilisez une expression régulière (regex) pour filtrer final_data
. Si un nom de colonne ne correspond pas à l'expression régulière, la colonne ne sera pas incluse dans le DataFrame résultant.
L'autre argument auquel vous passez DataFrame.filter ()
est axe
. De nombreuses méthodes d'un DataFrame peuvent fonctionner en ligne ou en colonne, et vous pouvez basculer entre les deux approches à l'aide de la axe
argument. Avec l'argument par défaut axe = 0
, les pandas rechercheraient dans l'index des lignes correspondant à l'expression régulière que vous avez transmise. Puisque vous voulez trouver tous les Colonnes qui correspondent à l'expression rationnelle à la place, vous passez axe = 1
.
Maintenant que vous avez collecté les colonnes dont vous avez besoin à partir du DataFrame, vous pouvez effectuer les calculs avec elles. Tout d'abord, vous additionnez les deux valeurs indépendamment, puis vous les divisez pour calculer le score total des devoirs:
sum_of_hw_scores = devoirs_scores.somme(axe=1)
sum_of_hw_max = homework_max_points.somme(axe=1)
final_data[[[["Total devoirs"] = sum_of_hw_scores / sum_of_hw_max
Dans ce code, vous utilisez DataFrame.sum ()
et passer le axe
argument. Par défaut, .somme()
additionnera les valeurs de toutes les lignes de chaque colonne. Cependant, vous voulez la somme de toutes les colonnes pour chaque ligne car chaque ligne représente un étudiant. le axe = 1
l'argument dit aux pandas de faire exactement cela.
Ensuite, vous affectez une nouvelle colonne dans final_data
appelé Total devoirs
au rapport des deux sommes.
Voici un exemple des résultats du calcul pour les quatre exemples d'élèves:
NetID | Somme des scores de devoirs | Somme des scores maximum | Total devoirs |
---|---|---|---|
wxb12345 | 598 | 740 | 0.808108 |
mxl12345 | 612 | 740 | 0,827027 |
txj12345 | 581 | 740 | 0,785135 |
jgf12345 | 570 | 740 | 0,770270 |
Dans ce tableau, vous pouvez voir la somme des scores des devoirs, la somme des scores max et le score total des devoirs pour chaque élève.
L'autre méthode de calcul consiste à diviser chaque score de devoirs par son score maximum, à additionner ces valeurs et à diviser le total par le nombre de devoirs. Pour ce faire, vous pouvez utiliser un pour
boucle et parcourez chaque colonne. Cependant, pandas vous permet d'être plus efficace car il correspondra aux étiquettes de colonne et d'index et effectuera des opérations mathématiques uniquement sur les étiquettes correspondantes.
Pour que cela fonctionne, vous devez modifier les noms de colonne pour homework_max_points
pour faire correspondre les noms devoirs_scores
. Vous pouvez le faire en utilisant DataFrame.set_axis ()
:
hw_max_renamed = homework_max_points.set_axis(devoirs_scores.Colonnes, axe=1)
Dans ce code, vous créez un nouveau DataFrame, hw_max_renamed
et vous définissez les colonnes axe
d'avoir les mêmes noms que les colonnes devoirs_scores
. Vous pouvez maintenant utiliser ce DataFrame pour plus de calculs:
average_hw_scores = (devoirs_scores / hw_max_renamed).somme(axe=1)
Dans ce code, vous calculez la average_hw_scores
en divisant chaque score de devoirs par ses points maximums respectifs. Ensuite, vous additionnez les ratios pour toutes les affectations de devoirs dans chaque ligne avec DataFrame.sum ()
et l'argument axe = 1
.
Étant donné que la valeur maximale pour chaque devoir individuel est de 1,0, la valeur maximale que cette somme pourrait prendre serait égale au nombre total de devoirs. Cependant, vous avez besoin d'un nombre qui va de 0 à 1 pour prendre en compte la note finale.
Cela signifie que vous devez diviser average_hw_scores
par le nombre d'affectations que vous pouvez faire avec ce code:
final_data[[[["Devoirs moyens"] = average_hw_scores / devoirs_scores.forme[[[[1]
Dans ce code, vous utilisez DataFrame.shape
pour obtenir le nombre d'affectations de devoirs_scores
. Comme un tableau NumPy, DataFrame.shape
renvoie un tuple de (n_rows, n_columns)
. Prendre la deuxième valeur du tuple vous donne le nombre de colonnes dans devoirs_scores
, qui est égal au nombre d'affectations.
Ensuite, vous affectez le résultat de la division à une nouvelle colonne dans final_data
appelé Devoirs moyens
.
Voici un exemple de résultat de calcul pour les quatre exemples d'étudiants:
NetID | Somme des notes moyennes des devoirs | Devoirs moyens |
---|---|---|
wxb12345 | 7.99405 | 0,799405 |
mxl12345 | 8.18944 | 0,818944 |
txj12345 | 7.85940 | 0,785940 |
jgf12345 | 7.65710 | 0,765710 |
Dans ce tableau, notez que le Somme des notes moyennes des devoirs
peut varier de 0 à 10, mais le Devoirs moyens
varie de 0 à 1. La deuxième colonne sera utilisée pour comparer à Total devoirs
suivant.
Maintenant que vous avez calculé vos deux notes de devoirs, vous pouvez prendre la valeur maximale à utiliser dans le calcul de la note finale:
final_data[[[["Score de devoirs"] = final_data[[[[
[[[["Total devoirs", "Devoirs moyens"]
].max(axe=1)
Dans ce code, vous sélectionnez les deux colonnes que vous venez de créer, Total devoirs
et Devoirs moyens
et attribuez la valeur maximale à une nouvelle colonne appelée Score de devoirs
. Notez que vous prenez le maximum pour chaque élève avec axe = 1
.
Voici un échantillon des résultats calculés pour les quatre exemples d'étudiants:
NetID | Total devoirs | Devoirs moyens | Score de devoirs |
---|---|---|---|
wxb12345 | 0.808108 | 0,799405 | 0.808108 |
mxl12345 | 0,827027 | 0,818944 | 0,827027 |
txj12345 | 0,785135 | 0,785940 | 0,785940 |
jgf12345 | 0,770270 | 0,765710 | 0,770270 |
Dans ce tableau, vous pouvez comparer les Total devoirs
, Devoirs moyens
et final Score de devoirs
Colonnes. Vous pouvez voir que le Score de devoirs
reflète toujours le plus grand des Total devoirs
ou Devoirs moyens
.
Calcul du score du quiz
Ensuite, vous devez calculer le score du quiz. Les questionnaires ont également différents nombres de points maximum, vous devez donc faire la même procédure que vous avez faite pour les devoirs. La seule différence est que la note maximale de chaque questionnaire n'est pas spécifiée dans les tableaux de données du questionnaire, vous devez donc créer une série pandas pour contenir ces informations:
quiz_scores = final_data.filtre(regex=r"^ Quiz d $", axe=1)
quiz_max_points = pd.Séries(
"Quiz 1": 11, "Quiz 2": 15, "Quiz 3": 17, "Quiz 4": 14, "Quiz 5": 12
)
sum_of_quiz_scores = quiz_scores.somme(axe=1)
sum_of_quiz_max = quiz_max_points.somme()
final_data[[[["Total des quiz"] = sum_of_hw_scores / sum_of_hw_max
average_quiz_scores = (quiz_scores / quiz_max_points).somme(axe=1)
final_data[[[["Quiz moyens"] = average_quiz_scores / quiz_scores.forme[[[[1]
final_data[[[["Score du quiz"] = final_data[[[[
[[[["Total des quiz", "Quiz moyens"]
].max(axe=1)
La plupart de ce code est assez similaire au code des devoirs de la dernière section. La principale différence avec le cas des devoirs est que vous avez créé une série pandas pour quiz_max_points
en utilisant un dictionnaire comme entrée. Les clés du dictionnaire deviennent des étiquettes d'index et les valeurs du dictionnaire deviennent les valeurs de série.
Étant donné que les étiquettes d'index dans quiz_max_points
avoir les mêmes noms que quiz_scores
, vous n'avez pas besoin d'utiliser DataFrame.set_axis ()
pour les quiz. pandas aussi émissions la forme d'une série afin qu'elle corresponde au DataFrame.
Voici un exemple du résultat de ce calcul pour les quiz:
NetID | Total des quiz | Quiz moyens | Score du quiz |
---|---|---|---|
wxb12345 | 0.808108 | 0,602139 | 0.808108 |
mxl12345 | 0,827027 | 0,682149 | 0,827027 |
txj12345 | 0,785135 | 0,585399 | 0,785135 |
jgf12345 | 0,770270 | 0,615286 | 0,770270 |
Dans ce tableau, le Score du quiz
est toujours le plus grand de Total des quiz
ou Quiz moyens
, comme prévu.
Calcul de la note de la lettre
Vous avez maintenant terminé tous les calculs requis pour la note finale. Vous avez des scores pour les examens, les devoirs et les questionnaires qui sont tous échelonnés entre 0 et 1. Ensuite, vous devez multiplier chaque score par sa pondération pour déterminer la note finale. Ensuite, vous pouvez mapper cette valeur sur une échelle pour les notes alphabétiques, de A à F.
Comme pour les scores de quiz maximaux, vous utiliserez une série pandas pour stocker les pondérations. De cette façon, vous pouvez multiplier par les colonnes correctes de final_data
automatiquement. Créez vos pondérations avec ce code:
pondérations = pd.Séries(
"Score de l'examen 1": 0,05,
"Score de l'examen 2": 0,1,
"Score de l'examen 3": 0,15,
"Score du quiz": 0,30,
"Score de devoirs": 0,4,
)
Dans ce code, vous donnez une pondération à chaque composant de la classe. Comme vous l'avez vu plus tôt, Examen 1
vaut 5%, Examen 2
vaut 10%, Examen 3
vaut 15%, les quiz valent 30% et Devoirs
vaut 40% de la note globale.
Ensuite, vous pouvez combiner ces pourcentages avec les scores que vous avez calculés précédemment pour déterminer le score final:
final_data[[[["Score final"] = (final_data[[[[pondérations.indice] * pondérations).somme(
axe=1
)
final_data[[[["Score plafond"] = np.plafond(final_data[[[["Score final"] * 100)
Dans ce code, vous sélectionnez les colonnes de final_data
qui ont les mêmes noms que l'index dans pondérations
. Vous devez le faire car certaines des autres colonnes de final_data
avoir un type str
, donc les pandas Erreur-type
si vous essayez de vous multiplier pondérations
par tous final_data
.
Ensuite, vous prenez la somme de ces colonnes pour chaque étudiant avec DataFrame.sum (axe = 1)
et vous attribuez le résultat à une nouvelle colonne appelée Score final
. La valeur de cette colonne pour chaque élève est un nombre à virgule flottante compris entre 0 et 1.
Enfin, étant le professeur vraiment sympa que vous êtes, vous allez arrondir la note de chaque élève. Vous multipliez chaque élève Score final
par 100
pour le mettre sur une échelle de 0 à 100, vous utilisez numpy.ceil ()
pour arrondir chaque score à l'entier le plus élevé suivant. Vous affectez cette valeur à une nouvelle colonne appelée Score plafond
.
Remarque: Vous devrez ajouter import numpy as np
en haut de votre script à utiliser np.ceil ()
.
Voici un exemple de résultat de calcul pour ces colonnes pour les quatre exemples d'étudiants:
NetID | Score final | Score plafond |
---|---|---|
wxb12345 | 0.805676 | 81 |
mxl12345 | 0,839419 | 84 |
txj12345 | 0,779917 | 78 |
jgf12345 | 0,773689 | 78 |
La dernière chose à faire est de mapper le score plafond de chaque élève sur une note de lettre. Dans votre école, vous pouvez utiliser les notes suivantes:
- UNE: Score de 90 ou plus
- B: Score entre 80 et 90
- C: Score entre 70 et 80
- ré: Score entre 60 et 70
- F: Score inférieur à 60
Étant donné que chaque note de lettre doit correspondre à une plage de scores, vous ne pouvez pas facilement utiliser simplement un dictionnaire pour le mappage. Heureusement, les pandas ont Series.map ()
, qui vous permet d'appliquer une fonction arbitraire aux valeurs d'une série. Vous pourriez faire quelque chose de similaire si vous utilisiez une échelle de notation différente de celle des lettres.
Vous pouvez écrire une fonction appropriée de cette façon:
grades =
90: "UNE",
80: "B",
70: "C",
60: "RÉ",
0: "F",
def grade_mapping(valeur):
pour clé, lettre dans grades.articles():
si valeur > = clé:
revenir lettre
Dans ce code, vous créez un dictionnaire qui stocke le mappage entre la limite inférieure de chaque grade de lettre et la lettre. Ensuite, vous définissez grade_mapping ()
, qui prend comme argument la valeur d'une ligne de la série de scores de plafond. Vous parcourez les éléments dans grades
, comparant valeur
à la clé
from the dictionary. If value
is greater than key
, then the student falls in that bracket and you return the appropriate letter grade.
Remarque: This function works only when the grades are arranged in descending order, and that relies on the order of the dictionary being maintained. If you’re using a version of Python older than 3.6, then you’ll need to use an OrderedDict
instead.
Avec grade_mapping()
defined, you can use Series.map()
to find the letter grades:
letter_grades = final_data[[[["Ceiling Score"].carte(grade_mapping)
final_data[[[["Final Grade"] = pd.Categorical(
letter_grades, catégories=grades.valeurs(), ordered=Vrai
)
In this code, you create a new Series called letter_grades
by mapping grade_mapping()
onto the Ceiling Score
column from final_data
. Since there are five choices for a letter grade, it makes sense for this to be a categorical data type. Once you’ve mapped the scores to letters, you can create a categorical column with the pandas Categorical
class.
To create the categorical column, you pass the letter grades as well as two keyword arguments:
catégories
is passed the values fromgrades
. The values ingrades
are the possible letter grades in the class.ordered
is passedVrai
to tell pandas that the categories are ordered. This will help later if you want to sort this column.
The categorical column that you create is assigned to a new column in final_data
appelé Final Grade
.
Here are the final grades for the four example students:
NetID | Final Score | Ceiling Score | Final Grade |
---|---|---|---|
wxb12345 | 0.805676 | 81 | B |
mxl12345 | 0.839419 | 84 | B |
txj12345 | 0.779917 | 78 | C |
jgf12345 | 0.773689 | 78 | C |
Among the four example students, two people got Bs and two people got Cs, matching their ceiling scores and the letter grade mapping you created.
Grouping the Data
Now that you’ve calculated the grades for each student, you probably need to put them into the student administration system. This term, you’re teaching several sections of the same class, as indicated by the Section
column in the roster table.
All of the modifications to gradebook.py
made in this section are collected in the 04-grouping-the-data.py
fichier. You can download the source code by clicking the link below:
To put the grades into your student administration system, you need to separate the students into each section and sort them by their last name. Fortunately, pandas has you covered here as well.
pandas has powerful abilities to group and sort data in DataFrames. You need to group your data by the students’ section number and sort the grouped result by their name. You can do that with this code:
pour section, table dans final_data.groupby("Section"):
section_file = DATA_FOLDER / F"Section section Grades.csv"
num_students = table.shape[[[[0]
impression(
F"In Section section there are num_students students saved to "
F"file section_file. "
)
table.sort_values(by=[[[["Last Name", "First Name"]).to_csv(section_file)
In this code, you use DataFrame.groupby()
sur final_data
to group by the Section
column and DataFrame.sort_values()
to sort the grouped results. Last, you save the sorted data to a CSV file for upload to the student administration system. With that, you’re done with your grades for the term and you can relax for the break!
Plotting Summary Statistics
Before you hang up the whiteboard marker for the summer, though, you might like to see a little bit more about how the class did overall. Using pandas and Matplotlib, you can plot some summary statistics for the class.
All of the modifications made to gradebook.py
in this section are collected in the 05-plotting-summary-statistics.py
fichier. You can download the source code by clicking the link below:
First, you might want to see a distribution of the letter grades in the class. You can do that with this code:
grade_counts = final_data[[[["Final Grade"].value_counts().sort_index()
grade_counts.terrain.bar()
plt.spectacle()
In this code, you use Series.value_counts()
sur le Final Grade
column in final_data
to calculate how many of each of the letters appear. By default, the value counts are sorted from most to fewest, but it would be more useful to see them in letter-grade order. Tu utilises Series.sort_index()
to sort the grades into the order that you specified when you defined the Categorical
column.
You then leverage pandas’s ability to use Matplotlib and produce a bar plot of the grade counts with DataFrame.plot.bar()
. Since this is a script, you need to tell Matplotlib to show you the plot with plt.show()
, which opens an interactive figure window.
Remarque: You’ll need to add import matplotlib.pyplot as plt
at the top of your script for this to work.
Your figure should look similar to the figure below:
The height of the bars in this figure represents the number of students who received each letter grade shown on the horizontal axis. The majority of your students got a B letter grade.
Next, you might want to see a histogram of the numerical scores of the students. pandas can use Matplotlib with DataFrame.plot.hist()
to do that automatically:
final_data[[[["Final Score"].terrain.hist(bins=20, label="Histogram")
In this code, you use DataFrame.plot.hist()
to plot a histogram of the final scores. Any keyword arguments are passed through to Matplotlib when the plotting is done.
A histogram is one way to estimate the distribution of the data, but you might be interested in more sophisticated methods as well. pandas has the ability to use the SciPy library to calculate a kernel density estimate with DataFrame.plot.density()
. You can also guess that the data will be normally distributed and manually calculate a normal distribution with the mean and standard deviation from your data. You can try this code to see how it works:
final_data[[[["Final Score"].terrain.density(
linewidth=4, label="Kernel Density Estimate"
)
final_mean = final_data[[[["Final Score"].mean()
final_std = final_data[[[["Final Score"].std()
X = np.linspace(final_mean - 5 * final_std, final_mean + 5 * final_std, 200)
normal_dist = scipy.stats.norm.pdf(X, loc=final_mean, scale=final_std)
plt.terrain(X, normal_dist, label="Normal Distribution", linewidth=4)
plt.Légende()
plt.spectacle()
In this code, you first use DataFrame.plot.density()
to plot the kernel density estimate for your data. You adjust the line width and label for the plot to make it easier to see.
Next, you calculate the mean and standard deviation of your Final Score
data using DataFrame.mean()
et DataFrame.std()
. Tu utilises np.linspace()
to generate a set of x-values from -5
à +5
standard deviations away from the mean. Then you calculate the normal distribution in normal_dist
by plugging into the formula for the standard normal distribution.
Remarque: You’ll need to add import scipy.stats
at the top of your script for this to work.
Finally, you plot X
contre normal_dist
and adjust the line width and add a label. Once you show the plot, you should get a result that looks like this:
In this figure, the vertical axis shows the density of the grades in a particular bin. The peak occurs near a grade of 0.83. Both the kernel density estimate and the normal distribution do a pretty good job of matching the data.
Conclusion
You now know how to build a gradebook script with pandas so you can stop using spreadsheet software. This will help you avoid errors and calculate your final grades more quickly in the future.
In this tutorial, you learned:
- Comment load, clean, et merge data into pandas DataFrames
- Comment calculate with DataFrames and Series
- Comment carte values from one set to another
- Comment terrain summary statistics using pandas and Matplotlib
In addition, you saw how to group data and save files to upload to your student administration system. Now you’re ready to create your pandas gradebook for next term!
Click the link below to download the code for this pandas project and learn how to build a gradebook without spreadsheets:
[ad_2]