2016-04-08 7 views
2

Ich möchte ein NumPy (Version 1.11.0) Array von float64 zu int64 konvertieren. Ich möchte, dass diese Operation mit ganzen Zahlen durchgeführt werden kann, aber nicht mit ganzen Zahlen.Convert float64 zu int64 mit "sicher"

war mein Verständnis, dass ich casting=safe verwenden konnte, obwohl klar mein Verständnis falsch war ...

Ich hoffe, dass die folgenden funktionieren würde:

np.array([1.0]).astype(int, casting='safe') 

Und dass dies fehlschlagen:

np.array([1.1]).astype(int, casting='safe') 

jedoch beide mit diesem Fehler fehlschlagen:

--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-51-7261ddf00794> in <module>() 
    1 import numpy as np 
    2 print(np.__version__) 
----> 3 np.array([1.0]).astype(int, casting='safe') 

TypeError: Cannot cast array from dtype('float64') to dtype('int64') according to the rule 'safe' 

Ich vermute, ich habe ein grundlegendes Missverständnis, was sicheres Casting bedeutet, also ist das vielleicht nicht der beste Weg, dies zu erreichen, gibt es einen besseren Weg für das erste Beispiel, aber das zweite zu scheitern?

+2

Ich glaube, "sicher" ist für Casts, in denen keine Informationen verloren gehen. Es ist keine Operation, die sich um den Wert kümmert, sondern nur der Typ. Mit anderen Worten ist 'float' ->' int' keine sichere Transformation für die gesamte Domäne von 'float'. Die Rückseite sollte jedoch sicher sein. – ebolyen

Antwort

2

Ich kenne keine Möglichkeit, dies direkt in numpy zu tun. Der schnellste Weg, den ich finden konnte einen Schwimmer dtype Array von ganzen Zahlen in ein int dtype Array zu konvertieren ist:

import numpy as np 

def float_to_int(array): 
    int_array = array.astype(int, casting='unsafe', copy=True) 
    if not np.equal(array, int_array).all(): 
     raise TypeError("Cannot safely convert float array to int dtype. " 
         "Array must only contain whole numbers.") 
    return int_array 

Prüfung auf Korrektheit:

In [3]: whole_numbers = np.arange(1000000, dtype=float) 

In [4]: fractional = np.arange(0, 100000, 0.1, dtype=float) 

In [5]: float_to_int(whole_numbers) 
Out[5]: array([  0,  1,  2, ..., 999997, 999998, 999999]) 

In [6]: float_to_int(fractional) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-6-0a7807a592b7> in <module>() 
----> 1 float_to_int(fractional) 

<ipython-input-2-953668ae0922> in float_to_int(array) 
     2   int_array = array.astype(int, casting='unsafe', copy=True) 
     3   if not np.equal(array, int_array).all(): 
----> 4     raise TypeError("Cannot safely convert float array to int dtype. " 
     5         "Array must only contain whole numbers.") 
     6   return int_array 

TypeError: Cannot safely convert float array to int dtype. Array must only contain whole numbers. 

Basierend auf https://stackoverflow.com/a/35042794/3776794 und https://stackoverflow.com/a/7236784/3776794 ich eine Implementierung versucht, mit np.modf aber dies ist langsamer als die Lösung oben:

def float_to_int_mod(array): 
    mod_array, int_array = np.modf(array) 
    if not np.equal(mod_array, 0).all(): 
     raise TypeError("Cannot safely convert float array to int dtype. " 
         "Array must only contain whole numbers.") 
    return int_array.astype(int, casting='unsafe', copy=True) 

Runtime Vergleich:

In [8]: %timeit float_to_int(whole_numbers) 
100 loops, best of 3: 2.75 ms per loop 

In [9]: %timeit float_to_int_mod(whole_numbers) 
100 loops, best of 3: 8.74 ms per loop 

Dies ist mit Python 3 und numpy 1.11.0 getestet.

1

Sie haben es fast geschafft:

In [7]: a = np.array([1.1, 2.2, 3.3]) 

In [8]: a.astype(int) == a 
Out[8]: array([False, False, False], dtype=bool) 

In [9]: if (a.astype(int) != a).any(): 
    ...:  raise ValueError("Conversion failed") 
    ...: 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-9-3628e8ae2ce8> in <module>() 
     1 if (a.astype(int) != a).any(): 
----> 2  raise ValueError("Conversion failed") 
     3 

ValueError: Conversion failed 

In [10]: b = np.array([1.0, 2.0, 3.0]) 

In [11]: b.astype(int) == b 
Out[11]: array([ True, True, True], dtype=bool) 

"Safe" vs "unsicher" Gießen bezieht sich nur auf dtypes, keine Werte. Also, ja, eine Umwandlung von float64 nach int64 ist "unsicher", weil es mindestens eine Gleitkommazahl gibt, die nicht verlustfrei in eine ganze Zahl umgewandelt werden kann.