Le meilleur moyen de créer un tableau NumPy à partir d'un dictionnaire?

StackOverflow https://stackoverflow.com/questions/601477

  •  03-07-2019
  •  | 
  •  

Question

Je commence tout juste avec NumPy, il me manque donc peut-être certains concepts de base ...

Quel est le meilleur moyen de créer un tableau NumPy à partir d'un dictionnaire dont les valeurs sont des listes?

Quelque chose comme ça:

d = { 1: [10,20,30] , 2: [50,60], 3: [100,200,300,400,500] }

Devrait devenir quelque chose comme:

data = [
  [10,20,30,?,?],
  [50,60,?,?,?],
  [100,200,300,400,500]
]

Je vais faire des statistiques de base sur chaque ligne, par exemple:

deviations = numpy.std(data, axis=1)

Questions:

  • Quel est le moyen le plus efficace de créer numpy.array à partir du dictionnaire? Le dictionnaire est grand; quelques millions de clés, chacune contenant environ 20 éléments.

  • Le nombre de valeurs pour chaque "ligne" est différent. Si je comprends bien, numpy souhaite une taille uniforme, que dois-je indiquer dans les éléments manquants pour rendre std () heureux?

Mise à jour: une chose que j'ai oublié de mentionner - bien que les techniques python soient raisonnables (par exemple, la mise en boucle de quelques millions d’éléments est rapide), elle est limitée à un seul processeur. Les opérations Numpy s’adaptent bien au matériel et touchent tous les processeurs, de sorte qu’ils sont attractifs.

Était-ce utile?

La solution

Il n'est pas nécessaire de créer des tableaux numpy pour appeler numpy.std (). Vous pouvez appeler numpy.std () en boucle sur toutes les valeurs de votre dictionnaire. La liste sera convertie en un tableau numpy à la volée pour calculer la variation standard.

L’inconvénient de cette méthode est que la boucle principale sera en python et non en C. Mais je suppose que cela devrait être assez rapide: vous calculerez toujours std à la vitesse C et vous économiserez beaucoup de mémoire ne sera pas obligé de stocker 0 valeurs où vous avez des tableaux de taille variable.

  • Si vous souhaitez optimiser cela davantage, vous pouvez stocker vos valeurs dans une liste de tableaux numpy, de sorte que vous fassiez la liste python - > Numpy tableau conversion qu'une seule fois.
  • si vous trouvez que cela est encore trop lent, essayez d’utiliser psycho pour optimiser la boucle python.
  • si cela est encore trop lent, essayez d’utiliser Cython avec le module numpy. Ce Tutoriel réclame des améliorations de vitesse impressionnantes pour le traitement des images. Ou simplement programmer la totalité de la fonction std en Cython (voir this pour obtenir des points de repère et des exemples avec fonction sum)
  • Une alternative à Cython serait d'utiliser SWIG avec numpy.i .
  • si vous souhaitez utiliser uniquement numpy et tout calculer au niveau C, essayez de regrouper tous les enregistrements de même taille dans des tableaux différents et appelez numpy.std () sur chacun d’eux. Cela devrait ressembler à l'exemple suivant.

exemple avec complexité O (N):

import numpy
list_size_1 = []
list_size_2 = []
for row in data.itervalues():
    if len(row) == 1:
      list_size_1.append(row)
    elif len(row) == 2:
      list_size_2.append(row)
list_size_1 = numpy.array(list_size_1)
list_size_2 = numpy.array(list_size_2)
std_1 = numpy.std(list_size_1, axis = 1)
std_2 = numpy.std(list_size_2, axis = 1)

Autres conseils

Bien qu'il y ait déjà quelques idées assez raisonnables ici, je pense que la suite mérite d'être mentionnée.

Remplir les données manquantes avec une valeur par défaut gâcherait les caractéristiques statistiques (std, etc.). Manifestement, c’est pour cette raison que Mapad a proposé l’astuce consistant à regrouper des enregistrements de même taille. Le problème (en supposant qu’il n’existe pas de données a priori sur la longueur des enregistrements) est qu’il implique encore plus de calculs que la solution simple:

  1. au moins O (N * logN) appels 'len' et comparaisons pour le tri avec un algorithme efficace
  2. O (N) vérifie le deuxième chemin dans la liste pour obtenir les groupes (leurs index de début et de fin sur l'axe "vertical")

Utiliser Psyco est une bonne idée (il est étonnamment facile à utiliser, assurez-vous de l'essayer).

Il semble que la méthode optimale consiste à appliquer la stratégie décrite par Mapad à la puce 1, mais avec une modification: ne pas générer la liste complète, mais effectuer une itération dans le dictionnaire en convertissant chaque ligne en numpy.array et en effectuant les calculs requis. . Comme ceci:

for row in data.itervalues():
    np_row = numpy.array(row)    
    this_row_std = numpy.std(np_row)
    # compute any other statistic descriptors needed and then save to some list

Dans tous les cas, quelques millions de boucles en python ne prendront pas aussi longtemps que prévu. En outre, cela ne ressemble pas à un calcul de routine, alors qui se soucie de savoir si cela prend plus de secondes / minutes s’il est exécuté de temps en temps ou même juste une fois.

Une variante généralisée de ce qui a été suggéré par Mapad:

from numpy import array, mean, std

def get_statistical_descriptors(a):
    if ax = len(shape(a))-1
    functions = [mean, std]
    return f(a, axis = ax) for f in functions


def process_long_list_stats(data):
    import numpy

    groups = {}

    for key, row in data.iteritems():
        size = len(row)
        try:
            groups[size].append(key)
        except KeyError:
            groups[size] = ([key])

    results = []

    for gr_keys in groups.itervalues():             
        gr_rows = numpy.array([data[k] for k in gr_keys])       
        stats = get_statistical_descriptors(gr_rows)                
        results.extend( zip(gr_keys, zip(*stats)) )

    return dict(results)

dictionnaire numpy

Vous pouvez utiliser un tableau structuré pour conserver la possibilité d'adresser un objet numpy à l'aide d'une clé, comme un dictionnaire.

import numpy as np


dd = {'a':1,'b':2,'c':3}
dtype = eval('[' + ','.join(["('%s', float)" % key for key in dd.keys()]) + ']')
values = [tuple(dd.values())]
numpy_dict = np.array(values, dtype=dtype)

numpy_dict['c']

va maintenant sortir

array([ 3.])
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top