IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Calcul scientifique Python Discussion :

Benchmark conversion list-->numpy.array


Sujet :

Calcul scientifique Python

  1. #21
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 430
    Par défaut
    Je sors un peu du sujet, mais il ne te serait pas possible de rester en array numpy au lieu de passer de l'un à l'autre ?

    Sinon, l'inverse ne serait pas moins coûteux: de array numpy vers une liste (bien sur, si tu peux voir ton problème dans ce sens là) ?

  2. #22
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Citation Envoyé par lg_53 Voir le message
    Je veux bien qu'on s'arrange pour faire des comparaisons de telles sortes que #itération * #elements doit être +/- constant, mais il faut quand même que le temps d'éxécution à la sortie soit suffisamment significatif pour ne pas être trop sensible à des phénomènes extérieurs. Car dire que tantot la méthode est plus rapide, tantot c'est la fonction ca me parait un peu suspect.
    Ca dépend ce qu'on cherche.

    Pour moi, pourvu qu'on aide un peu Python, l'appel à la méthode n'est pas moins rapide que l'appel à la fonction (c'est ce que raconte le premier test). Par contre, il y a des différences entre type natif et s/classe. Essentiellement parce que vérifier que la méthode n'est pas dans le dict de la classe utilisateur avant de récupérer l'adresse d'une fonction via l'offset d'un struct C coûte (et çà, pas de magie pour l'optimiser autre que l'accès direct au type natif...).

    Et donc c'est sûr que plein d'itérations vs une liste à un élément va exploser les compteurs.
    note: c'est d'ailleurs pour çà que je ne teste même pas côté "méthodes d'accès particulaires", on se paie l'overhead de la mécanique pour ramener une seule référence.

    Mon propos était juste de montrer que np.array avait un (sur)coût démesuré comparé à tuple et que ce coût dépendait de la taille de la liste. Suite à quoi, çà motive d'aller voir dans la documentation pour voir s'il n'y a pas mieux et y trouver np.fromiter.
    note: pour voir çà dans les tests, il suffit de regarder les lignes où on a de grandes listes et peu d'itérations. Avec tuple la s/classe est semblable au type natif alors qu'avec np.array, on est déjà dans les choux.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #23
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Suite de la saga : benchmark sur l'accès particulaire.

    Le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    import numpy as np
    from time import time
     
    class MyList(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def get1(self, i):
            return self[i]
     
        def get2(self, i):
            return self._list[i]
     
    def test_getitem(data):
        cname = data.__class__.__name__
        N = len(data)
        meth = data.__getitem__
     
        t0 = time()
        for i in range(Niter): 
            a=meth(i%N)
        t1 = time()
        print('%20s : %s'%(cname+'.meth',t1-t0))
     
        t0 = time()
        for i in range(Niter): 
            a=data.__getitem__(i%N)
        t1 = time()
        print('%20s : %s'%(cname+'.__getitem__',t1-t0))
     
        t0 = time()
        for i in range(Niter): 
            a=data[i%N]
        t1 = time()
        print('%20s : %s'%(cname+'[]',t1-t0))
     
     
    def test_meth(mname):
        meth = getattr(data_mylist, mname)
        N = len(data_mylist)
        t0 = time()
        for i in range(Niter): 
            a=meth(i%N)
        t1 = time()
        print('%20s : %s'%(data_mylist.__class__.__name__+'.'+mname,t1-t0))
     
     
    Niter_times_datasize_power = 10
     
    for i in range(1,Niter_times_datasize_power+1):
        datasize=10**i
        Niter = 10**(Niter_times_datasize_power-i)
     
        rd = np.random.RandomState(seed=0)
        data_list = list( rd.rand(datasize) )
        data_tuple = tuple( data_list )
        data_array = np.fromiter(data_list)
        data_mylist = MyList(data_list)
     
        print('----- datasize : %d   Niter : %d ----'%(datasize, Niter))
        test_getitem(data_array)
        test_getitem(data_tuple)
        test_getitem(data_list)
        test_getitem(data_mylist)
        test_meth('get1')
        test_meth('get2')
    donne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    ----- datasize : 10   Niter : 1000000000 ----
            ndarray.meth : 143.34151816368103
     ndarray.__getitem__ : 185.50509357452393
               ndarray[] : 106.11187410354614
              tuple.meth : 88.44966983795166
       tuple.__getitem__ : 130.1745092868805
                 tuple[] : 51.49375867843628
               list.meth : 67.41389679908752
        list.__getitem__ : 93.03752303123474
                  list[] : 51.750850200653076
             MyList.meth : 67.34592080116272
      MyList.__getitem__ : 114.10770392417908
                MyList[] : 141.90324783325195
             MyList.get1 : 195.3817093372345
             MyList.get2 : 134.57937955856323
    ----- datasize : 100   Niter : 100000000 ----
            ndarray.meth : 14.473280668258667
     ndarray.__getitem__ : 18.68649458885193
               ndarray[] : 10.70017385482788
              tuple.meth : 8.858410835266113
       tuple.__getitem__ : 13.042917490005493
                 tuple[] : 5.4585113525390625
               list.meth : 6.749993085861206
        list.__getitem__ : 9.307555675506592
                  list[] : 5.1195068359375
             MyList.meth : 6.754076242446899
      MyList.__getitem__ : 11.410252094268799
                MyList[] : 14.864243030548096
             MyList.get1 : 20.506871700286865
             MyList.get2 : 13.664382457733154
    ----- datasize : 1000   Niter : 10000000 ----
            ndarray.meth : 1.4823944568634033
     ndarray.__getitem__ : 1.9026758670806885
               ndarray[] : 1.11826753616333
              tuple.meth : 0.9546623229980469
       tuple.__getitem__ : 1.3584046363830566
                 tuple[] : 0.583106517791748
               list.meth : 0.7552444934844971
        list.__getitem__ : 1.000119924545288
                  list[] : 0.5671353340148926
             MyList.meth : 0.7554869651794434
      MyList.__getitem__ : 1.206751823425293
                MyList[] : 1.5009753704071045
             MyList.get1 : 2.0428097248077393
             MyList.get2 : 1.4099791049957275
    ----- datasize : 10000   Niter : 1000000 ----
            ndarray.meth : 0.15135693550109863
     ndarray.__getitem__ : 0.2037186622619629
               ndarray[] : 0.11478161811828613
              tuple.meth : 0.09796690940856934
       tuple.__getitem__ : 0.13777518272399902
                 tuple[] : 0.06052851676940918
               list.meth : 0.07859516143798828
        list.__getitem__ : 0.10262942314147949
                  list[] : 0.059446096420288086
             MyList.meth : 0.07865047454833984
      MyList.__getitem__ : 0.12306332588195801
                MyList[] : 0.15300321578979492
             MyList.get1 : 0.20720958709716797
             MyList.get2 : 0.1430516242980957
    ----- datasize : 100000   Niter : 100000 ----
            ndarray.meth : 0.015029430389404297
     ndarray.__getitem__ : 0.019211292266845703
               ndarray[] : 0.01141667366027832
              tuple.meth : 0.009816646575927734
       tuple.__getitem__ : 0.013797760009765625
                 tuple[] : 0.0061130523681640625
               list.meth : 0.007891416549682617
        list.__getitem__ : 0.010290145874023438
                  list[] : 0.005977630615234375
             MyList.meth : 0.007889032363891602
      MyList.__getitem__ : 0.012327194213867188
                MyList[] : 0.01532435417175293
             MyList.get1 : 0.02076435089111328
             MyList.get2 : 0.01433253288269043
    ----- datasize : 1000000   Niter : 10000 ----
            ndarray.meth : 0.0015451908111572266
     ndarray.__getitem__ : 0.002026081085205078
               ndarray[] : 0.001146078109741211
              tuple.meth : 0.0010075569152832031
       tuple.__getitem__ : 0.0013790130615234375
                 tuple[] : 0.0006091594696044922
               list.meth : 0.0007991790771484375
        list.__getitem__ : 0.0010249614715576172
                  list[] : 0.0005877017974853516
             MyList.meth : 0.0007872581481933594
      MyList.__getitem__ : 0.0012302398681640625
                MyList[] : 0.0015330314636230469
             MyList.get1 : 0.0020728111267089844
             MyList.get2 : 0.0014333724975585938
    ----- datasize : 10000000   Niter : 1000 ----
            ndarray.meth : 0.00016045570373535156
     ndarray.__getitem__ : 0.0001933574676513672
               ndarray[] : 0.00011038780212402344
              tuple.meth : 9.679794311523438e-05
       tuple.__getitem__ : 0.00013375282287597656
                 tuple[] : 5.602836608886719e-05
               list.meth : 7.367134094238281e-05
        list.__getitem__ : 9.822845458984375e-05
                  list[] : 5.507469177246094e-05
             MyList.meth : 7.510185241699219e-05
      MyList.__getitem__ : 0.00011873245239257812
                MyList[] : 0.0001533031463623047
             MyList.get1 : 0.000202178955078125
             MyList.get2 : 0.00013899803161621094
    NB: les .meth, c'est __getitem__ mais avec la méthode stocké avant pour éviter la recherche dans le dico.

    - Pour les types natifs (tuple et liste), écrire data[] est plus rapide que de factoriser la méthode __getitem__ pour l'appeler ensuite. Faire des appels simple à __getitem__ (sans factoriser la méthode au préalable) coute relativement chère : Comme la fait précédemment remarqué wiztricks, la recherche de la méthode dans le dictionnaire de la classe coûte chère : ca multiplie par 2 ici le temps d'exe !

    - Liste semble un peu plus rapide que tuple (je me serais attendu à l'inverse vu que tuple est de taille fixé, j'aurais pensé que ce serait plus optimisé...)

    - Pour le type numpy, écrire data[] est aussi ce qu'il y a de plus rapide. Quelquesoit le cas de figure c'est environ 2 fois plus lent que sur un tuple.

    - Pour une sous-classe de liste, contrairement aux autres, le plus rapide est l'appel à __getitem__ (que l'on factorise). Cette méthode est équivalente en temps sur une instance de liste, ou bien sur une instance d'une sous classe de liste.

    Si on dérive la classe liste, l'accès particulaire :
    - oblige à factoriser la méthode __getitem__ avant son appel pour être optimal
    - coûte environ 30% de plus qu'un classique data_list[]

    Ca fait cher la sous classe. Je vais rester du coup sur des méthodes extérieures to_nparray pour ne pas non plus avoir à payer aussi le surcoût d'une sous-classe de côté là.

  4. #24
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Je sors un peu du sujet, mais il ne te serait pas possible de rester en array numpy au lieu de passer de l'un à l'autre ?

    Sinon, l'inverse ne serait pas moins coûteux: de array numpy vers une liste (bien sur, si tu peux voir ton problème dans ce sens là) ?
    Dans mon cas ca serait l'inverse i.e. de rester en liste sans passer par des arrays numpy. Mais bon ce sont des grosses listes, et après je dois les sortir dans des fichiers. Je dois donc benchmarké ca aussi : écrire une liste dans un fichier VS conversion liste-->numpy et faire écrire à numpy dans le fichier. J'avais lu que numpy était assez optimiser pour ça. Je vais donc vérifier ça, et voir si ca vaut encore le coût même s'il faut se payer un cast avant...
    Ca fera peut-être l'objet d'un nouveau topic.

    Merci à vous tous

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. [Python 2.X] Extraire données numpy array vers une liste ?
    Par Ben20 dans le forum Calcul scientifique
    Réponses: 4
    Dernier message: 05/03/2015, 11h30
  2. créer une liste de numpy.array
    Par jean-pat dans le forum Calcul scientifique
    Réponses: 4
    Dernier message: 11/03/2011, 21h13
  3. Conversion variable texte en array
    Par t-too dans le forum MATLAB
    Réponses: 1
    Dernier message: 11/07/2007, 09h07
  4. liste chainée ou array
    Par arno. dans le forum C
    Réponses: 6
    Dernier message: 20/08/2006, 20h28
  5. Conversion List -> String
    Par Bayard dans le forum Général Python
    Réponses: 1
    Dernier message: 27/11/2005, 21h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo