2010-12-08 6 views
96

Étant donné un tableau NumPy de int32, comment le convertir en float32en place? Donc, fondamentalement, je voudrais faireConversion de type place d'un tableau NumPy

a = a.astype(numpy.float32) 

sans copier le tableau. C'est gros.

La raison pour cela est que j'ai deux algorithmes pour le calcul de a. L'un d'entre eux renvoie un tableau de int32, l'autre renvoie un tableau de float32 (et ceci est inhérent aux deux algorithmes différents). Tous les autres calculs supposent que a est un tableau de float32.

Actuellement, je fais la conversion dans une fonction C appelée via ctypes. Y a-t-il un moyen de faire ça en Python?

+0

avec 'ctypes' est autant "en Python", comme en utilisant' numpy'. :) –

+3

@Karl: Non, parce que je dois coder et compiler la fonction C moi-même. –

+0

Oh, je vois. Je pense que vous êtes probablement SOL sur celui-ci. –

Répondre

80

Vous pouvez faire une vue avec un autre DTYPE, puis copiez en place dans la vue:

import numpy as np 
x = np.arange(10, dtype='int32') 
y = x.view('float32') 
y[:] = x 

print(y) 

donne

array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32) 

Pour montrer la conversion était en place, notez que la copie dex à y modifié x:

print(x) 

impressions

array([   0, 1065353216, 1073741824, 1077936128, 1082130432, 
     1084227584, 1086324736, 1088421888, 1090519040, 1091567616]) 
+19

Note pour ceux (comme moi) qui veulent une conversion entre dtype de différentes tailles d'octets (par exemple 32 à 16 bits): Cette méthode échoue parce que y.size <> x.size. Logique une fois que vous y pensez :-( –

+0

Cette solution fonctionnait-elle pour une ancienne version de Numpy? Quand je fais 'np.arange (10, dtype = np.int32) .view (np.float32) 'sur Numpy 1.8.2 , Je reçois 'array ([0.00000000e + 00, 1.40129846e-45, ... [snip] ... 1.26116862e-44], dtype = float32)'. –

+2

@BasSwinckels: Cela est attendu.La conversion se produit lorsque vous affecter 'y [:] = x'. – unutbu

13

Vous pouvez modifier le type de tableau sans conversion comme ceci:

a.dtype = numpy.float32 

mais vous devez changer tous les entiers à quelque chose qui sera interprété comme le flotteur correspondant. Une façon très lent à faire serait d'utiliser le module struct de python comme ceci:

def toi(i): 
    return struct.unpack('i',struct.pack('f',float(i)))[0] 

... appliqué à chaque membre de votre tableau.

Mais peut-être un moyen plus rapide serait d'utiliser les outils de ctypeslib de numpy (que je ne connais pas bien)

- modifier -

Depuis ctypeslib ne marche pas semble fonctionner, alors je procéder à la conversion avec la méthode numpy.astype typique, mais procéder à des tailles de blocs qui se trouvent dans les limites de votre mémoire:

a[0:10000] = a[0:10000].astype('float32').view('int32') 

... puis changer le DTYPE lorsque vous avez terminé.

Voici une fonction qui accomplit la tâche pour tout dtypes compatible (ne fonctionne que pour dtypes avec des objets de même taille) et gère des réseaux arbitrairement en forme avec l'utilisateur contrôle sur la taille des blocs:

import numpy 

def astype_inplace(a, dtype, blocksize=10000): 
    oldtype = a.dtype 
    newtype = numpy.dtype(dtype) 
    assert oldtype.itemsize is newtype.itemsize 
    for idx in xrange(0, a.size, blocksize): 
     a.flat[idx:idx + blocksize] = \ 
      a.flat[idx:idx + blocksize].astype(newtype).view(oldtype) 
    a.dtype = newtype 

a = numpy.random.randint(100,size=100).reshape((10,10)) 
print a 
astype_inplace(a, 'float32') 
print a 
+1

Merci pour votre réponse. Honnêtement, je ne pense pas que ce soit très utile pour les ** grands ** tableaux - c'est trop lent. Réinterpréter les données du tableau comme un type différent est facile - par exemple en appelant 'a.view (numpy.float32)'. La partie difficile est en train de convertir les données. 'numpy.ctypeslib' aide seulement à réinterpréter les données, pas à les convertir réellement. –

+0

ok. Je n'étais pas sûr de ce que vos limites de mémoire/processeur étaient. Voir ma modification. – Paul

+0

Merci pour la mise à jour. Le faire par blocs est une bonne idée - probablement le meilleur que vous pouvez obtenir avec l'interface NumPy actuelle. Mais dans ce cas, je vais probablement m'en tenir à ma solution ctypes actuelle. –

130

Mise à jour: Cette fonction permet d'éviter que la copie si elle peut, par conséquent, Ce n'est pas la bonne réponse à cette question. La réponse de @ unutbu est la bonne.


a = a.astype(numpy.float32, copy=False) 

numpy astype a un drapeau de copie. Pourquoi ne devrions-nous pas l'utiliser?

+12

Une fois que ce paramètre est pris en charge dans une version NumPy, nous pourrions bien sûr l'utiliser, mais c Actuellement, il est uniquement disponible dans la branche de développement. Et au moment où j'ai posé cette question, ça n'existait pas du tout. –

+2

@SvenMarnach Il est maintenant supporté, au moins dans ma version (1.7.1). – PhilMacKay

+0

Il semble fonctionner parfaitement dans python3.3 avec la dernière version numpy. – CHM

-4

Utilisez ceci:

In [105]: a 
Out[105]: 
array([[15, 30, 88, 31, 33], 
     [53, 38, 54, 47, 56], 
     [67, 2, 74, 10, 16], 
     [86, 33, 15, 51, 32], 
     [32, 47, 76, 15, 81]], dtype=int32) 

In [106]: float32(a) 
Out[106]: 
array([[ 15., 30., 88., 31., 33.], 
     [ 53., 38., 54., 47., 56.], 
     [ 67., 2., 74., 10., 16.], 
     [ 86., 33., 15., 51., 32.], 
     [ 32., 47., 76., 15., 81.]], dtype=float32) 
+4

Etes-vous sûr que ce n'est pas une copie? Pouvez-vous vérifier et expliquer un peu plus? –

-1

a = np.subtract(a, 0., dtype=np.float32)

+1

Bien que cet extrait de code puisse être la solution, [y compris une explication] (// meta.stackexchange.com/questions/114762/explaining-entirely- code-based-answers) contribue vraiment à améliorer la qualité de votre message. Rappelez-vous que vous répondez à la question pour les lecteurs dans le futur, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. – Sebastialonso

+0

Pourquoi cela devrait-il être une conversion ** en place **? 'numpy.subtract' renvoie une copie, n'est-ce pas? Seulement le nom 'a' réutilisé pour un autre morceau de données ... S'il vous plaît expliquer, si je me trompe à ce sujet. – koffein

+0

Merci de l'avoir signalé, il semble que vous ayez raison - une copie est produite. – MIO