If I have a numpy dtype, how do I automatically convert it to its closest python data type? For example,
numpy.float32 -> "python float" numpy.float64 -> "python float" numpy.uint32 -> "python int" numpy.int16 -> "python int"
I could try to come up with a mapping of all of these cases, but does numpy provide some automatic way of converting its dtypes into the closest possible native python types? This mapping need not be exhaustive, but it should convert the common dtypes that have a close python analog. I think this already happens somewhere in numpy.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Use val.item() to convert most NumPy values to a native Python type:
import numpy as np
# for example, numpy.float32 -> python float
val = np.float32(0)
pyval = val.item()
print(type(pyval)) # <class 'float'>
# and similar...
type(np.float64(0).item()) # <class 'float'>
type(np.uint32(0).item()) # <class 'int'>
type(np.int16(0).item()) # <class 'int'>
type(np.cfloat(0).item()) # <class 'complex'>
type(np.datetime64(0, 'D').item()) # <class 'datetime.date'>
type(np.datetime64('2001-01-01 00:00:00').item()) # <class 'datetime.datetime'>
type(np.timedelta64(0, 'D').item()) # <class 'datetime.timedelta'>
...
(Another method is np.asscalar(val), however it is deprecated since NumPy 1.16).
For the curious, to build a table of conversions of NumPy array scalars for your system:
for name in dir(np):
obj = getattr(np, name)
if hasattr(obj, 'dtype'):
try:
if 'time' in name:
npn = obj(0, 'D')
else:
npn = obj(0)
nat = npn.item()
print('{0} ({1!r}) -> {2}'.format(name, npn.dtype.char, type(nat)))
except:
pass
There are a few NumPy types that have no native Python equivalent on some systems, including: clongdouble, clongfloat, complex192, complex256, float128, longcomplex, longdouble and longfloat. These need to be converted to their nearest NumPy equivalent before using .item().
Method 2
found myself having mixed set of numpy types and standard python. as all numpy types derive from numpy.generic, here’s how you can convert everything to python standard types:
if isinstance(obj, numpy.generic):
return numpy.asscalar(obj)
Method 3
If you want to convert (numpy.array OR numpy scalar OR native type OR numpy.darray) TO native type you can simply do :
converted_value = getattr(value, "tolist", lambda: value)()
tolist will convert your scalar or array to python native type. The default lambda function takes care of the case where value is already native.
Method 4
tolist() is a more general approach to accomplish this. It works in any primitive dtype and also in arrays or matrices.
I doesn’t actually yields a list if called from primitive types:
numpy == 1.15.2
>>> import numpy as np >>> np_float = np.float64(1.23) >>> print(type(np_float), np_float) <class 'numpy.float64'> 1.23 >>> listed_np_float = np_float.tolist() >>> print(type(listed_np_float), listed_np_float) <class 'float'> 1.23 >>> np_array = np.array([[1,2,3.], [4,5,6.]]) >>> print(type(np_array), np_array) <class 'numpy.ndarray'> [[1. 2. 3.] [4. 5. 6.]] >>> listed_np_array = np_array.tolist() >>> print(type(listed_np_array), listed_np_array) <class 'list'> [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
Method 5
How about:
In [51]: dict([(d, type(np.zeros(1,d).tolist()[0])) for d in (np.float32,np.float64,np.uint32, np.int16)])
Out[51]:
{<type 'numpy.int16'>: <type 'int'>,
<type 'numpy.uint32'>: <type 'long'>,
<type 'numpy.float32'>: <type 'float'>,
<type 'numpy.float64'>: <type 'float'>}
Method 6
You can also call the item() method of the object you want to convert:
>>> from numpy import float32, uint32 >>> type(float32(0).item()) <type 'float'> >>> type(uint32(0).item()) <type 'long'>
Method 7
I think you can just write general type convert function like so:
import numpy as np def get_type_convert(np_type): convert_type = type(np.zeros(1,np_type).tolist()[0]) return (np_type, convert_type) print get_type_convert(np.float32) >> (<type 'numpy.float32'>, <type 'float'>) print get_type_convert(np.float64) >> (<type 'numpy.float64'>, <type 'float'>)
This means there is no fixed lists and your code will scale with more types.
Method 8
Sorry to come late to the partly, but I was looking at a problem of converting numpy.float64 to regular Python float only. I saw 3 ways of doing that:
npValue.item()npValue.astype(float)float(npValue)
Here are the relevant timings from IPython:
In [1]: import numpy as np In [2]: aa = np.random.uniform(0, 1, 1000000) In [3]: %timeit map(float, aa) 10 loops, best of 3: 117 ms per loop In [4]: %timeit map(lambda x: x.astype(float), aa) 1 loop, best of 3: 780 ms per loop In [5]: %timeit map(lambda x: x.item(), aa) 1 loop, best of 3: 475 ms per loop
It sounds like float(npValue) seems much faster.
Method 9
numpy holds that information in a mapping exposed as typeDict so you could do something like the below::
>>> import __builtin__ as builtins # if python2 >>> import builtins # if python3
Then::
>>> import numpy as np
>>> {v: k for k, v in np.typeDict.items() if k in dir(builtins)}
{numpy.object_: 'object',
numpy.bool_: 'bool',
numpy.string_: 'str',
numpy.unicode_: 'unicode',
numpy.int64: 'int',
numpy.float64: 'float',
numpy.complex128: 'complex'}
If you want the actual python types rather than their names, you can do ::
>>> {v: getattr(builtins, k) for k, v in np.typeDict.items() if k in vars(builtins)}
{numpy.object_: object,
numpy.bool_: bool,
numpy.string_: str,
numpy.unicode_: unicode,
numpy.int64: int,
numpy.float64: float,
numpy.complex128: complex}
Method 10
My approach is a bit forceful, but seems to play nice for all cases:
def type_np2py(dtype=None, arr=None):
'''Return the closest python type for a given numpy dtype'''
if ((dtype is None and arr is None) or
(dtype is not None and arr is not None)):
raise ValueError(
"Provide either keyword argument `dtype` or `arr`: a numpy dtype or a numpy array.")
if dtype is None:
dtype = arr.dtype
#1) Make a single-entry numpy array of the same dtype
#2) force the array into a python 'object' dtype
#3) the array entry should now be the closest python type
single_entry = np.empty([1], dtype=dtype).astype(object)
return type(single_entry[0])
Usage:
>>> type_np2py(int) <class 'int'> >>> type_np2py(np.int) <class 'int'> >>> type_np2py(str) <class 'str'> >>> type_np2py(arr=np.array(['hello'])) <class 'str'> >>> type_np2py(arr=np.array([1,2,3])) <class 'int'> >>> type_np2py(arr=np.array([1.,2.,3.])) <class 'float'>
Method 11
A side note about array scalars for those who don’t need automatic conversion and know the numpy dtype of the value:
Array scalars differ from Python scalars, but for the most part they can be used interchangeably (the primary exception is for versions of Python older than v2.x, where integer array scalars cannot act as indices for lists and tuples). There are some exceptions, such as when code requires very specific attributes of a scalar or when it checks specifically whether a value is a Python scalar. Generally, problems are easily fixed by explicitly converting array scalars to Python scalars, using the corresponding Python type function (e.g., int, float, complex, str, unicode).
Thus, for most cases conversion might not be needed at all, and the array scalar could be used directly. The effect should be identical to using Python scalar:
>>> np.issubdtype(np.int64, int) True >>> np.int64(0) == 0 True >>> np.issubdtype(np.float64, float) True >>> np.float64(1.1) == 1.1 True
But if, for some reason, the explicit conversion is needed, using the corresponding Python built-in function is the way to go. As shown in the other answer it’s also faster than array scalar item() method.
Method 12
If you have an array list_numpy_numbers of numpy types, do the following:
list_native_numbers = [i.item() for i in list_numpy_numbers]
Method 13
Translate the whole ndarray instead one unit data object:
def trans(data):
"""
translate numpy.int/float into python native data type
"""
result = []
for i in data.index:
# i = data.index[0]
d0 = data.iloc[i].values
d = []
for j in d0:
if 'int' in str(type(j)):
res = j.item() if 'item' in dir(j) else j
elif 'float' in str(type(j)):
res = j.item() if 'item' in dir(j) else j
else:
res = j
d.append(res)
d = tuple(d)
result.append(d)
result = tuple(result)
return result
However, it takes some minutes when handling large dataframes. I am also looking for a more efficient solution.
Hope a better answer.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0