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 :

array avec nommage des colonnes


Sujet :

Calcul scientifique Python

  1. #1
    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 array avec nommage des colonnes
    Bonjour à tous

    J'ai besoin d'une structure d'array mais :
    - qui offre aussi la possibilité de nommer les colonnes avec une extraction et une assignation à la manière d'un dictionnaire
    - qui conserve la structure d'array (l'extraction standard, les opéreations arithmétiques que l'on peut faire dessus, etc ...)


    Il y a bien la piste des arrays structurés comme là
    https://docs.scipy.org/doc/numpy-1.1...asics.rec.html
    ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A=np.array([(3.0,2.5)],dtype=[('C1',np.float),('C2',np.float)])
    A['C1']  ### Affiche 3.0
    A[0] ### Affiche (3.0,2.5)   :(
    Sauf que là, je n'ai bien sûr pas le format voulu (comme un array pur):
    A[0] donne (3.0,2.5) et non pas 3.0 comme je le voudrais.
    Pire encore, je ne peux plus faire d'opérations, comme par exemple 0.5*A ...

    J'ai essayé ensuite veinement de créer une classe dérivée de np.ndarray, mais là je m'enfonce dans les abysses de numpy et je n'y comprends pas grand chose... Je me tourne donc vers la communauté pour obtenir un peu d'aide.

    Je résumé donc mon besoin (histoire d'être clair) : disposer d'une classe qui me permette d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    A=MaClasse( [3.0,2.5] , names=["C1","C2"] )
    A[0] ## Affiche 3.0
    A[:1] ## Affiche 3.0
    A["C1"] ## Affiche 3.0
    B=A
    B["C1"]=5.0
    B[1]=7.0  ## B contient donc les valeurs : [5.0, 7.0]
    A+B
    0.5*A
    A*B
    Merci à vous

    Lg_53

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 778
    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 778
    Par défaut
    Salut,

    En écrivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A=np.array([(3.0,2.5)],dtype=[('C1',np.float),('C2',np.float)])
    vous fabriquez un tableau ayant une seule ligne et 2 colonnes nommées C1 et C2.
    Normal que: A['C1'] n'affiche qu'une valeur alors que A[0] affiche la ligne.
    Avec deux lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> A=np.array([(3.0,2.5),(1,2)],dtype=[('C1',np.
    >>>
    >>> A
    array([(3.0, 2.5), (1.0, 2.0)],
          dtype=[('C1', '<f8'), ('C2', '<f8')])
    >>> A['C1']
    array([ 3.,  1.])
    Comme avec ce genre de tableau, seules les colonnes sont d'un type homogène, vous allez pouvoir faire des opérations par colonnes mais pas sur l'ensemble du tableau.

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

  3. #3
    Membre émérite

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 665
    Par défaut
    Salut,

    Peut-être déjà envisagé, mais vu qu'il n'est pas mentionné dans le post, et Pandas? Avec pandas on peut gérer les données sous la forme d'un dictionnaire (récupérer une colonne par une clé par exemple), mais aussi faire des calculs sur les lignes ou les colonnes, et même tout le tableau à la fois.

    J

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 778
    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 778
    Par défaut
    Citation Envoyé par Julien N Voir le message
    Peut-être déjà envisagé, mais vu qu'il n'est pas mentionné dans le post, et Pandas? Avec pandas on peut gérer les données sous la forme d'un dictionnaire (récupérer une colonne par une clé par exemple), mais aussi faire des calculs sur les lignes ou les colonnes, et même tout le tableau à la fois.
    Sûr que pandas est un peu plus souple pour gérer les tableaux de n'importe quoi... mais il y a encore plus de documentations (et d'exemples) à lire que pour numpy...

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

  5. #5
    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
    Salut,

    Merci pour vos réponses rapides.

    @wiztricks: Ah oui, je comprends. Bien dommage alors du coup que je ne puisse faire des opérations que sur les colonnes et pas sur tout le tableau entier. Car c'est juste ce qui manque pour répondre à mon beosin.

    @Julien: Oui panda, j'avais regardé un peu, mais j'en ai pas parlé. Mon souci c'est que grosso modo je vais avoir besoin un grand nombre de fois de caster vers ou depuis un numpy.ndarray (pour que ca puisse communiquer avec scipy.ode). Déjà que les séries pandas, c'est très couteux à manipuler (100 fois plus lent qu'un array selon cette source --> https://penandpants.com/2014/09/05/p...-numpy-arrays/ ), alors si en plus je dois faire des casts réguliers ...

    On a rien sans rien me direz vous. On ne peut pas gagner en fonctionalité sans perdre un peu de performance. Ceci dit je n'ai pas besoin de toute l'artillerie panda. Juste besoin de nommer mes colonnes (dans des array 1D et 2D) et de pouvoir y accéder via ses labels. J'ai aussi exploré plus en détail la piste de créer une classe dérivée de numpy.ndarray. Finalement ca me garderait une structure en numpy.ndarray, donc ca m'évite tous des cast et ca me permet de pas trop entacher les performances. Ca serait un juste milieu.

    Je vous présente ce que j'ai pour l'instant (ca marche bien en 1D, mais j'ai encore des mises au point à faire pour le 2D):

    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
    106
    107
    108
     
    from collections import OrderedDict, Iterable
    import numpy as np
     
    import pdb
    import sys
     
     
    ###Inspire de : https://docs.scipy.org/doc/numpy/user/basics.subclassing.html
    class NamedArray(np.ndarray):
     
        def __new__(cls, input_array, names=None):
            obj = np.asarray(input_array).view(cls)
            obj.colnames = OrderedDict(  (name,i) for i,name in enumerate(names) )
            return obj
     
        def __array_finalize__(self, obj):
            if obj is None: return
            self.colnames = getattr(obj, 'colnames', None )
     
        def __repr__(self):
            s=super().__repr__()
            return s[:-1]+", names="+str(self.names)+")"
     
        def __str__(self):
            return ' '.join(self.names)+'\n'+super().__str__()
     
        def Get(self,colname):
            if self.ndim == 1 :
                return self[ self.colnames[colname] ]
            else:
                return np.array(self[ :, self.colnames[colname] ])
     
        def __getitem__(self,idx):
            if isinstance(idx,str): 
                return self.Get(idx)
            else :          
                if isinstance(idx,slice):
                    return NamedArray( super().__getitem__(idx), self.names[idx] )
                else :
                    return super().__getitem__(idx)
     
        def Set(self,colname,val):
            #### Pour le 1D, a voir pour le 2D
            self[ self.colnames[colname] ] = val
     
        def __setitem__(self,idx,val):
            if isinstance(idx,str): 
                self.Set(idx,val)
            else :
                super().__setitem__(idx,val)
     
        @property
        def names(self):
            return list(self.colnames.keys())
     
     
    arr = np.arange(5)
    obj = NamedArray(arr, names=['c0','c1','c2','c3','c4'])
    print(type(obj))
    print(obj.names)
    print(obj)        ### call __str__
    print(repr(obj))  ### call __repr__
    print(obj[1])     ### call __getitem__
    print(obj['c1'])  ### call __getitem__
    print(0.5*obj)
    print(obj+obj)
    obj[1]=13.0             ### call __setitem__
    obj['c0']=17.0          ### call __setitem__
    obj[3:5]=[21.0,22.0]    ### call __setitem__
    print(obj)
     
    print("---")
     
    v = obj[1:3]
    print(type(v))
    print(v.colnames)
    print(v.names)               
    print(v.Get('c2'))
    print(v['c2'])
     
    print(" ----- Test 2D ---- ")
    obj = NamedArray([arr,arr+10], names=['c0','c1','c2','c3','c4'])
    print(type(obj))
    print(obj.names)
    print(obj)        ### call __str__
    print(repr(obj))  ### call __repr__
    print(obj[1])     ### call __getitem__
    print(obj[:,1])   ### call __getitem__    ### Pb ...
    print(obj['c1'])  ### call __getitem__
    #print(obj[1,'c1']  ### call __getitem__    ### Pas encore possible)
    print(0.5*obj)
    print(obj+obj)
    obj[0,1]=13.0             ### call __setitem__
    print(obj)
    #obj['c0']=17.0          ### call __setitem__
    #obj[3:5]=[21.0,22.0]    ### call __setitem__
    #print(obj)
     
    print("---")
     
    v = obj[1:3]    ### besoin d'avoir un NamedArray1D !
    print(type(v))
    print(v.colnames)
    print(v.names)    
    print(v)           
    print(v.Get('c2'))
    print(v['c2'])
    Si jamais vous voyez d'autres solutions, ou bien une manière d'améliorer la piste que je suis en train d'explorer n'hésitez pas à m'en faire part.


    Lg_53

  6. #6
    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
    Je reviens clore ce post après beaucoup de réflexion.

    La meilleure chose que je puisse faire dans mon cas, c'est finalement de créer une classe qui dérive de la classe numpy.ndarray. Même si ce n'est pas de la toute première évidence d'écrire une sous classe de numpy !


    Voici une bonne piste pour faire ça :

    http://www.python-forum.org/viewtopic.php?f=11&t=11306

    Ce code m'a bien aidé mais je l'ai réduits afin de gagner en performance en le limitant ses fonctionnalités aux usages dont j'ai besoin.

    Sachez tout de même que le simple fait de réécrire le getter (même sans rien mettre dedans):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def __getitem__(self,idx):
        return super().__getitem__(idx)
    coute un facteur 5 en temps d'éxécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    --- Exec Time : Acces test 1.00e+06 simus
    0.12801289558410645   ### without __getitem__ rewrite
    0.6350655364990234     ### with __getitem__ rewrite
    On ne peut donc pas réduire plus que celà la pénalité que l'on prend sur le temps d'éxécution.

    Si ca peut servir à qqn...

    Merci à ceux qui ce sont intéressé à ce sujet.

  7. #7
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 153
    Par défaut
    Ce qui est important c'est votre problématique... et faire avec les outils à votre disposition !

    Modifier la syntaxe d'un module utilisé alors que vous avez moyens de le faire sans, c'est overkill.
    Vous perdez toute nature du module et du temps d'exécution...

    Au final quel est l'objectif de cette question ? Un apprentissage de la POO ou répondre à un problème scientifique ?

  8. #8
    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
    L'objectif ici est de répondre au problème scientifique suivant :

    J'ai un système d'EDO que je veux résoudre assez naturellement avec scipy.ode.integrate.
    Le nombre de variables et de paramètres pouvant être grand, comment puis-je facilité la vie de mon utilisateur en lui fournissant des accès via le nom des variables (à la manière d'un dico) et sans trop entacher sur les performances (le système étant potentiellement grand)?


    Il y a bien l'idée de créer un dictionnaire qui permet de garder en mémoire la correspondance entre le nom de la variable et sa position dans l'array

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    name2idx = { name:i for i,name in enumerate(varnames) }
    mais du coup :
    1) Soit j'englobe ça dans une classe qui aura 2 attributs : un numpy.ndarray et mon dictionnaire des correspondances, avec les getter et les setters qui vont bien. Là je perds scipy car je ne peux plus passer une telle classe à scipy vu qu'elle n'est pas un array !
    2) Soit je laisse le dico des correspondances en retour à l'utilisateur qui devra penser à :
    - faire une indirection par ce dico pour tout accès voulu via le nom de la variable plutot que de sa position
    - mettre en paramètre ce dictionaire des correspondances dans toutes les fonctions où il aura envie d'écrire var['alpha'] plutot que var[0]

    La 1ere option ne me parait donc pas possible, et la seconde n'est pas du tout user friendly !
    Dériver de la classe numpy.ndarray est la seule parade que j'ai trouvé pour donner à un array une allure de dico sans que ce ne soit plus un array. Après si vous en voyez une autre je suis toute ouie.

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 153
    Par défaut
    Waouhhh, ça me semble bien compliqué tout ça...

    Citation Envoyé par lg_53
    Le nombre de variables et de paramètres pouvant être grand
    Je comprend pas, comment ça être grand ? de quel ordre ? quelles variables ?

    Là vous parlez d'une solution que vous avez décidé de mettre en oeuvre, mais êtes vous sûr que se soit la bonne ?

    Citation Envoyé par lg_53
    comment puis-je facilité la vie de mon utilisateur en lui fournissant des accès via le nom des variables (à la manière d'un dico) et sans trop entacher sur les performances (le système étant potentiellement grand)?
    Ça me semble bien abstrait tout ça... difficile de répondre à tout cela ! Quel code et quelle réponse semble complexe pour l'utilisateur ?

  10. #10
    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
    Oui en effet c'est compliqué !


    Voici un MWE de qqch de standard, dans lequel j'ai commenté les lignes que je souhaiterais pouvoir écrire.
    Ca pemettra de clarifier les idées je l'espère.


    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
    import numpy as np
    from scipy.integrate import ode
     
    class SpecialArray() : pass  ### A completer
     
     
    ####  le système EDO de la forme : Y' = F(t,Y,params)
    def F(t, Y, params):
        return np.array( params[0]*Y[0], -params[1]*Y[1] )
     
    #state=SpecialArray( np.array([3.0,2.5]) , names=["P","M"] )
    #params=SpecialArray( np.array([1.0,1.3]) , names=["a","b"] )
    state=np.array([3.0,2.5])
    params=np.array([1.0,1.3])
     
    ##### state (et params) fonctionne comme des arrays 
    #####      (extraction, assignation, opération arithmétique, ...)
    print(state[0])
    print(state[:1])
    B=state
    B[1]=7.0
    print(B)
    print(state+B)
    print(0.5*state)
    print(state*B)
     
    #### state et params sont "acceptés" dans le solveur EDO de scipy
    solveur = ode(F).set_integrator('dopri5')
    solveur.set_initial_value(state)
    solveur.set_f_params(params)
     
    print("=== ODE solving ====")
    Tend = 10
    dt=1.0
    while solveur.successful() and solveur.t < Tend :
         print(solveur.t+dt, solveur.integrate(solveur.t+dt))
     
    ####  Mais je voudrais que
    #### state (et params) disposent de getter/setter comme des dictionnaires
    #print(state["P"]) ## Affiche 3.0
    #state["M"]=5.0
    #print(state)
     
    ## et je pourrais meme réécrire F ainsi si je le voulais, sans en modifier la signature :
    def F2(t, Y, params):
      return np.array( params['a']*Y['P'], -params['b']*Y['M'] )

    Mon EDO me donne l'évolution d'un certain état (vecteur de variables) nommé state (et nommé 'y' en interne dans le solveur scipy). Selon le code de scipy, 'y' doit nécéssairement avoir une forme d'array ou bien de qqch qui s'y apparente puisque la donnée fournie est castée en un numpy array.
    Extrait du code de scipy :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        def set_initial_value(self, y, t=0.0):
            """Set initial conditions y(t) = y."""
            if isscalar(y):
                y = [y]
            n_prev = len(self._y)
            if not n_prev:
                self.set_integrator('')  # find first available integrator
            self._y = asarray(y, self._integrator.scalar)                   ##### <--------------  y est casté en np.ndarray
            self.t = t
            self._integrator.reset(len(self._y), self.jac is not None)
    return self
    Dans mon problème F n'est bien sûr pas aussi simple que ça et contiendra environ 200 variables et au moins autant de paramètres.
    De plus le système Y'=F(t,Y,params) sera résolu entre mille et un million de fois avec des jeux de paramètres différents.
    Vu que la fonction F est complexe elle est construite dynamiquement à partir d'un fichier d'input qui contient le descriptif du système (un SBML simplifié).
    Ce fichier d'input ne contient aucune contrainte sur l'ordre des variables du système. De même pour ses paramètres.
    D'où le fait que je veuille disposer d'un accès via le nom de la variable plutot que par sa position.

    Donc pour l'instant la solution mise en place est celle qui consiste à écrire une classe qui dérive de np.ndarray. Après effectivement je ne prétends pas que ce soit la bonne ou la meilleure, mais à l'heure actuelle c'est la seule que j'ai trouvée qui ne dégrade pas trop les performances !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL-2003] transfert de plusieurs lignes en une seule avec ajout des colonnes
    Par ghatfan99 dans le forum Excel
    Réponses: 0
    Dernier message: 10/08/2011, 20h33
  2. Réponses: 2
    Dernier message: 04/11/2010, 17h42
  3. Réponses: 2
    Dernier message: 21/10/2010, 17h23
  4. Réponses: 2
    Dernier message: 15/06/2009, 18h40
  5. Pb avec déplacement des colonnes dans Access
    Par sabredebois dans le forum IHM
    Réponses: 10
    Dernier message: 01/07/2008, 00h49

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