Archives Wild Code School
Python

List Comprehension

Quête 40 sur 66

List Comprehensions

Bienvenue dans la leçon sur les list comprehensions (syntaxe courte pour créer une liste) !

welcome_image

La Documentation se trouve dans la section 5.1.3

Contenu

Nous allons apprendre :

  • pourquoi on en a besoin,
  • de la structure de base à une version plus avancée,
  • comment écrire une dictionary comprehension (syntaxe courte pour créer un dictionnaire).

Prêt à commencer ? Avant de continuer ta lecture, assure-toi d'avoir terminé les quêtes suivantes :

A-t-on besoin des list comprehensions ??

Dans la Data, on fait généralement face à d'énormes quantités de valeurs qu'on doit traiter assez vite (dans certains cas extrêmes, "assez vite" veut dire "en moins d'une semaine". Dingue, non ?). Il existe plusieurs options, côté matériel comme côté logiciel, qui peuvent nous aider à améliorer le temps de traitement. Par exemple le GPU, Pandas et la programmation fonctionnelle. La première étape pour les utiliser efficacement, c'est d'arrêter de penser "valeur par valeur" (ou "une donnée après l'autre") et de commencer à penser "toutes les données d'un coup".

Passer du traitement d'une valeur au traitement de toutes les valeurs d'un coup : change ton point de vue !

L'une des principales différences entre la Data et le développement logiciel, côté code, c'est la quantité d'informations traitées en même temps. Les développeurs logiciels manipulent des variables qui occupent très peu de mémoire à la fois. En général, c'est une valeur ou un appel d'instance pour un traitement. Les gens de la Data traitent d'énormes quantités d'informations toutes en même temps, donc ils doivent réfléchir à comment tout traiter (ou la plupart) en une seule fois.

Regardons le code suivant. Admettons qu'on a une list de nombres et qu'on doit les mettre au carré.

python
some_list_of_numbers = [0, 1, 2, 3, 4, 5]
new_list_of_numbers = []

for number in some_list_of_numbers:
  new_list_of_numbers += [number ** 2]

new_list_of_numbers

Dans cet extrait de code, la boucle for prend chaque valeur, la met au carré, l'ajoute à la nouvelle list, puis passe à la valeur suivante. Donc la personne qui écrit considère le traitement de chaque valeur l'une après l'autre, puis les remet chacune dans une list.

L'objectif d'un code orienté Data avec de bonnes performances, c'est de traiter toutes les valeurs d'un coup. Si ce n'est pas possible, au moins des groupes de valeurs à la fois. Comment on fait ça ? On déplace l'attention de ce qui arrive à une valeur vers ce qui arrive à toutes les valeurs en même temps.

Pour l'exemple précédent :

python
some_list_of_numbers = [0, 1, 2, 3, 4, 5]
new_list_of_numbers = [number ** 2 for number in some_list_of_numbers]

new_list_of_numbers

Maintenant, on ne voit plus le traitement de chaque nombre, on se concentre juste sur la list entière.

Un autre avantage, c'est que sans indentation le code est plus facile à lire. Avec des codes plus longs, ce sera plus facile à suivre pour les yeux.

Voyons ce qui s'est passé avec un exemple de la vie réelle.

Avant de commencer, revoyons quelques concepts dont on a besoin :

↗
https://www.geeksforgeeks.org/ternary-operator-in-python/

Les opérateurs ternaires

geeksforgeeks.org

Le job des comprehensions !

Notre entreprise a trouvé un nouveau client et on se lance sur le projet !! yay_image

Notre client est une entreprise immobilière qui possède plusieurs immeubles en centre-ville. Les bureaux des immeubles qu'ils possèdent ont des capteurs, et le manager veut connaître la température moyenne par jour. Les capteurs viennent d'être installés et ils ont les données du dernier mois. Les capteurs enregistrent une mesure en Kelvin toutes les cinq minutes, donc on doit faire la moyenne par jour et présenter nos résultats. Le client veut les résultats en Celsius.

List Comprehension : structure de base

Une fois qu'on a la température moyenne par jour, on doit la convertir en Kelvin, comme demandé dans les spécifications.

Ce qu'un développeur logiciel écrirait :

python
temperature_in_kelvin = [301.15, 301.15, 303.15, 300.15, 301.15, 302.15, 324.15, 294.15, 301.15, 300.15, 297.15, 299.15, 302.15, 286.15, 301.15, 300.15, 298.15, 329.15, 299.15, 289.15, 299.15, 299.15, 299.15, 301.15, 301.15, 292.15, 300.15, 289.15, 299.15, 298.15, 298.15]
temperature_in_celsius = []

for t in temperature:
  temperature_in_celsius += [int(t - 273.15)]

print(temperature_in_celsius)

Revoyons la règle pour passer d'une boucle à une list comprehension :

list_comprehension_!.png

Comment transformer ce code en quelque chose qu'un professionnel de la Data écrirait :

python
temperature_in_celsius = [int(t - 273.15) for t in temperature]

print(temperature_in_celsius)

List Comprehension : structure de base avec une fonction

Le client s'est trompé ! Ils viennent de nous dire que la mesure vraiment demandée, c'est le Fahrenheit. Utilisons la formule pour convertir des Celsius en Fahrenheit :

$fahren = (celsius) * 9 / 5 + 32$

pour transformer les valeurs en Celsius en Fahrenheit

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren (t) for t in temperature_in_celsius]

print(temperature_in_fahren)

List Comprehension : structure avec un filtre

On est retournés voir notre client pour un retour. Ils ont regardé les chiffres et se sont rendu compte que certains étaient assez élevés. Ils ont compris que ça devait être des mesures erronées et veulent les retirer. Ils veulent que les valeurs supérieures à 39°C soient effacées de la list. Apparemment, ça ne les dérange pas d'avoir moins de valeurs dans la list, puisqu'il devrait y avoir une valeur par jour du mois dernier.

On doit filtrer la list de façon à ce que seules les valeurs qui satisfont la condition puissent être traitées et ajoutées à la nouvelle list.

python
temperature_in_fahren = []

def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

for t in temperature_in_celsius:
  if t < 40:
    temperature_in_fahren += [cels_to_fahren(t)]

print(temperature_in_fahren)

Utilisons cette règle :

list_comprehensions_2.png

et écrivons le code avec une list comprehension :

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren (t) for t in temperature_in_celsius if t < 40]

print(temperature_in_fahren)

List Comprehension : structure avec des conditions

Nos clients sont de retour. Ils ont vu le résultat et demandent quelques modifications supplémentaires. Certaines valeurs sont clairement fausses, leurs capteurs enregistrent une température trop basse. Maintenant ils veulent que toutes les valeurs en dessous de 68°F soient remplacées par 68°F.

Pour ça, on va ajouter une condition if à la valeur, en suivant cette règle :

list_comprehensions_3.png

Comme tu peux le voir, le deuxième if s'écrit comme un ternary operator (opérateur ternaire). Heureusement qu'on vient juste de réviser ça !

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren(t) for t in temperature_in_celsius]

# Additional list comprehension
temperature_checked = [t if t >= 68 else 68.0 for t in temperature_in_fahren]

print(temperature_checked)

Mettons tout ensemble

Nos clients sont maintenant satisfaits et on va améliorer la lisibilité du code.

C'est normal d'écrire plus de lignes de code au début et d'essayer d'en réduire le nombre plus tard. Faisons pareil.

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_processed = [cels_to_fahren(t) if cels_to_fahren(t) >= 68 else 68.0 for t in temperature_in_celsius if t < 40]

print(temperature_processed)

Dictionary Comprehensions

De la même façon, les dictionary comprehensions sont plus rapides à écrire et produisent un code plus rapide à lire. Tout le code sera plus facile à comprendre. Continuons avec notre exemple.

Nos clients sont de retour et veulent savoir pour combien de jours du mois on a chaque température. On va répondre à cette question avec une dictionary comprehension.

python
day_count = {t : temperature_processed.count(t) for t in set(temperature_processed)}

print(day_count)

Peux-tu deviner la règle que j'ai suivie pour la construire ?

quiz
true
# Est-ce la règle ? {k: v for v in list}
[x] Faux
[] Vrai

Ressources supplémentaires :

↗
https://www.w3schools.com/python/python_lists_comprehension.asp

List Comprehensions, général

w3schools.com
↗
https://www.pythonforbeginners.com/lists/nested-list-comprehensions-in-python

Listes imbriquées, avancé

pythonforbeginners.com
↗
https://youtu.be/AhSvKGTh28Q

List Comprehensions, vidéo avec exercices

youtu.be
↗
https://towardsdatascience.com/10-examples-to-master-python-dictionary-comprehensions-7aaa536f5960

Dictionary Comprehensions, complet avec exercices

towardsdatascience.com

Challenge

Bravo d'être arrivé jusqu'ici !

C'est l'heure du challenge !

image Crée une copie de ce notebook et réalise les tâches dessus : lien vers colab.

Une fois que tu as terminé, poste un lien vers ton notebook comme solution pour validation, n'oublie pas de le partager pour que toute personne ayant le lien puisse le lire.

Critères de validation

  • Le notebook est partagé de façon à être lisible par toute personne ayant le lien
  • Les exercices ont été correctement codés

List Comprehensions

Welcome to the List Comprehension Lesson!

welcome_image

Documentation is in the section 5.1.3

Content

We are going to learn:

  • why we need to use them,
  • from the basic structure to a more advanced one,
  • how to write a dictionary comprehension.

Ready to start? Before you keep reading, make sure you have completed the following quests:

Do we need list comprehensions??

In Data we are usually faced with huge amounts of values we need to process rather quickly (in some extreme cases "rather quickly" means "in less than a week". Crazy, ah?). There are multiple options, both hardware-wise and software-wise, that can help us improve the processing time. For example the GPU, Pandas, and functional programming. The first step to use them proficiently is to stop thinking "per value" (or "one piece of data after the next") and start thinking "all data at once".

From processing one value to processing all the values we have at once: change the focus!

On of the main differences between Data and Software Development, code-wise, is the amount of information processed at once. Software Developers have to do with variables that occupy very little memory space at once. Usually is a value or an instance-call for some process. Data people process huge amount of information all at once, so they need to think on how to process all of it - or most of it - in one go.

Let's look at the following code. Let's assume we have a list of numbers and we need to square them.

python
some_list_of_numbers = [0, 1, 2, 3, 4, 5]
new_list_of_numbers = []

for number in some_list_of_numbers:
  new_list_of_numbers += [number ** 2]

new_list_of_numbers

In this code snippet, the for-loop considers each value and after squaring each of them, adds them to the new list, and then moves on to the next value. So the writer considers processing each value one after the other and then putting each of them back in a list.

The goal of a Data-oriented code with good performance is to process all the values at once. If that's not possible, at least groups of values at once. How do we do this? We shift the focus from what happens to one value to what happens to all of them at once.

For the previous example:

python
some_list_of_numbers = [0, 1, 2, 3, 4, 5]
new_list_of_numbers = [number ** 2 for number in some_list_of_numbers]

new_list_of_numbers

Now we don't see what is the processing of each number anymore, we are just focusing on the entire list.

An additional advantage is that without indentation the code is easier to read. With longer codes, it will be easier for the eyes to follow.

Let's see what has happened with a real life example.

Before starting, let's review some concepts we need:

↗
https://www.geeksforgeeks.org/ternary-operator-in-python/

Ternary operators

geeksforgeeks.org

The Comprehensive Job!

Our company found a new client and we are getting in on the project!! yay_image

Our client is a real estate company and owns several buildings downtown. The offices in the buildings they own have sensors, and the manager wants to know the average temperature per day. The sensors have just been installed and they have the last month worth of data. The sensors record a reading in Kelvin every five minutes, so we need to average per day and present our findings. The client wants the results in Celsius.

List Comprehension - Basic structure

Once we got the average temperature per day, we need to turn it into Kelvin, as per specifications.

What a Software Developer will write:

python
temperature_in_kelvin = [301.15, 301.15, 303.15, 300.15, 301.15, 302.15, 324.15, 294.15, 301.15, 300.15, 297.15, 299.15, 302.15, 286.15, 301.15, 300.15, 298.15, 329.15, 299.15, 289.15, 299.15, 299.15, 299.15, 301.15, 301.15, 292.15, 300.15, 289.15, 299.15, 298.15, 298.15]
temperature_in_celsius = []

for t in temperature:
  temperature_in_celsius += [int(t - 273.15)]

print(temperature_in_celsius)

Let's review the rule to pass from a loop to a list comprehension:

list_comprehension_!.png

How to change this code in something a Data Professional would write:

python
temperature_in_celsius = [int(t - 273.15) for t in temperature]

print(temperature_in_celsius)

List Comprehension - Basic Structure using a Function

The client got it wrong! They just let us know the actual required metric is the Fahrenheit. Let's use the formula to convert from Celsius to Fahrenheit:

$fahren = (celsius) * 9 / 5 + 32$

to turn the Celsius values into Fahrenheit

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren (t) for t in temperature_in_celsius]

print(temperature_in_fahren)

List Comprehension - Structure using a Filter

We went back to our client for feedback. They looked at the numbers and realized that some of them were pretty high. They realized they must have been wrong readings and want them out. They want the values over 39°C erased from the list. Apparently they are not concern with having fewer values in the list, as there should be one value per day of the past month.

We need to filter the list in a way that only the values that satisfy the condition can be processes and added to the new list.

python
temperature_in_fahren = []

def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

for t in temperature_in_celsius:
  if t < 40:
    temperature_in_fahren += [cels_to_fahren(t)]

print(temperature_in_fahren)

Let's use this rule:

list_comprehensions_2.png

and write the code with a list comprehension:

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren (t) for t in temperature_in_celsius if t < 40]

print(temperature_in_fahren)

List Comprehension - Structure using Conditions

Our clients are back. They saw the result and are asking for some additional modifications. Some of the values are clearly wrong, they sensors are recording a temperature that is too low. Now they want that all the values below 68°F to be substituted with 68°F.

To do this we'll add a if condition to the value, following this rule:

list_comprehensions_3.png

As you can see the second if gets written as a ternary operator. Good thing we just had a refresher on that!

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_in_fahren = [cels_to_fahren(t) for t in temperature_in_celsius]

# Additional list comprehension
temperature_checked = [t if t >= 68 else 68.0 for t in temperature_in_fahren]

print(temperature_checked)

Let's put it all together

Our clients are now satisfied and we are going to improve the legibility of the code.

It's normal to write more lines of code at first and try to reduce the number later on. Let's do the same.

python
def cels_to_fahren(temp):
  return temp * 9 / 5 + 32

temperature_processed = [cels_to_fahren(t) if cels_to_fahren(t) >= 68 else 68.0 for t in temperature_in_celsius if t < 40]

print(temperature_processed)

Dictionary Comprehensions

In the same way, dictionary comprehensions are faster to write and produce code that is quicker to read. The whole code will be easier to understand. Let's keep using our example.

Our clients are back and want to know for how many days of the month we have each temperature. We are going to answer this question with a dictionary comprehension.

python
day_count = {t : temperature_processed.count(t) for t in set(temperature_processed)}

print(day_count)

Can you guess the rule I followed to build it?

quiz
true
# Is this the rule? {k: v for v in list}
[x] False
[] True

Additional Resources:

↗
https://www.w3schools.com/python/python_lists_comprehension.asp

List Comprehensions , General

w3schools.com
↗
https://www.pythonforbeginners.com/lists/nested-list-comprehensions-in-python

Nested Lists, Advanced

pythonforbeginners.com
↗
https://youtu.be/AhSvKGTh28Q

List Comprehensions, video with exercises

youtu.be
↗
https://towardsdatascience.com/10-examples-to-master-python-dictionary-comprehensions-7aaa536f5960

Dictionary Comprehensions, comprehensive with exercises

towardsdatascience.com

Challenge

Great job arriving here!

Now is challenge time!

image Create a copy of this notebook and carry out the tasks on it: link to colab.

Once you are finished, post a link to your notebook as a solution for validation, don't forget to share it so that anyone who has the link can read it.

Validation criterias

  • The notebook is shared so that is readable by anyone with the link
  • The exercises have been correctly coded