Mickaël Tits CETIC mickael.tits@cetic.be
Les collections de données sont des objets de type dit conteneur, qui contiennent d'autres objets, tels que des int, string, d'autres collections de données, ou tout autre type d'objet (tels que ceux vus dans les chapitres suivants).
Ces collections permettent de structurer les données, en représentant soit différentes données d'un même type (une liste de prix par exemple), ou les différentes caractéristiques d'un élément (e.g.: l'adresse, la surface, et le prix d'une maison en vente).
La représentation des objets sous forme de collection permet de les traiter de manière systématique: appliquer une instruction sur chaque élément, filtrer tous les éléments respectant une conditions, etc.
En Python, il existe différents types de collection de données, qui ont chacune leurs spécificités, avantages et inconvénients:
list
): une séquence ordonnée d'objets modifiabletuple
): une séquence ordonnée d'objets immuable (voir ci-dessous)dict
): un ensemble de paires clé-valeurstr
) peut être vu comme une séquence ordonnée de caractèresset
): un ensemble d'objets distincts (pas abordés dans ce cours. Pour plus d'informations, voir ici ou ici)mystring = "1234"
mystring[2] = "0"
mystring
#Pour déclarer une liste d'éléments, on utilise des crochets []
my_list = [1, 3, 5, 7]
my_list
# Une liste peut contenir différents types de données
my_list2 = [3.14, 42, my_list, True, 'Namur']
my_list2
#La fonction len() permet de connaître la longueur d'une liste
len(my_list)
my_list[0]
my_list[2]
#Une erreur est obtenue si l'indice est invalide
#my_list[4]
#Un indice négatif part de la fin d'une liste
my_list[-1], my_list[-2]
#On peut accéder à plusieurs éléments d'une liste en utilisant un colon (:)
print(my_list[1:3]) #permet d'accéder aux éléments entre les indices 1 et 3 (3 exclu)
print(my_list[1:]) #permet d'accéder aux élements à partir de l'indice 1 (jusqu'au dernier)
print(my_list[:2]) #permet d'accéder aux éléments du premier jusqu'à l'indice 2 (2 exclu)
print(my_list[:]) #permet d'accéder à tous les éléments
print(my_list[1:4:2]) #permet d'accéder aux éléments de 1 à 4 (4 exclu) par pas de 2
#Additionner des listes résulte en une concaténation
my_list+[4, 5]
#Naturellement, la multiplication résulte en une multiple concaténation
my_list*2, [0]*10
#On peut modifier les éléments d'une liste (on dit que c'est un objet mutable)
my_list[0] = 42
my_list
#On ne peut pas additionner un entier à une liste
#my_list + 4
#Pour réaliser une opération sur chaque élément d'une liste, on peut utiliser une boucle for
#%%timeit
my_list_plus_4 = [0]*len(my_list)
for i in range(len(my_list)):
my_list_plus_4[i] = my_list[i] + 4
my_list_plus_4
#Ou
#%%timeit
my_list_plus_4 = [] #liste vide
for item in my_list:
my_list_plus_4.append(item + 4) #ajouter un élément à la nouvelle liste
my_list_plus_4
Pour chaque type de collection d'objets, différentes fonctions de base permettent de réaliser différents type d'opérations, tels que:
#permet de connaître la longueur d'une list
l = len(my_list)
#Les opérations mathématiques ne fonctionnent que sur les listes
#dont tous les éléments sont numériques
num_list = [1,2,3, True, 4.2]
s = sum(num_list)
M = max(num_list)
m = min(num_list)
a = any([False,False,True]) #output: True
A = all([False,False,True]) #output: False
print(l, s, M, m, a, A)
Instruction plus compacte, et plus rapide (et souvent plus lisible) pour réaliser une opération sur chaque élément dans une liste.
Syntaxe:
new_list = [instruction for item in list if condition]
Code équivalent sans compréhension de liste:
new_list = []
for item in list:
if condition:
output = instruction
new_list.append(output)
#Pour additionner un scalaire à chaque éléments d'une list, on peut aussi utiliser une "list-comprehension": plus compacte, et plus rapide
#%%timeit
my_list_plus_4 = [i + 4 for i in my_list]
my_list_plus_4
On peut représenter une matrice par une liste de listes. On peut réaliser une opération entre deux liste avec une double compréhension de liste.
Remarque: En pratique, pour les opérations mathématiques on utilise généralement des librairies spécialisées, telles que numpy
(voir Chapitre 5).
my_list1 = [1,2,3,4]
my_list2 = [5,6,7,8]
#my_list1'*my_list2:
matprod = [ [a*b for b in my_list2] for a in my_list1]
matprod
my_list = [-1, 2, 3, -7, 5, -4, 2, 8, -56, 9, 5.3, -4.5]
#Remplacer les nombres négatifs par 0 ?
zero_list = []
for item in my_list:
if item < 0:
zero_list.append(0)
else:
zero_list.append(item)
print('négatifs remplacés par 0:', zero_list)
#Ou
zero_list = [0 if item < 0 else item for item in my_list]
print('négatifs remplacés par 0, bis:', zero_list)
#Eliminer les nombres négatifs d'une liste ?
my_list = [-1, 2, 3, -7, 5, -4, 2, 8, -56, 9, 5.3, -4.5]
positive_list = [item for item in my_list if item >= 0]
print('négatifs éliminés:', positive_list)
Parmi une liste de prix, ne garder que ceux entre 200.000 et 300.000.
prices = [50000, 1000, 500000, 200000, 300000, 400000, 260000, 270000]
Solutions des exercices ici
Remarque: on utilise en général des tuples pour représenter une structure de données:
E.g.: a_house = ("Rue de Fer 25, Namur", "villa", 2000000, 4, "immoweb")
Avec des types généralement différents. Ce type de représentation a peu d'intérêt d'être mutable. Il représente les caractéristiques d'un bien immobilier dans cet exemple (addresse, type, prix, nombre de chambre, source). A l'inverse, on utilise généralement une liste pour représenter une collection d'objets homogènes (bien que ça accepte des types hétérogènes).
E.g.: house_prices = [200000, 350000, 170000, 270000]
L'utilisation d'une liste permet de facilement ajouter/supprimer des éléments (généralement du même type, e.g. de nouveaux prix), et de réaliser rapidement des instructions sur chaque élément grâce aux compréhensions de liste.
#L'utilisation de parenthèses permet de déclarer un tuple
my_tuple = ("Rue de Fer 25, Namur", "villa", 2000000, 4, "immoweb")
my_tuple
my_set = {2,1,1,2,1,3,1}
my_set.add(4)
my_set
# Les parenthèses sont conventionnelles mais ne sont cependant pas nécessaires pour déclarer un tuple
my_tuple = "Rue de Fer 25, Namur", "villa", 2000000, 4, "immoweb"
my_tuple
my_tuple[0]
#On ne peut pas modifier les éléments d'un tuple, on dit que c'est un "objet immuable" (immutable en anglais). La ligne suivante donne donc une erreur
my_tuple[2] = 300000
my_list = [-1, 2, 3, -7, 5, -4, 2, 8, -56, 9, 5.3, -4.5]
my_tuple = tuple(my_list)
%timeit my_list = [-1, 2, 3, -7, 5, -4, 2, 8, -56, 9, 5.3, -4.5]
%timeit my_tuple = (-1, 2, 3, -7, 5, -4, 2, 8, -56, 9, 5.3, -4.5)
Remarque:
Les commandes commençant pas % ou %% sont des "commandes magiques" propres aux Notebooks, et ne fonctionnent pas dans un script python classique.
Les dictionnaires sont des collection de données de type paire clé-valeur. On utilise des accolades {} pour déclarer un dictionnaire. Les dictionnaires sont des objets mutables, ce qui veut dire qu'on peut ajouter des clés et des valeurs après déclaration. Les dictionnaires permettent notamment de manipuler un ensemble de données tabulaires.
Remarque: Nous verrons plus loin qu'ils existe une représentation plus pratique de données tabulaires: le DataFrame.
house1 = {"address":"Rue de Fer 25, 5000 Namur", "website":"immoweb", "price": 400000, "surface":150}
house2 = {"address":"Rue de Bruxelles 42, 5000 Namur", "website":"immoweb", "price": 350000, "surface":200}
house3 = {"address":"Porte de Namur 25, Bruxelles", "website":"immovlan", "price": 400000, "surface":100}
#On peut modifier une valeur
house1["surface"] = 170
#On peut aussi ajouter une clé
house1["rooms"] = 4
#On peut itérer sur les clés d'un dictionnaire
for key in house1:
print(key, ' - ', house1[key])
#On peut utiliser des compréhension de dictionnaire (ce qui crée un nouveau dictionnaire)
house1_string = {key:str(house1[key]) for key in house1}
print("Valeurs du dictionnaire converties en strings:", house1_string)
#On peut aussi utiliser des compréhensions de liste (Remarque: on peut utiliser des compréhension de liste sur tout objet itérable, c'est-à-dire utilisable avec l'instruction "for")
is_string = [type(house1[key]) is str for key in house1]
print("is_string:", is_string)
#Dictionnaire de dictionnaires
house_dataset = {1:house1,2:house2,3:house3}
# => Facile d'extraire et ajouter une maison:
my_house = house_dataset[2]
house_dataset[4] = {"address":"Rue de Fer 26, Namur", "website":"immovlan", "price": 370000, "surface":170}
# Facile de filtrer les maisons:
big_houses = {k:house_dataset[k] for k in house_dataset if house_dataset[k]["surface"] > 150}
print("Grandes maisons:", big_houses)
# Moins facile d'extraire ou ajouter une caractéristique pour toutes les maisons: on doit modifier itérativement chaque élément (maison)!
rooms = [4,3,4,2]
keys = list(house_dataset.keys())
for i in range(4):
house_dataset[keys[i]]["rooms"] = rooms[i]
print(house_dataset)
#Dictionnaire de listes ?
#Remarque: on peut écrire la déclaration d'une collection d'objet (list [], tuple () ou dict{}) sur plusieurs lignes.
house_dataset2 = {"address":["Rue de Fer 25, 5000 Namur", "Rue de Bruxelles 42, 5000 Namur", "Porte de Namur 25, Bruxelles"],
"website":["immoweb","immoweb","immovlan"],
"price": [400000, 350000, 400000],
"surface":[150, 200, 100]}
# Plus facile d'extaire et ajouter une caractéristique:
prices = house_dataset2["price"]
house_dataset2["rooms"] = [4,3,4]
#Facile de filtrer des caractéristiques:
house_numbers = {k:house_dataset2[k] for k in house_dataset2 if type(house_dataset2[k][0]) is int}
print("Variables numériques:", house_numbers)
# Mais moins facile d'extraire ou ajouter une maison: on doit modifier itérativement chaque élément (liste)!
house4 = ("Rue de Fer 26, Namur", "immovlan", 370000, 170, 2)
keys = list(house_dataset2.keys())
for i in range(5):
house_dataset2[keys[i]].append(house4[i])
print(house_dataset2)
Remarque:
On verra plus tard qu'il existe une représentation plus pratique des données (le DataFrame), qu'on peut utiliser avec des librairies spécialisées.
address = "Rue de Bruxelles"
print("Premier élément:\n", address[0])
#On peut convertir un string en une autre collection simple (e.g., une liste)
print("Converti en liste:\n", list(address))
print("Converti en minuscules:\n", address.lower() )
print("Split des mots (i.e. splitter les chaînes entre les whitespaces (' ') ):\n", address.split(' ') )
for i in [0,1,2,3]:
itération sur chaque élément de la collectionif "n" in ["n","a","m","u","r"]:
permet de vérifier la condition qu'un élément soit dans une collection"n" in "namur"
=> True
address_list = ['Rue de la Loi, Bruxelles','Rue de Bruxelles 61, Namur',
'Rue de Fer 42, Namur', 'Chaussée de Bruxelles',
'Gauffre de Bruxelles', 'Grand Place, Bruxelles']
brux = []
for address in address_list:
if 'Bruxelles' in address:
brux.append(address)
print(brux)
#Ou
brux = [address for address in address_list if 'Bruxelles' in address]
print(brux)
Pour assigner une collection d'objet, on utilise []
pour une list
, ()
pour un tuple
, {}
pour un dict
.
Pour accéder aux éléments d'une collection, on utilise toujours des crochets [i]. E.g.: my_list[i], my_tuple[i], my_dict[i]
Pour appeler une function ou une méthode, on utilise des parenthèses. E.g. print(my_list), ou my_list.append(42)
my_list = ['a','b','c']
my_tuple = (1,2,3)
my_dict = {'a':1, 'b':2, 'c':3}
my_list.append('d')
print(my_list[3], my_tuple[0], my_dict['c'])
list
dict
tuple
set
len
sum
max
min
any
all
in
#list comprehension syntax:
[instruction for item in list if condition]
#dictionary comprehension syntax
{key_instruction:value_instruction for key in dict if condition}
Vous êtes maintenant capables de manipuler des collections d'objets, vous pouvez passer au Chapitre 3: Concepts avancés de programmation: exceptions, fonctions, objets