Corrigé
Concours Nationaux d’Entrée aux Cycles de Formation d’Ingénieurs Session 2019
Découvrez la correction complète de l'épreuve d'informatique du Concours National d'Entrée aux Cycles de Formation d'Ingénieurs 2019 (Session Biologie). Ce guide couvre les fonctions Python de manipulation de données, l'algèbre relationnelle, les requêtes SQL et l'intégration SQLite3.
D'après le document Concours Nationaux d’Entrée aux Cycles de Formation d’Ingénieurs Session 2019
Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source
Biology, Computer Science, SQL, Programming · PDF · 5 pages · 2019
Afficher l'aperçu du document
Ce document présente la correction de l'épreuve d'informatique issue du Concours National d’Entrée aux Cycles de Formation d’Ingénieurs, session 2019, dans la filière Biologie. Il permet de réviser la programmation Python pour la manipulation de données, l'algèbre relationnelle, les requêtes SQL avancées, ainsi que l’utilisation de SQLite3 et Matplotlib.
Problème 1 : Programmation et structuration de données en Python
Ce problème porte sur plusieurs fonctions Python destinées à manipuler un ensemble de données représenté sous forme de dictionnaire. Chaque clé correspond à un attribut et chaque valeur à une liste d'observations associées.
1. Charge de données depuis un fichier (LoadFile)
La fonction charge un fichier texte dont la première ligne contient les noms des colonnes séparés par le caractère « # », et les lignes suivantes les valeurs associées.
def LoadFile(fname):
with open(fname) as f:
keys = f.readline().strip().split("#")
values = [[int(x) for x in l.split("#")] for l in f]
return {k: list(v) for k, v in zip(keys, zip(*values))}
Étapes clés :
- Ouverture du fichier à l'aide d'un bloc de gestion de contexte (
with). - Lecture et découpage de la première ligne pour obtenir les noms de colonnes (
keys). - Conversion des valeurs de chaque ligne en entiers.
- Transposition de la matrice de données avec
zip(*values)pour regrouper les valeurs par colonne. - Construction du dictionnaire final associant chaque clé à sa liste de valeurs.
2. Dénombrement des valeurs distinctes (CountValues)
Cette fonction compte le nombre de valeurs distinctes pour un attribut donné dans le jeu de données.
def CountValues(DEST, obs):
return len(set(DEST[obs]))
- Extraction de la liste d'observations
DEST[obs]. - Conversion en ensemble (
set) pour éliminer automatiquement les doublons. - Calcul de la cardinalité de l'ensemble avec
len().
3. Évaluation de la distribution des classes (EvalDistr)
Cette fonction évalue la distribution des décisions (classes 0 et 1) au sein de la clé "decision".
def EvalDistr(DSET):
decision = DSET.get("decision", [])
if len(decision) == 0:
return {0: 0.5, 1: 0.5}
p0 = decision.count(0) / len(decision)
return {0: p0, 1: 1 - p0}
- Si la liste des décisions est vide, la fonction retourne une distribution équiprobable
{0: 0.5, 1: 0.5}. - Sinon, elle calcule la fréquence relative
p0de la classe 0. - Elle retourne un dictionnaire contenant les proportions respectives des classes 0 et 1.
4. Test de pureté d'un jeu de données (IsPure)
Cette fonction vérifie si le jeu de données contient une seule classe de décision.
def IsPure(DSET):
return 1 in EvalDistr(DSET).values()
Si l'une des proportions calculées par EvalDistr est égale à 1, cela signifie que toutes les observations appartiennent à la même classe.
5. Identification des variables qualitatives binary (IsQualitative)
Cette fonction contrôle si chaque attribut du jeu de données contient exclusivement des valeurs binaires (0 ou 1).
def IsQualitative(DSET):
return {k: set(v) <= {0, 1} for k, v in DSET.items()}
Elle parcourt chaque variable et vérifie si l'ensemble de ses valeurs est un sous-ensemble de {0, 1}.
6. Scission d'un jeu de données selon un seuil (Cut)
La fonction divise le jeu de données en deux sous-ensembles en fonction d'un seuil S appliqué à la variable obs.
def Cut(DSET, obs, S=0.5):
keys = set(DSET)
keys.remove(obs)
DSET1, DSET2 = {}, {}
for k in keys:
vals1, vals2 = [], []
vals = DSET[k]
for i in range(len(vals)):
if DSET[obs][i] >= S:
vals1.append(vals[i])
else:
vals2.append(vals[i])
DSET1[k], DSET2[k] = vals1, vals2
oth_obs = keys.pop()
p0 = len(DSET1[oth_obs]) / len(DSET[obs])
return [DSET1, DSET2], [p0, 1 - p0]
7. Calcul de l'impureté d'un découpage (Impurity)
Cette fonction évalue l'impureté résiduelle après la scission du jeu de données selon un seuil.
def Impurity(DSET, obs, S=0.5):
[DSET1, DSET2], [p1, p2] = Cut(DSET, obs, S)
return p1 * min(EvalDistr(DSET1).values()) + p2 * min(EvalDistr(DSET2).values())
L'impureté totale est obtenue en calculant la moyenne pondérée de l'impureté minimale des sous-ensembles obtenus.
8. Tri des observations (SortObs)
Cette fonction réorganise les couples (valeur de l'observation, décision) par ordre croissant des valeurs de l'observation.
def SortObs(DSET, obs):
return sorted((v, d) for v, d in zip(DSET[obs], DSET["decision"]))
9. Recherche du meilleur seuil de coupure (BestCut)
La fonction détermine le seuil de coupure optimal minimisant l'impureté pour une observation donnée.
def BestCut(DSET, obs, Qual):
if Qual[obs]:
return (0.5, Impurity(DSET, obs))
else:
Lc = SortObs(DSET, obs)
Lseuil = []
if IsPure(DSET):
Lseuil.append(max(Lc)[0])
else:
for i in range(len(Lc) - 1):
vc, dc = Lc[i]
vn, dn = Lc[i + 1]
if dc != dn:
Lseuil.append((vc + vn) / 2)
sBest = min(Lseuil, key=lambda s: Impurity(DSET, obs, s))
return (sBest, Impurity(DSET, obs, sBest))
Problème 2 : Bases de données relationnelles et SQL
Partie 1 : Algèbre relationnelle
Question 1 : Extraction des identifiants, noms et descriptions des jeux de données au format « csv ».
Π ds_id, ds_name, ds_description (σ format = 'csv' (DataSet))
Question 2 : Extraction de la description des classifieurs utilisant le langage Python et la catégorie KNN.
Π cls_description (σ language = 'Python' et category = 'KNN' (Classifieur ⋈ cls_id Combine ⋈ m_name Method))
Partie 2 : Requêtes SQL
Question 3 : Modification du format des jeux de données de « csv » vers « docx ».
UPDATE DataSET
SET format = 'docx'
WHERE format = 'csv';
Question 4 : Suppression des classifieurs programmé en PASCAL.
DELETE FROM Classifieur
WHERE language = 'PASCAL';
Question 5 : Identifiants des classifieurs ayant un taux d'erreur strictement inférieur à 0.3.
SELECT ds_id
FROM Classifieur
WHERE error_rate < 0.3;
Question 6 : Recherche du nom du jeu de données contenant le plus grand nombre d'instances.
SELECT ds_name
FROM DataSET
WHERE nb_instances = (
SELECT MAX(nb_instances)
FROM DataSet
);
Question 7 : Jeux de données associés exclusivement à des classifieurs en Python (ou sans aucun classifieur).
SELECT ds_id
FROM DataSet AS D
WHERE NOT EXISTS (
SELECT * FROM Classifieur AS C
WHERE C.ds_id = D.ds_id AND language != 'Python'
);
Question 8 : Jeux de données n'ayant aucun classifieur associé.
SELECT ds_id
FROM DataSet
WHERE ds_id NOT IN (
SELECT ds_id
FROM Classifieur
);Question 9 : Nombre de classifieurs dont le taux d'erreur est supérieur à la moyenne globale.
SELECT COUNT(*)
FROM Classifieur
WHERE error_rate > (SELECT AVG(error_rate) FROM Classifieur);
Question 10 : Nombre de méthodes distinctes utilisées par chaque classifieur.
SELECT D.ds_id, COUNT(DISTINCT M.m_name) AS NB_M
FROM DataSet AS D,
Classifieur AS C,
Combine AS CM,
Method AS M
WHERE (D.ds_id = C.ds_id) AND
(C.cls_id = CM.cls_id) AND
(CM.m_name = M.m_name)
GROUP BY C.cls_id;
Question 11 : Liste des jeux de données associés aux classifieurs affichant le taux d'erreur minimal.
SELECT * FROM DataSet
WHERE ds_id IN (
SELECT ds_id FROM Classifieur
WHERE error_rate = (
SELECT MIN(error_rate)
FROM Classifieur
)
);
Question 12 : Jeux de données associés à au moins trois classifieurs développés en Java.
SELECT D.ds_id, ds_name
FROM DataSet AS D,
Classifieur AS C
WHERE (D.ds_id = C.ds_id) AND (language = 'Java')
GROUP BY ds_id
HAVING COUNT(*) >= 3;
Partie 3 : Intégration Python et SQLite3
Question 13 : Création de table, insertion groupée et génération de graphiques statistiques.
import sqlite3
import matplotlib.pyplot as plt
cnx = sqlite3.connect('C1.db')
cur = cnx.cursor()
sql_tbl = """
CREATE TABLE Method
(
m_name TEXT PRIMARY KEY,
category TEXT,
m_description TEXT
);
"""
cur.execute(sql_tbl)
sql_ins = """
INSERT INTO Method Values(?,?,?)
"""
lst_data = [(k,) + tuple(v) for k, v in dict_M.items()]
cur.executemany(sql_ins, lst_data)
cnx.commit()
sql_sel = """
SELECT ds_id, AVG(error_rate) AS M_erreur
FROM Classifieur
GROUP BY ds_id
ORDER BY ds_id
"""
cur.execute(sql_sel)
x, y = zip(*cur.fetchall())
plt.plot(x, y)
plt.show()
cnx.close()
Conseils de méthode
Pour réussir cette épreuve aux concours d'ingénieurs, plusieurs compétences clés sont évaluées :
- Structure de données Python : Maîtrisez les compréhensions de listes, les opérations sur ensembles (
set) et le modulezippour transposer efficacement des matrices. - Rigueur en SQL : Différenciez l'usage de
WHERE(filtrage des lignes) etHAVING(filtrage après agrégationGROUP BY). - Sous-requêtes logiques : Privilégiez l'utilisation de
NOT EXISTSouNOT INpour traiter les exclusions et vérifiez la cohérence des jointures multiples. - Gestion des bases de données en Python : N'oubliez jamais d'exécuter
cnx.commit()après des requêtes de modification (INSERT,UPDATE,DELETE) et de fermer la connexion.