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. #1
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut Benchmark conversion list-->numpy.array
    Bonjour à tous

    Je cherche différent moyen de caster une liste (ou une portion de liste) en un numpy array. J'aurais besoin de plusieurs méthodes différentes selon les besoins/la situation alors je me disais pourquoi pas faire une classe qui dériverait de list et qui ajouterais à ce type les différentes méthodes de cast vers un array que je souhaites proposer.

    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
    import numpy as np
    from time import time
     
    datasize=10000
     
    rd = np.random.RandomState(seed=0)
    data = list( rd.rand(datasize) )
     
     
    #### Option 1 : Une fonction exterieur
    def to_nparray(datalist):
        return np.array(datalist)
     
    #### Option 2 : On creer une classe qui derive de list
    class MyList(list):
        def to_nparray(self):
            return np.array(self)
     
    data2 = MyList(data)   
     
    Niter4access = int(1e7)
    Niter4nparr_cast= int(1e4)
     
    t0 = time()
    for i in range(Niter4access) : b=data[i%datasize]
    t1 = time()
    for i in range(Niter4access) : b=data2[i%datasize]
    t2 = time()
    for i in range(Niter4nparr_cast) : b=to_nparray(data)
    t3 = time()
    for i in range(Niter4nparr_cast) : b=data2.to_nparray()
    t4 = time()
     
    print("======== Exec time ========")
    print("-- Particular acces (%s iter) ---"%Niter4access)
    print("External fct: %s"%(t1-t0))
    print("Class method: %s"%(t2-t1))
    print("-- np.array cast (%s iter) ---"%Niter4nparr_cast)
    print("External fct: %s"%(t3-t2))
    print("Class method: %s"%(t4-t3))
    A ma grande stupeur faire une nouvelle classe est donc bien plus couteux !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 1.5281527042388916
    Class method: 2.4622461795806885
    -- np.array cast (10000 iter) ---
    External fct: 5.599560022354126
    Class method: 6.787678480148315
    Quelqu'un peut-il tester chez lui et me dire s'il a les mêmes différences entre les 2 cas ? Qqn a-t-il une explication de pourquoi y a t il autant de différence sur le temps d'éxécution (+60% en coût sur l'accès particulaire tout de même ce n'est pas rien, et +27% sur la conversion ). Je sais qu'on rajoute une classe, donc c'est plus lourd. Mais à ce point ...

  2. #2
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Bonjour,

    Au début, je pensais que tu étais sur un cas trompeur, car les temps que tu montres pourraient laisser penser que c'est juste l'initialisation de l'objet qui est un temps incompressible, j'ai donc refait ton test mais en multipliant par 10 les ranges, et là, on voit bien une différence qui n'est pas lié uniquement à l'initialisation de l'objet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ======== Exec time ========
    -- Particular acces (100000000 iter) ---
    External fct: 16.96150016784668
    Class method: 27.86549997329712
    -- np.array cast (100000 iter) ---
    External fct: 60.59150004386902
    Class method: 74.43249988555908
    Bon après, je n'ai pas l'explication mais je trouve ça moche...
    Cordialement.

  3. #3
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    La création des arrays est faite avant que je ne déclenche les chrono via time, donc ce temps là n'est pas compté dedans. Et on s'attends en effet à ce qu'à la création il y est un surcoût, mais celui là je suis prêt à le payer. Celui sur l'extraction où l'appel à la méthode, moins ....

    Le fait que tu l'ait lancé (merci d'ailleurs pour ce temps que tu as pris) m'indique déjà que c'est à priori "normal" et pas lié à mon installation (tu as aussi un bon 60% d'augmentation du cout sur l'accès particulaire).

    Si qqn a une explication je la veux bien.

    Du coup, je vais opté pour un ensemble de fonctions externes plutôt qu'une nouvelle classe. Ca sera un peu plus crade car moins sémantique, mais là le prix est trop exhorbitant sur le nombre de fois où j'aurais à le faire. Si qqn a une solution intermédiaire, je suis preneur également.

  4. #4
    Membre confirmé

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Points : 503
    Points
    503
    Billets dans le blog
    1
    Par défaut
    Non, rien j'ai dit une connerie...
    Le temps ronge l'amour comme l'acide.

  5. #5
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Bon, a priori, c'est une raison de recherche dans divers dictionnaire liée aux classe qui ferait ça...

    Une petite explication (en anglais) : https://stackoverflow.com/questions/...s-twice-as-slo
    Cordialement.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Même résultat et pas d'explications.

    Citation Envoyé par disedorgue Voir le message
    Bon, a priori, c'est une raison de recherche dans divers dictionnaire liée aux classe qui ferait ça...
    C'est une hypothèse qui se teste facilement en mettant la méthode appelée dans une variable (çà évite la recherche).
    J'ai testé, il y a un petit mieux mais trop "petit" pour être l'explication.
    Un autre test est d'appeler la fonction en lui passant l'instance en paramètre: même punition.

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

  7. #7
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Ok, tant pis, au moins ça élimine déjà une piste...

    Il n'existe pas un outil qui permet de voir la pile d'exécution du moteur python pour voir la balade qu'il fait quand il s'agit d'une classe par exemple ?
    Cordialement.

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Il n'existe pas un outil qui permet de voir la pile d'exécution du moteur python pour voir la balade qu'il fait quand il s'agit d'une classe par exemple ?
    Je ne sais pas.

    Si on remplace l'appel à np.array par un truc qui balaie la liste, on trouve des résultats semblables (pourvu qu'on mette la méthode dans une variable histoire de bypasser la résolution de noms).

    Si on évite l'héritage via:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MyList:
        def __init__(self, alist):
            self._list = alist
        def to_nparray(self):
            return np.array(self._list)
    J'obtiens aussi des résultats semblables.

    Donc np.array semble bosser plus lorsqu'il ne récupère pas un type "natif", c'est par là qu'est l'indirection.
    En tout cas, pour le problème de "base" çà donne un semblant de solution.

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

  9. #9
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Par contre, ça ne résout pas le 1er cas, l'accès particulaire, ou alors j'ai pas trouvé l'évidence:

    J'ai du rajouter pour la class une method:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        def __getitem__(self, i):
            return self._list[i]
    Pour que le code de départ fonctionne.
    Cordialement.

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Par contre, ça ne résout pas le 1er cas, l'accès particulaire, ou alors j'ai pas trouvé l'évidence:
    Ah ouais, je l'ai zappé celui là car on sait pourquoi (trouver la fonction à appeler dans le tas de __dict__).
    C'est sûr que la forme littérale (liste[i]) est difficile à contourner... Et ajouter des indirections/appels de fonctions n'arrangera pas les choses. Si on zappe l'héritage, le plus simple sera de rendre l'attribut public et d'y accéder directement. Il y a peut être d'autres Pythonneries qui pourrait rendre les choses plus élégantes, mais là, je ne vois pas.

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

  11. #11
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Alors, sur ma petite machine perso (vieux dual core 32 bits) :

    Pour la classe d'origine:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class MyList(list):
        def to_nparray(self):
            return np.array(self)
    Les temps suivants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 6.557446479797363
    Class method: 9.392954111099243
    -- np.array cast (10000 iter) ---
    External fct: 24.018495321273804
    Class method: 29.008670568466187
    Avec la classe suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MyList(list):
        def __init__(self, alist):
            self._list = alist
     
        def __getitem__(self,i):
            return self._list[i]
     
        def to_nparray(self):
            return np.array(self._list)
    Les temps suivants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 6.6995978355407715
    Class method: 12.80150294303894
    -- np.array cast (10000 iter) ---
    External fct: 24.882997512817383
    Class method: 24.995436906814575
    Et pour la classe suivante (qui semble être le meilleur compromis) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MyList(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def to_nparray(self):
            return np.array(self._list)
    Les temps suivants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 6.758497476577759
    Class method: 9.66832685470581
    -- np.array cast (10000 iter) ---
    External fct: 24.691341638565063
    Class method: 24.85800290107727
    Cordialement.

  12. #12
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Si on évite l'héritage via:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MyList:
        def __init__(self, alist):
            self._list = alist
        def to_nparray(self):
            return np.array(self._list)
    J'obtiens aussi des résultats semblables.

    Donc np.array semble bosser plus lorsqu'il ne récupère pas un type "natif", c'est par là qu'est l'indirection.
    En tout cas, pour le problème de "base" çà donne un semblant de solution.

    - W
    La faute à numpy ? Bonne idée mais je viens de faire un test qui écarte cette hypothèse. Si dans mes classes je rajoutes des méthodes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class MyList(list):
        def to_tuple(self):
            return tuple(self)
    On obtient aussi des écarts de temps considérables !

    L'idée de disedorgue qui dérive la classe, mais qui aussi en plus garde une référence vers l'instance de la classe parent (comme l'avait proposé wiztricks, merci pour cette idée) permet d'avoir en effet un temps d'éxécution comparable sur les méthodes to_nparray (et to_tuple aussi au passage). Pour l'accès particulaire par contre, ca reste un mystère !

    Ma classe n'étant là à la base que pour regrouper un ensemble de fonction de cast plus ou moins complexe, l'idée de laisser l'attribut publique perd un peu de son intérêt, puisque dès qu'on utilise une méthode autre qu'un cast on va devoir passer par cet attribut. Pour cette raison je vais adopté la 1ere solution (des méthodes externes), mais ceci dit, pour d'autres la solution suivante serait très nettement acceptable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MyList(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def to_nparray(self):
            return np.array(self._list)
    fournit un temps comparable pour le cast, et seulement un poil plus pour l'accès particulaire sous réserve de l'écrire ainsi :
    plutot que
    L'accès particulaire perd un peu en performance du à l'indirection ( comme mentionné par un internaute dans le lien stackoverflow donné plus haut :
    An official Python performance guide reccomends to avoid dots in performance critical parts of the code: https://wiki.python.org/moin/PythonS...erformanceTips
    ) qui reste tout de même petit bien que non négligeable (exectime +18%) à côté des écarts monstrueux que je pouvais constater au départ (exectime +60%).

    Je poste l'ensemble du code si jamais qqn en a besoin, ou souhaite à nouveau commenter/apporter sa contribution.

    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
    import numpy as np
    from time import time
     
    #### Sujet developpez.net relie à ce code :
    ###  https://www.developpez.net/forums/d1861888/autres-langages/python-zope/calcul-scientifique/benchmark-conversion-list-numpy-array/
     
    datasize=10000
     
    rd = np.random.RandomState(seed=0)
    data = list( rd.rand(datasize) )
     
     
    #### Option 1 : Une fonction exterieur
    def to_nparray(datalist):
        return np.array(datalist)
     
    def to_tuple(datalist):
        return tuple(datalist)
     
    #### Option 2 : On creer une classe qui derive de list
    class MyList(list):
        def to_nparray(self):
            return np.array(self)
     
        def to_tuple(self):
            return tuple(self)
     
    #### Option 3 : On creer une classe qui derive de list + on garde une référence vers l'instance parent     
    class MyList2(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def to_nparray(self):
            return np.array(self._list)
     
        def to_tuple(self):
            return tuple(self._list)
     
    #### Option 4 : On creer une classe qui derive de list et qui surcharge __getitem__
    class MyList3(list):
        def __getitem__(self,idx):
            return list.__getitem__(self,idx)
     
    data1 = MyList(data)
    data2 = MyList2(data) 
    data3 = MyList3(data)    
     
    Niter4access = int(1e7)
    Niter4nparr_cast= int(1e4)
     
    t0 = time()
    for i in range(Niter4access) : b=data[i%datasize]
    t1 = time()
    for i in range(Niter4access) : b=data1[i%datasize]
    t2 = time()
    for i in range(Niter4nparr_cast) : b=to_nparray(data)
    t3 = time()
    for i in range(Niter4nparr_cast) : b=data1.to_nparray()
    t4 = time()
    for i in range(Niter4nparr_cast) : b=to_tuple(data) 
    t5 = time()
    for i in range(Niter4nparr_cast) : b=data1.to_tuple()
    t6 = time()
    for i in range(Niter4access) : b=data3[i%datasize]
    t7 = time()
    for i in range(Niter4access) : b=data2[i%datasize]
    t8 = time()
    for i in range(Niter4nparr_cast) : b=data2.to_tuple()
    t9 = time()
    for i in range(Niter4nparr_cast) : b=data2.to_nparray()
    t10 = time()
    for i in range(Niter4access) : b=data2._list[i%datasize]
    t11 = time()
     
     
    print("======== Exec time ========")
    print("-- Particular acces (%s iter) ---"%Niter4access)
    print("External fct: %s"%(t1-t0))
    print("Class1 method: %s"%(t2-t1))
    print("Class2 method: %s"%(t8-t7))
    print("Overwrite __getitem__: %s"%(t7-t6))
    print("Class2 public attribute : %s"%(t11-t10))
    print("-- np.array cast (%s iter) ---"%Niter4nparr_cast)
    print("External fct: %s"%(t3-t2))
    print("Class1 method: %s"%(t4-t3))
    print("Class2 method: %s"%(t10-t9))
    print("-- tuple cast (%s iter) ---"%Niter4nparr_cast)
    print("External fct: %s"%(t5-t4))
    print("Class1 method: %s"%(t6-t5))
    print("Class2 method: %s"%(t9-t8))
    qui produit :

    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
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 1.5130739212036133
    Class1 method: 2.4333972930908203
    Class2 method: 2.4490203857421875
    Overwrite __getitem__: 4.981260776519775
    Class2 public attribute : 1.793931007385254
    -- np.array cast (10000 iter) ---
    External fct: 5.459544897079468
    Class1 method: 6.6294474601745605
    Class2 method: 5.490988731384277
    -- tuple cast (10000 iter) ---
    External fct: 0.2807767391204834
    Class1 method: 0.4795725345611572
    Class2 method: 0.26518988609313965

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    La faute à numpy ? Bonne idée mais je viens de faire un test qui écarte cette hypothèse. Si dans mes classes je rajoutes des méthodes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class MyList(list):
        def to_tuple(self):
            return tuple(self)
    On obtient aussi des écarts de temps considérables !
    Voilà le test que j'ai chez moi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    **tuple**
    func: 0.052156925201416016
    meth: 0.05215787887573242
    **array**
    func: 1.0822701454162598
    meth: 1.3430578708648682
    et le code:
    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
    from time import time
    import numpy as np
    import gc
    gc.disable()
     
    datasize = 2000
    rd = np.random.RandomState(seed=0)
    data = list( rd.rand(datasize) )
     
    def to_target(alist, target):
        return target(alist)
     
    class A(list):
        def to_target(self, target):
            return target(self)
     
    data2 = A(data.copy())
     
    count = 10000
     
    def test(target):
        t0 = time()
        for _ in range(count): z = to_target(data, target)
     
        t1 = time()
        c = data2.to_target
        for _ in range(count): z = c(target)
     
        t2 = time()
     
        print ('**%s**' % target.__name__)
        print ('func:', t1 - t0)
        print ('meth:', t2 - t1)
     
    test(tuple)
    test(np.array)
    Difficile de conclure autre chose côté numpy. Désolé!
    Et j'aurais bien aimé avoir des différences significatives avec "tuple" : les sources sont beaucoup plus faciles à lire.


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

  14. #14
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    Et bien ça alors !

    Voici ce que j'obtiens moi lorsque j'éxécute ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    **tuple**
    func: 0.0467989444732666
    meth: 0.0935983657836914
    **array**
    func: 1.0919790267944336
    meth: 1.325974464416504
    Donc pour l'array, on est raccord, mais pour le tuple là ... Ca me laisse perplexe tout ça.
    Tu utilises quelle version de Python ?

    Voici mon install, sous Windows 7 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    In [13]: sys.version
    Out[13]: '3.5.4 |Anaconda custom (64-bit)| (default, Nov  8 2017, 14:34:30) [MSC v.1900 64 bit (AMD64)]'

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Donc pour l'array, on est raccord, mais pour le tuple là ... Ca me laisse perplexe tout ça.
    Tu utilises quelle version de Python ?
    3.4, 3.6, ...
    Après avoir rejoué avec ces tests, il y a une certaine variabilité dans le résultat (plusieurs exécution sortent des durées différentes). Je suspecte que la durée est trop petite pour ne pas être sensible aux bruits (d'autres activités systèmes).
    Tout cela est à retravailler.

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

  16. #16
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    Certes il y a de la variabilité un peu sur les temps d'éxcution, mais même en augmentant le nombres d'itérations, je constate tout de même un écart significatif qui ne peut pas juste être du à de la variabilité.

    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
    >>>count = 1000000
     
    >>>test(tuple)
    **tuple**
    func: 4.63319993019104
    meth: 9.687599897384644
     
    >>>test(tuple)
    **tuple**
    func: 4.617599964141846
    meth: 9.656399965286255
     
    >>>test(tuple)
    **tuple**
    func: 4.617599964141846
    meth: 9.674599885940552
    Ca donne quoi de ton côté sur ta machine si tu augmentes le nombre d'itérations ?

  17. #17
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 280
    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 280
    Points : 12 729
    Points
    12 729
    Par défaut
    Selon certain besoin, on pourrait changer par exemple ta classe MyList2 comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyList2(list):
        def __init__(self, alist):
            self._list = np.asarray(alist)
            super().__init__(self._list)
     
        def to_nparray(self):
            return self._list
     
        def __setitem__(self,key,item):
            self._list[key] = item
            super().__setitem__(key,item)
     
        def to_tuple(self):
            return tuple(super().__iter__())
    ce qui donnerait:
    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
    ======== Exec time ========
    -- Particular acces (10000000 iter) ---
    External fct: 1.6983397006988525
    Class1 method: 2.6795356273651123
    Class2 method: 2.7235448360443115
    Overwrite __getitem__: 4.983496427536011
    Class2 public attribute : 2.673534631729126
    -- np.array cast (10000 iter) ---
    External fct: 6.017703533172607
    Class1 method: 7.474494457244873
    Class2 method: 0.0020003318786621094
    -- tuple cast (10000 iter) ---
    External fct: 0.28905773162841797
    Class1 method: 0.5576114654541016
    Class2 method: 0.5656130313873291
    Mais bon, comme je dis, c'est selon le besoin car ici, on crée le array numpy tout en conservant la "list" (on utilise donc plus de mémoire) ...
    D'où le besoin de redéfinir la méthode __setitem__ pour modifier le array quant on modifie la "list".

    Pour ton histoire de tuple, je suis toujours sur les temps qu'il y a ci-dessus, chez moi ça à l'air constant (je suis en 3.6).
    Cordialement.

  18. #18
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    Oui effectivement c'est selon les besoins cette solution. Malheureusement pour moi ce n'est pas envisgeable dans mon cas : les listes sont grosses, et on a besoin souvent d'y faire des append, donc s'il faut faire des np.concatenate sur l'array derrière à chaque append sur la liste, laisse tomber le cout !

    Pour ce qui est du cast vers un tuple tu constates aussi la différence de coût entre la fonction externe, et les méthodes internes à des classes.

    Merci pour votre aide à tous en tout cas et les solutions proposées. Je vais passer le topic en résolu, choisissant l'option 1 dans mon premier post, bien que la question du pourquoi ce surcoût, même dans le cas d'un cast vers un tuple, reste finalement en suspens (surcoût qui ne semble pas être constaté chez tous le monde d'ailleurs...).

  19. #19
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    J'ai compris ce qui me choquait dans ces tests.

    La liste peut être native ou s/classée "tuple" ou "nd.array" vont itérer sur chacun des éléments de cette liste. Python retournera une référence à l'objet qui sera stocké ou recopié suivant le cas.
    Il y a en gros deux étapes: la création du contexte de la boucle qui va faire les accès et l'accès aux éléments.... Et si je prend une grosse liste ou N plus petites, je biaise le résultat dans un sens ou dans l'autre en fonction de la taille de la liste et du nombre d'itérations (des appels à la fonction qui... histoire d'avoir une durée acceptable).
    Donc il faut fixer les choses pour qu'à la fin on ait créé le même nombre d'accès.
    i.e #itération * #elements doit être +/- constant.
    Ce qui donne ce code:
    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
    from time import process_time as time
    import numpy as np
    import gc
     
    def access(alist, target=None):
        for e in alist:
            z = e
     
    def create(alist, target):
        return target(alist)
     
    def create2(alist, target=None):
        return np.fromiter(alist, dtype=int)
     
    class A(list):
        create = create
        access = access
        create2 = create2
     
    power = 7
    samples = 10**power
     
    def test(cname, klass, target=None):
        for x in range(power):
            count = 10**x 
            size = int(samples / count)
            assert size * count == samples
     
            #count = 10 * count
            data = list(range(size))
            a = klass(data)
     
            func = globals().get(cname)
            meth = getattr(a, cname)
     
            gc.disable()
            t0 = time()
            for _ in range(count):
                func(data, target)
            t1 = time()
     
            for _ in range(count):
                 meth(target)
            t2 = time()
            gc.enable()
            print('*** func: %.5f, meth: %.5f' %(t1 - t0, t2 - t1),
              'size: ', size, 'count: ', count)
    Avec test('access', A), on voit que les accès via la fonction ou la méthode prennent à peu près le même temps:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    *** func: 0.15625, meth: 0.17188 size:  10000000 count:  1
    *** func: 0.15625, meth: 0.17188 size:  1000000 count:  10
    *** func: 0.15625, meth: 0.15625 size:  100000 count:  100
    *** func: 0.15625, meth: 0.15625 size:  10000 count:  1000
    *** func: 0.17188, meth: 0.15625 size:  1000 count:  10000
    *** func: 0.18750, meth: 0.17188 size:  100 count:  100000
    *** func: 0.29688, meth: 0.29688 size:  10 count:  1000000
    Avec test('create', A, tuple), çà varie dans les deux sens suivant la valeur du nombre d'itérations et du nombre d’éléments (et çà va généralement plus vite que le code précédent car çà bosse essentiellement dans le code C):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    *** func: 0.40625, meth: 0.25000 size:  10000000 count:  1
    *** func: 0.17188, meth: 0.17188 size:  1000000 count:  10
    *** func: 0.04688, meth: 0.06250 size:  100000 count:  100
    *** func: 0.07812, meth: 0.04688 size:  10000 count:  1000
    *** func: 0.04688, meth: 0.03125 size:  1000 count:  10000
    *** func: 0.04688, meth: 0.06250 size:  100 count:  100000
    *** func: 0.21875, meth: 0.26562 size:  10 count:  1000000
    Avec np.array test('create', A, np.array), j'ai une anomalie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    *** func: 0.54688, meth: 1.09375 size:  10000000 count:  1
    *** func: 0.53125, meth: 1.00000 size:  1000000 count:  10
    *** func: 0.50000, meth: 0.87500 size:  100000 count:  100
    *** func: 0.48438, meth: 0.62500 size:  10000 count:  1000
    *** func: 0.48438, meth: 0.64062 size:  1000 count:  10000
    *** func: 0.53125, meth: 0.96875 size:  100 count:  100000
    *** func: 1.21875, meth: 4.29688 size:  10 count:  1000000
    car le passage par méthode coûte bien plus que dans le cas tuple.
    Le problème est illustré par:
    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
    >>> import numpy as np
    >>> L = [1, 2, 3]
    >>> class A(list):
    ...    def __iter__(self):
    ...        print('__iter__')
    ...        return super().__iter__()
    ...
    >>> np.array(A(L))
    __iter__
    __iter__
    __iter__
    array([1, 2, 3])
    >>> tuple(A(L))
    __iter__
    (1, 2, 3)
    >>>
    i.e. np.array s'assure qu'on ne lui a pas passé un tableau de tableaux... Et çà coûte un bras. test('create2', A) dit à numpy de ne pas s'en embarrasser (via np.fromiter):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    *** func: 0.39062, meth: 0.35938 size:  10000000 count:  1
    *** func: 0.31250, meth: 0.32812 size:  1000000 count:  10
    *** func: 0.21875, meth: 0.21875 size:  100000 count:  100
    *** func: 0.21875, meth: 0.21875 size:  10000 count:  1000
    *** func: 0.25000, meth: 0.23438 size:  1000 count:  10000
    *** func: 0.35938, meth: 0.34375 size:  100 count:  100000
    *** func: 1.15625, meth: 1.17188 size:  10 count:  1000000
    Et d'obtenir des résultats bien meilleurs.

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

  20. #20
    Membre émérite

    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
    Points : 2 328
    Points
    2 328
    Par défaut
    Salut

    Merci beaucoup pour cette réponse très complète et bien détaillée.

    Citation Envoyé par wiztricks Voir le message
    Avec test('create', A, tuple), çà varie dans les deux sens suivant la valeur du nombre d'itérations et du nombre d’éléments (et çà va généralement plus vite que le code précédent car çà bosse essentiellement dans le code C):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    *** func: 0.40625, meth: 0.25000 size:  10000000 count:  1
    *** func: 0.17188, meth: 0.17188 size:  1000000 count:  10
    *** func: 0.04688, meth: 0.06250 size:  100000 count:  100
    *** func: 0.07812, meth: 0.04688 size:  10000 count:  1000
    *** func: 0.04688, meth: 0.03125 size:  1000 count:  10000
    *** func: 0.04688, meth: 0.06250 size:  100 count:  100000
    *** func: 0.21875, meth: 0.26562 size:  10 count:  1000000
    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.

    J'ai donc enquêté et j'ai fais mes tests en relancant ton code, avec power=8 et en y ajoutant dans le print le différentiel en bout de ligne. test('create', A, tuple) donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    *** func: 1.15440, meth: 1.20120 size:  100000000 count:  1 delta: +4.05%
    *** func: 1.17000, meth: 1.20120 size:  10000000 count:  10 delta: +2.67%
    *** func: 1.13880, meth: 1.17000 size:  1000000 count:  100 delta: +2.74%
    *** func: 0.39000, meth: 0.56160 size:  100000 count:  1000 delta: +44.00%
    *** func: 0.31200, meth: 0.51480 size:  10000 count:  10000 delta: +65.00%
    *** func: 0.23400, meth: 0.49920 size:  1000 count:  100000 delta: +113.33%
    *** func: 0.43680, meth: 0.76440 size:  100 count:  1000000 delta: +75.00%
    *** func: 2.12160, meth: 2.77680 size:  10 count:  10000000 delta: +30.88%
    J'ai lancé 10 fois la chose j'obtiens toujours dans le même ordre de grandeur : la fonction est toujours plus performante que la méthode (contrairement à ce que tu as pu constater en faisant 10 fois moins d'itérations avec power = 7). Sur de très gros tableaux ca ne semble pas être énorme (2 à 4%). Mais sur des tableaux de taille inférieure ou égal à 100 000 éléments, là ça déconne. Dans le code que je proposais au tout début, j'avais fixé mon dataset à 10 000. Si je regarde la ligne en question ici pour un dataset de taille 10 000, on y est sur des écarts signifiactifs...


    Par contre, sur l'aspect que numpy fait des vérifications et donc explose son temps d'exe à cause de cela là c'est super bien vu ça.
    Citation Envoyé par wiztricks Voir le message
    Avec np.array test('create', A, np.array), j'ai une anomalie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    *** func: 0.54688, meth: 1.09375 size:  10000000 count:  1
    *** func: 0.53125, meth: 1.00000 size:  1000000 count:  10
    *** func: 0.50000, meth: 0.87500 size:  100000 count:  100
    *** func: 0.48438, meth: 0.62500 size:  10000 count:  1000
    *** func: 0.48438, meth: 0.64062 size:  1000 count:  10000
    *** func: 0.53125, meth: 0.96875 size:  100 count:  100000
    *** func: 1.21875, meth: 4.29688 size:  10 count:  1000000
    car le passage par méthode coûte bien plus que dans le cas tuple.
    Le problème est illustré par:
    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
    >>> import numpy as np
    >>> L = [1, 2, 3]
    >>> class A(list):
    ...    def __iter__(self):
    ...        print('__iter__')
    ...        return super().__iter__()
    ...
    >>> np.array(A(L))
    __iter__
    __iter__
    __iter__
    array([1, 2, 3])
    >>> tuple(A(L))
    __iter__
    (1, 2, 3)
    >>>
    Même odre de grandeur lorsque j'éxécute chez moi. Gros point pour toi wiztricks, j'étais clairement passé à côté de cela. Ca ca montre pourquoi c'est plus gourmand de caster vers un np.array que vers un tuple. Mais ca n'explique pas les écarts constaté juste avant entre fonction et méthode.

    Je poursuit mon enquête et me dit finalement qu'on avait contourner le problème déjà (sans comprendre pourquoi) avec la classe qui gardait une référence
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MyList2(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def to_nparray(self):
            return np.array(self._list)
     
        def to_tuple(self):
            return tuple(self._list)
    à la liste originelle. Et la raison finalement c'est que là en passant par cette référence, on passait donc à notre constructeur numpy directement un type de base. Le code ci dessous l'illustre bien (même si on se limite au cas où les données sont de taille fixée à 10 000)

    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
    import numpy as np
    from time import time
     
    #### Sujet developpez.net relie à ce code :
    ###  https://www.developpez.net/forums/d1861888/autres-langages/python-zope/calcul-scientifique/benchmark-conversion-list-numpy-array/
     
    datasize=10000
     
    rd = np.random.RandomState(seed=0)
    data = list( rd.rand(datasize) )
     
     
    def to_nparray(datalist):
        return np.array(datalist)
     
    def to_tuple(datalist):
        return tuple(datalist)
     
    class MyList(list):
        def __init__(self, alist):
            self._list = alist
            super().__init__(self._list)
     
        def to_nparray1(self):
            return np.array(self._list)
     
        def to_nparray2(self):
            return np.array(self)
     
        def to_nparray3(self):
            return np.fromiter(self, dtype=float)
     
        def to_nparray4(self):
            return np.fromiter(self._list, dtype=float)
     
        def to_tuple1(self):
            return tuple(self._list)
     
        def to_tuple2(self):
            return tuple(self)
     
     
    data1 = MyList(data)
     
    def test_func(fname, data):
        func = globals().get(fname)
        t0 = time()
        for _ in range(Niter): 
            a=func(data)
        t1 = time()
        print('func %20s : %s'%(fname+'('+d.__class__.__name__+')',t1-t0))
     
    def test_meth(mname):
        meth = getattr(data1, mname)
        t0 = time()
        for _ in range(Niter): 
            a=meth()
        t1 = time()
        print('meth %20s : %s'%(mname,t1-t0))
     
     
    Niter = int(2e4)
     
    print('-- *** cast tuple *** --')
    for d in (data, data1):
        test_func('to_tuple',d)
    for i in range(1,3):
        test_meth('to_tuple'+str(i))
     
    print('-- *** cast np_array *** --')
    for d in (data, data1):
        test_func('to_nparray', d)
    for i in range(1,5):
        test_meth('to_nparray'+str(i))
    qui donne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    -- *** cast tuple *** --
    func       to_tuple(list) : 0.5616037845611572
    func     to_tuple(MyList) : 0.9828062057495117
    meth            to_tuple1 : 0.5514054298400879
    meth            to_tuple2 : 0.9828064441680908
    -- *** cast np_array *** --
    func     to_nparray(list) : 10.780669212341309
    func   to_nparray(MyList) : 13.02608346939087
    meth          to_nparray1 : 10.810869216918945
    meth          to_nparray2 : 13.010483503341675
    meth          to_nparray3 : 2.4492156505584717
    meth          to_nparray4 : 2.464815855026245
    Et là effectivement on voit également bien que :
    - la fonction to_tuple(list) et la méthode to_tuple1 produise le même temps : elles s'appuient toutes deux sur le type natif qu'est la liste
    - même temps aussi pour to_tuple(MyList) et la méthode to_tuple2, qui s'appui directement sur un input de type MyList non natif
    - les 2 précédentes remarques sont également constatées dans le cadre d'un cast vers un numpy array
    - les 2 méthodes s'appuyant sur np.fromiter sont comparables indépendamment du type d'entrée

    Conclusion :
    - Méthode et fonction sont donc comparables. C'est le type d'input qui fait donc la différence (selon s'il est natif ou non). Pour garder l'équivalence sur les temps d'exe il faut donc garder une référence à l'instance parent de type natif
    - La méthode np.fromiter permet de s'affranchir de tout cela lorsqu'on cast vers un array puisque considère l'objet passé, quelqu'il soit, comme un itérateur.


    Me reste à vérifier tout ceci sur les méthodes d'accès particulaires. Je ferais un autre poste lundi pour ce point.
    Un super gros merci en tout cas aux contributeurs de ce topic, et à wiztricks tout particulièrement

    Bon weekend

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

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