Python >> Tutoriel Python >  >> Python

Comment diviser une liste en morceaux de taille égale ?

Dans cet article, vous apprendrez à diviser une liste en morceaux de taille égale en Python. Étape par étape, vous arriverez au code suivant pour découper votre liste en parties de taille égale :

Allez-y et jouez avec le code vous-même, mais si vous avez besoin d'explications, lisez la suite car je vais vous l'expliquer en détail :

Formulation du problème

Problème :Imaginez que vous ayez un capteur de température qui envoie des données toutes les 6 minutes, ce qui fait 10 points de données par heure. Tous ces points de données sont stockés dans une liste pour chaque jour.

Maintenant, nous voulons avoir une liste des températures moyennes horaires pour chaque jour. C'est pourquoi nous devons diviser la liste des données pour une journée en morceaux de taille égale .

Découper votre liste

Pour découper votre liste en parties consécutives de taille n , utilisez une boucle for pour itérer sur chaque n -th index utilisant la fonction intégrée de Python range(0, len(data), chunk_length) . Ensuite, utilisez l'index i comme position de départ pour obtenir le même nombre d'éléments consécutifs à partir de chaque position de départ en utilisant la fonction de découpage de Python data[i:i+chunk_length] .

Voici le code :

data = [15.7, 16.2, 16.5, 15.9, ..., 27.3, 26.4, 26.1, 27.2]
chunk_length = 10

for i in range(0, len(data), chunk_length):
    print(data[i:i+chunk_length])

Fonction de plage d'arrière-plan()

Le range() La fonction peut être utilisée avec un, deux ou trois arguments.

  • Si vous l'utilisez avec un argument unique , par exemple, range(10) , nous obtenons un objet range contenant les nombres de 0 à 9. Ainsi, si vous appelez range avec un argument, cet argument sera interprété comme la valeur d'arrêt de la range, mais il est exclu de la range.
  • Vous pouvez également appeler le range() fonction avec deux arguments , par exemple, range(5, 10) . Cet appel avec deux arguments renvoie un objet range contenant les nombres 5 à 9. Nous avons donc maintenant une limite inférieure et une limite supérieure pour la plage. Contrairement à la valeur d'arrêt, la valeur de départ est incluse dans la plage.
  • Dans un appel de la fonction range() avec trois arguments , le premier paramètre est la valeur de départ, le second est la valeur d'arrêt et la troisième valeur est la taille du pas. Par exemple, range(5, 15, 2) renvoie un objet plage contenant les valeurs suivantes :5, 7, 9, 11, 13. Comme vous pouvez le voir, la plage commence par le début, puis ajoute la valeur de pas tant que les valeurs sont inférieures à la valeur d'arrêt.

Dans notre problème, nos morceaux ont une longueur de 10, la valeur de départ est 0 et la valeur maximale est la fin de la liste de données.

Donc, si vous appelez le range(0, len(data), 10) , il itérera sur les indices de départ des morceaux. Mettons-y quelques chiffres pour illustrer cela :

Pour un seul jour, nous avons une longueur de données de 24 * 10 =240, donc l'appel de la fonction range serait ceci :range(0, 240, 10) et la plage résultante serait 0, 10, 20, 30, …, 230. Arrêtez-vous un instant et considérez ces valeurs :elles représentent les indices du premier élément de chaque bloc.

Alors qu'avons-nous maintenant ? Les indices de départ de chaque morceau ainsi que la longueur - et c'est tout ce dont nous avons besoin pour découper les données d'entrée en morceaux dont nous avons besoin.

Découpage en arrière-plan

L'opérateur de découpage prend deux ou trois arguments séparés par les deux-points : symbole. Ils ont la même signification que dans la fonction range.

Le découpage est un concept pour découper une sous-chaîne à partir d'une chaîne donnée. Utiliser la notation de découpage s[start:stop:step] pour accéder à tous les step -ème élément à partir de l'index start (inclus) et se terminant par l'index stop (exclu). Les trois arguments sont facultatifs, vous pouvez donc les ignorer pour utiliser les valeurs par défaut (start=0 , stop=len(lst) , step=1 ). Par exemple, l'expression s[2:4] à partir de la chaîne 'hello' taille la tranche 'll' et l'expression s[:3:2] taille la tranche 'hl' .

Si vous voulez en savoir plus sur le tranchage, lisez notre article détaillé ici. N'hésitez pas à regarder également notre vidéo de fond sur Python Slicing

Cependant, nous pouvons encore améliorer ce code et le rendre réutilisable en créant un générateur à partir de celui-ci.

Fragmentation avec des expressions génératrices

Un générateur est une fonction mais au lieu d'une instruction de retour, il utilise le mot-clé yield .

Le mot-clé yield interrompt la fonction et renvoie une valeur. La prochaine fois que la fonction est appelée, la valeur suivante est renvoyée et l'exécution de la fonction s'arrête à nouveau. Ce comportement peut être utilisé dans une boucle for, où nous voulons obtenir une valeur du générateur, travailler avec cette valeur à l'intérieur de la boucle, puis la répéter avec la valeur suivante. Voyons maintenant la version améliorée de notre code :

data = [15.7, 16.2, 16.5, 15.9, ..., 27.3, 26.4, 26.1, 27.2]
chunk_length = 10


def make_chunks(data, length):
    for i in range(0, len(data), length):
        yield data[i:i+length]
        
        
for chunk in make_chunks(data, chunk_length):
    print(chunk)

Cela semble déjà assez pythonique et nous pouvons réutiliser la fonction make_chunks() pour toutes les autres données que nous devons traiter.

Exemple de moyenne sur des morceaux

Terminons le code afin d'obtenir une liste des températures moyennes horaires en conséquence.

import random


def make_chunks(data, length):
    for i in range(0, len(data), length):
        yield data[i:i + length]

        
def process(chunk):
    return round(sum(chunk)/len(chunk), 2)


n = 10
# generate random temperature values
day_temperatures = [random.random() * 20 for x in range(24 * n)]
avg_per_hour = []

for chunk in make_chunks(day_temperatures, n):
    r = process(chunk)
    avg_per_hour.append(r)

print(avg_per_hour)

Et voilà, ce code pythonic cool résout notre problème. Nous pouvons rendre le code encore un peu plus court, mais je considère que ce code est moins lisible car vous devez connaître des concepts Python vraiment avancés.

import random


make_chunks = lambda data, n: (data[i:i + n] for i in range(0, len(data), n))
process = lambda data: round(sum(data)/len(data), 2)


n = 10
# generate random temperature values
day_temperatures = [random.random() * 20 for x in range(24 * n)]
avg_per_hour = []

for chunk in make_chunks(day_temperatures, n):
    r = process(chunk)
    avg_per_hour.append(r)

print(avg_per_hour)

Alors qu'est ce qu'on a fait? Nous avons réduit les fonctions d'assistance à des expressions lambda et pour la fonction génératrice, nous utilisons un raccourci spécial - la parenthèse.

Résumé

Nous avons utilisé la fonction range avec trois arguments, le start valeur, la arrêt valeur, et l'étape évaluer. En définissant la valeur de pas sur la longueur de bloc souhaitée, la valeur de départ sur 0 et la valeur d'arrêt sur la longueur totale des données, nous obtenons un objet de plage contenant tous les indices de départ de nos blocs. Avec l'aide du découpage, nous pouvons accéder exactement au morceau dont nous avons besoin à chaque étape d'itération.