Récuperer les nombres dans deux tabelaux

Récuperer les nombres dans deux tabelaux - Python - Programmation

Marsh Posté le 14-05-2012 à 15:30:29    

Bonjour,
 
J'ai un petit soucis pour sélectionner des nombres dans python, j'aimerais sélectionner les données d'un tableau a et d'un tableau b si on respecte une certaine condition sur les données de b.  
 
Mon "script" est le suivant
 
a=[3,5,7,9,11]
b=[1,24,65,78,2]
c=[(val_1,val_2) for val_1,val_2 in a,b if val_2<60]
print(c)
 
j'aimerais alors que la ligne suivante s'imprime
c=[(3,1),(5,24),(11,2)]
 
et comme vous pouvez vous en douter ça ne marche pas en effet j'ai déjà fait comme ça pour récupérer des données d'une même liste mais pour deux listes je ne trouve pas la bonne façon de faire, j’espère vraiment que vous allez pouvoir m'aider car je suis totalement débutante et j'ai essayé plein de trucs différents et aucun ne marche. Je craque!!!!  
Je vous remercie d'avance pour votre aide

Reply

Marsh Posté le 14-05-2012 à 15:30:29   

Reply

Marsh Posté le 14-05-2012 à 18:17:38    

Rapidement ça donnerait :
 

Code :
  1. [(x,y) for x,y in zip(a,b) if y < 60]


Pas tout à fait optimal vu que zip(a,b) va te renvoyer une liste complète des tuples a,b alors que tu vas en dégager certains qui respectent pas ta condition, m'enfin...

Reply

Marsh Posté le 15-05-2012 à 13:38:25    

Cool, merci beaucoup!!!

Reply

Marsh Posté le 15-05-2012 à 14:36:22    

En fait j'ai un autre soucis, je cherche à récupérer des max sur des intervalles, j'ai donc découpé en intervalles puis je trie et je récupère la dernière valeur, tout marche bien sauf que je n'arrive pas à mettre ces résultats sous forme de tableau dans un fichier résultat, malgré toutes mes tentatives donc si vous pourriez me donner encore un petit coup de pouce ça serait génial.
 
for i in range(20):
 alpha=2500*i
 beta=2500*(i+1)
 c=[(val_1,val_2) for val_1,val_2 in zip(f,h) if alpha<val_1<beta]
 
 
 trie=[(val1,val2) for val1,val2 in sorted(c))]  
 
 taille_trie=len(trie)
 
 maximum=trie[taille_trie-1]
 
 
 for (val1,val2) in maximum:
    tableau="%8s %8s" % (val1,val2)+"\n"  
    res=open("resultat.txt","a" )
    res.write(tableau)
 
Erreur PYTHON:
Traceback (most recent call last):
  File "enveloppe.py", line 36, in <module>
    for (val1,val2) in maxi:
TypeError: 'int' object is not iterable

Reply

Marsh Posté le 15-05-2012 à 15:26:29    

Me semble logique, dans

Code :
  1. maximum=trie[taille_trie-1]


tu récupères un tuple (int, int). Ensuite tu tentes d'itérer sur ce tuple unique en l'unpackant, c'est pas possible. À quoi te sert ton maximum et pourquoi t'itère là dessus et non sur ton array?
 
Accessoirement, la première boucle sert à rien, tu prends que la dernière itération en compte.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 15-05-2012 à 16:40:19    

en fait j'ai deux intervalles a et b, je cherche à récupérer pour tous les nombres compris entre 0 et 2500 dans a le maximum dans b et de même entre 2500 et 5000.... jusqu'à 50000. (les indices de a correspondent aux indices de b). Je sais que c'est surement top comme j'ai fait mais vu que j'utilise python pour la première fois c'est la seule méthode que j'ai réussie à faire tourner!  
 
En effet écrit comme ça la première boucle ne sert à rien  :pt1cable:  

Reply

Marsh Posté le 15-05-2012 à 18:04:13    

joaninha18 a écrit :

en fait j'ai deux intervalles a et b, je cherche à récupérer pour tous les nombres compris entre 0 et 2500 dans a le maximum dans b et de même entre 2500 et 5000.... jusqu'à 50000. (les indices de a correspondent aux indices de b). Je sais que c'est surement top comme j'ai fait mais vu que j'utilise python pour la première fois c'est la seule méthode que j'ai réussie à faire tourner!


Bon ça me semble confus, on va voir si j'arrive à comprendre:
 

  • Tu as deux séquences A et B, qui sont des séquences de nombres je présume? Des séquences non ordonnées?
  • Ce sont en fait des correspondances, avec les nombres de A compris entre 0 et 50000, et les nombres de B on s'en fout
  • Pour toute section de 2500 de A (les valeurs de A dans [0, 2500[, dans [2500, 5000[, ...) tu veux le B maximum pour la section

C'est ça?
 
Trucs pas indiqués: quand tu récupères le maximum de B pour chaque section, tu veux la valeur de A correspondant? Et l'intervalle de A (genre 7500, 10000)?


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-05-2012 à 14:34:54    

C'est exactement ça!!! Et je veux récupérer le couple sous forme de tableau dans un fichier texte car avec ma technique (très probablement médiocre), je ne récupère ces couples que dans la console et je dois faire un copier coller puis enlever les parenthèses et les virgules en bref ce n'est pas super optimisé!!!
 
(merci pour votre patience!)

Reply

Marsh Posté le 16-05-2012 à 15:30:53    

joaninha18 a écrit :

C'est exactement ça!!! Et je veux récupérer le couple


"Le couple", c'est la paire (valeur de A, valeur de B) dans chaque section de A?

joaninha18 a écrit :

sous forme de tableau dans un fichier texte


Qu'entends tu par "sous forme de tableau"? Il y a des miyons de manières de modéliser un tableau dans un fichier texte, de fixed-length (chaque colonne prend N caractère point barre) à une table org-mode


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-05-2012 à 17:23:59    

oui désolé pour la confusion par couple je voulais dire paire (valeur de A, valeur de B) dans chaque section de A et par tableau c'est à dire si je récupère les paires suivantes (200, 30) (2700, 50) avoir le tableau suivant
200     30
2700   50
.........

Reply

Marsh Posté le 16-05-2012 à 17:23:59   

Reply

Marsh Posté le 16-05-2012 à 18:53:32    

joaninha18 a écrit :

oui désolé pour la confusion par couple je voulais dire paire (valeur de A, valeur de B) dans chaque section de A et par tableau c'est à dire si je récupère les paires suivantes (200, 30) (2700, 50) avoir le tableau suivant
200     30
2700   50
.........


Genre du tab-separated values quoi


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-05-2012 à 21:37:13    

En effet, je ne savais pas ce qu'étais un tab-separated values mais après avoir regardé sur internet je confirme que c'est ça que je cherche à faire!

Reply

Marsh Posté le 17-05-2012 à 17:56:08    

Bon, dans la mesure où on a établi les specs, on peut résoudre le problème.

 

Pour commencer, il nous faut deux séquences, je vais les générer mais normalement on voudra probablement les récupérer de stdin ou d'un fichier quelconque.

Code :
  1. #
  2.    >>> STEP = 2500
  3.    >>> MAX = 50000
  4.    >>> import random, operator, pprint
  5.    >>> # seed statique histoire de toujours avoir les mêmes résultats, sinon pas possible de faire des assertions
  6.    >>> random.seed("joaninha18" )
  7.    >>> # On va faire des séquences de 100 nombres
  8.    >>> As = [random.randrange(MAX) for i in xrange(100)]
  9.    >>> # avec des bs dans [0, 100[
  10.    >>> Bs = [random.randrange(100) for i in xrange(100)]


Bien, on a notre setup: une liste de A, une liste de B, maintenant on veut splitter ça dans nos 20 ranges. On va utiliser la manière la plus simple (mais probablement la plus lente) de le faire: on va filtrer A pour chacune des ranges

Code :
  1. #
  2.    >>> ranges = []
  3.    >>> for i in xrange(0, MAX, STEP):
  4.    ...     ranges.append([(a, b) for a, b in zip(As, Bs) if i <= a < i + STEP])


À ce stade, on a 20 ranges avec 1 à 10 paires chaque (pour la seed forcée, sinon les runs sont pas stables et c'est chiant).

 

Nous reste plus qu'à récupérer le "b" maximum dans chaque range:

Code :
  1. #
  2.    >>> maximums = []
  3.    >>> for range in ranges:
  4.    ...     maximums.append(max(range, key=operator.itemgetter(1)))
  5.    >>> maximums
  6.    [(1439, 5), (4641, 97), (5062, 84), (9035, 24), (10002, 92), (13979, 96), (16681, 86), (19835, 99), (21086, 46), (24947, 94), (25508, 98), (27555, 96), (31076, 76), (33571, 97), (35807, 85), (39987, 85), (42168, 95), (44649, 56), (45231, 69), (47975, 90)]


et à imprimer le tout en sortie, au lieu de le mettre dans un fichier je vais l'envoyer sur stdout (c'est plus flexible), et je vais utiliser le module CSV de la stdlib, c'est plus clean imo:

Code :
  1. #
  2.    >>> import csv, sys
  3.    >>> writer = csv.writer(sys.stdout, delimiter='\t', quoting=csv.QUOTE_NONE)
  4.    >>> writer.writerows(maximums) # doctest: +NORMALIZE_WHITESPACE
  5.    1439    5
  6.    4641    97
  7.    5062    84
  8.    9035    24
  9.    10002    92
  10.    13979    96
  11.    16681    86
  12.    19835    99
  13.    21086    46
  14.    24947    94
  15.    25508    98
  16.    27555    96
  17.    31076    76
  18.    33571    97
  19.    35807    85
  20.    39987    85
  21.    42168    95
  22.    44649    56
  23.    45231    69
  24.    47975    90


Au début du post, j'ai noté que la méthode indiquée au dessus était simple mais probablement lente (sur un peu plus de 100 objets, je veux dire) (j'ai pas profilé en fait, donc bon). Les raisons sont multiples:

  • zip crée une liste qui est juste itérée, on a donc deux itérations (une pour créer la liste de paires, et une 2e pour la traverser). Utiliser itertools.izip serait probablement plus rapide, et consommerait moins de mémoire (vu qu'il a pas besoin de créer une liste)
  • Plus problématique, on traverse notre liste de (As, Bs) 20 fois (une fois pour chaque range) (puis on re-traverse les range pour avoir les maximales, mais ce sont des listes beaucoup plus courtes donc c'est pas très grave), on peut faire le tout en une seul passe (presque, faut quand même boucler sur la liste de ranges pour savoir où on met chaque valeur):
Code :
  1. #
  2.    >>> import itertools
  3.    >>> COUNT = MAX / STEP
  4.    >>> # Une liste permettant de tenir tous les maximums
  5.    >>> maxs_2 = [(None, None)] * COUNT
  6.    >>> for a, b in itertools.izip(As, Bs):
  7.    ...     # On itère sur toutes les ranges (par leur index)
  8.    ...     for i in xrange(COUNT):
  9.    ...         # Si la paire courante n'est pas dans la range, on passe à la suivante
  10.    ...         if not (i * STEP) <= a < ((i + 1) * STEP):
  11.    ...             continue
  12.    ...         # On regarde quel est le plus grand b entre la paire
  13.    ...         # actuellement stockée et la nouvelle, et on met ça dans notre
  14.    ...         # liste de maximums
  15.    ...         maxs_2[i] = max(maxs_2[i], (a, b), key=operator.itemgetter(1))
  16.    >>> # et on écrit le tout sur STDOUT comme la dernière fois
  17.    >>> writer.writerows(maxs_2) # doctest: +NORMALIZE_WHITESPACE
  18.    1439    5
  19.    4641    97
  20.    5062    84
  21.    9035    24
  22.    10002    92
  23.    13979    96
  24.    16681    86
  25.    19835    99
  26.    21086    46
  27.    24947    94
  28.    25508    98
  29.    27555    96
  30.    31076    76
  31.    33571    97
  32.    35807    85
  33.    39987    85
  34.    42168    95
  35.    44649    56
  36.    45231    69
  37.    47975    90


Notes finales:

  • Je ne connais pas assez numpy pour pouvoir sortir du code dedans, mais il est très très probable qu'il ait tout ce qu'il faut pour faire ce genre de trucs en 2 lignes lisibles, si tu fais beaucoup de calculs numériques dans ce genre je te suggère fortement d'aller l'apprendre, ainsi que scipy.
  • Dans un langage autre que Python, j'aurais probablement utilisé un fold pour la 2e version (ou essayé en tout cas)
  • Le code du commentaire est un gros doctest, si tu le prends (via quote) et que tu balances tout dans un fichier (disons "series.txt" ), tu peux l'exécuter avec python -mdoctest -v series.txt (l'option -v c'est pour qu'il donne le détail de tous les tests qu'il fait)


Message édité par masklinn le 17-05-2012 à 17:59:11

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 23-05-2012 à 09:43:57    

Merci beaucoup pour les conseils, ça m'a fait connaitre quelques fonctions python en plus c'est bien utile! Et surtout une méthode différente de raisonner!

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed