问题
I have a structured numpy array.
The numpy structure matches the type google.protobuf.Timestamp
.
I need to extract the seconds
int64
and the nanos
int32
from each element of said structure and assign it to the real Timestamp
structure.
Below I list a script that does just that in a convenient way for anyone to test (numpy
and protobuf
Python modules need to be installed).
How do I get rid/circumvent the TypeError
listed at the end and have the values out of the numpy structure in the Timestamp
variable?
import numpy as np
from google.protobuf import timestamp_pb2
# numpy structure that mimics google.protobuf.Timestamp
Timestamp_t = np.dtype([('seconds', np.int64), ('nanos', np.int32)])
# populate numpy array with above structure
x_values_size = 3
x_values = np.empty((x_values_size,), dtype=Timestamp_t)
x_values['seconds'] = np.linspace(0, 100, num=x_values_size, dtype=np.int64)
x_values['nanos'] = np.linspace(0, 10, num=x_values_size, dtype=np.int32)
# copy data from numpy structured array to a descriptor-created Timestamp
for elem in np.nditer(x_values) :
# destination protobuf structure (actually, part of some sequence)
# try 1: this will actually change the type of 'ts'
ts1 = timestamp_pb2.Timestamp()
print(type(ts1)) # Timestamp as expected
ts1 = elem
print(ts1) # now a numpy.ndarray
print(type(ts1))
print(ts1.dtype)
# try 2: assign member by member
ts2 = timestamp_pb2.Timestamp()
# fails with:
# TypeError: array(0, dtype=int64) has type <class 'numpy.ndarray'>, but expected one of: (<class 'int'>,)
ts2.seconds = elem['seconds']
ts2.nanos = elem['nanos']
print("-----")
Disclaimer: hardcore newbie when it comes to python and numpy arrays.
回答1:
So
In [112]: x_values
Out[112]:
array([( 0, 0), ( 50, 5), (100, 10)],
dtype=[('seconds', '<i8'), ('nanos', '<i4')])
I don't usually recommend using nditer
unless you need special behavior. Simple iteration on the array (rows if 2d) is usually all you need. But to better understand what is happening, lets compare the iteration methods:
In [114]: for elem in np.nditer(x_values):
...: print(elem, elem.dtype)
...: print(type(elem))
(0, 0) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.ndarray'>
(50, 5) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.ndarray'>
(100, 10) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.ndarray'>
In [115]: for elem in x_values:
...: print(elem, elem.dtype)
...: print(type(elem))
(0, 0) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.void'>
(50, 5) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.void'>
(100, 10) [('seconds', '<i8'), ('nanos', '<i4')]
<class 'numpy.void'>
Same except the type
is different, np.ndarray
v. np.void
. It's easier to modify the nditer
variable.
Do the same but looking at one field:
In [119]: for elem in np.nditer(x_values):
...: print(elem['seconds'], type(elem['seconds']))
0 <class 'numpy.ndarray'>
50 <class 'numpy.ndarray'>
100 <class 'numpy.ndarray'>
In [120]: for elem in x_values:
...: print(elem['seconds'], type(elem['seconds']))
0 <class 'numpy.int64'>
50 <class 'numpy.int64'>
100 <class 'numpy.int64'>
I don't have the protobuf
code, but I suspect
ts2.seconds = elem['seconds']
will work better with the 2nd iteration, the one that produces np.int64
values. Or add elem['seconds'].item()
.
来源:https://stackoverflow.com/questions/42996696/extract-python-native-values-from-numpy-structured-array