Jak skutecznie przekształcić 32-bitową liczbę całkowitą w tablicę czterech 8-bitowych liczb całkowitych w Pythonie?
Obecnie mam następujący kod, który jest super wolny:
def convert(int32_val):
bin = np.binary_repr(int32_val, width = 32)
int8_arr = [int(bin[0:8],2), int(bin[8:16],2),
int(bin[16:24],2), int(bin[24:32],2)]
return int8_arr
Na przykład:
print convert(1)
>>> [0, 0, 0, 1]
print convert(-1)
>>> [255, 255, 255, 255]
print convert(-1306918380)
>>> [178, 26, 2, 20]
Muszę osiągnąć to samo zachowanie na niepodpisanych 32-bitowych liczb całkowitych.
Dodatkowo. Czy można go wekorować do dużej liczby liczb całkowitych 32-bitowych?
4 odpowiedzi
Używanie dtype
, jak udokumentowane w: http://docs.scipy.org/doc/numpy/reference /generowany/numpy.dtype.html.
Subdivide int16 into 2 int8‘s, called x and y. 0 and 1 are the offsets in bytes:
np.dtype((np.int16, {'x':(np.int8,0), 'y':(np.int8,1)}))
dtype(('<i2', [('x', '|i1'), ('y', '|i1')]))
Lub dostosowany do twojego przypadku:
In [30]: x=np.arange(12,dtype=np.int32)*1000
In [39]: dt=np.dtype((np.int32, {'f0':(np.uint8,0),'f1':(np.uint8,1),'f2':(np.uint8,2), 'f3':(np.uint8,3)}))
In [40]: x1=x.view(dtype=dt)
In [41]: x1['f0']
Out[41]: array([ 0, 232, 208, 184, 160, 136, 112, 88, 64, 40, 16, 248], dtype=uint8)
In [42]: x1['f1']
Out[42]: array([ 0, 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 42], dtype=uint8)
Porównać
In [38]: x%256
Out[38]: array([ 0, 232, 208, 184, 160, 136, 112, 88, 64, 40, 16, 248])
Więcej dokumentacji na http://docs.scipy.org/doc/numpy/ Użytkownik / podstawy.Rec.html
2) Argument Tuple: Jedyną odpowiednią obudową krotki, która dotyczy struktur rekordowych, jest wtedy, gdy struktura jest odwzorowana do istniejącego typu danych. Odbywa się to przez parowanie w krotce, istniejący typ danych z dopasowaną definicją DTPE (przy użyciu opisanych tutaj dowolnych wariantów). Jako przykład (przy użyciu definicji za pomocą listy, więc zobacz 3) Więcej informacji:
x = NP.zeros (3, DTYPE = ("I4", [("R", "U1"), ("G", "U1"), ("B", "U1"), ("A" : "U1 ')]))
Array ([0, 0, 0])
x ['R'] # array ([0, 0, 0], DTYPE = UINT8)
W tym przypadku wytworzono tablicę, która wygląda i działa jak prosta tablica INT32, ale ma również definicje dla pola, które używają tylko jednego bajtu INT32 (trochę jak fortran ewormalne).
Jednym ze sposobów uzyskania tablicy 2D 4 bajtów jest:
In [46]: np.array([x1['f0'],x1['f1'],x1['f2'],x1['f3']])
Out[46]:
array([[ 0, 232, 208, 184, 160, 136, 112, 88, 64, 40, 16, 248],
[ 0, 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 42],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
Ten sam pomysł, ale bardziej kompaktowy:
In [50]: dt1=np.dtype(('i4', [('bytes','u1',4)]))
In [53]: x2=x.view(dtype=dt1)
In [54]: x2.dtype
Out[54]: dtype([('bytes', 'u1', (4,))])
In [55]: x2['bytes']
Out[55]:
array([[ 0, 0, 0, 0],
[232, 3, 0, 0],
[208, 7, 0, 0],
[184, 11, 0, 0],
[160, 15, 0, 0],
[136, 19, 0, 0],
[112, 23, 0, 0],
[ 88, 27, 0, 0],
[ 64, 31, 0, 0],
[ 40, 35, 0, 0],
[ 16, 39, 0, 0],
[248, 42, 0, 0]], dtype=uint8)
In [56]: x2
Out[56]:
array([ 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000,
9000, 10000, 11000])
W Python 3.2 i wyższy, istnieje nowy metodę int
to_bytes
, który można również użyć:
>>> convert = lambda n : [int(i) for i in n.to_bytes(4, byteorder='big', signed=True)]
>>>
>>> convert(1)
[0, 0, 0, 1]
>>>
>>> convert(-1)
[255, 255, 255, 255]
>>>
>>> convert(-1306918380)
[178, 26, 2, 20]
>>>
Wystarczy korzystać z Wydziału Wbudowanego Pythona i Modulus zapewnia 6x Speedup w moich testach.
def convert(i):
i = i % 4294967296
n4 = i % 256
i = i / 256
n3 = i % 256
i = i / 256
n2 = i % 256
n1 = i / 256
return (n1,n2,n3,n4)
Możesz użyć operacji bitowych:
def int32_to_int8(n):
mask = (1 << 8) - 1
return [(n >> k) & mask for k in range(0, 32, 8)]
>>> int32_to_int8(32768)
[0, 128, 0, 0]
Lub alternatywnie możesz użyć {x0}} pakiet w Pythonie:
>>> import struct
>>> int32 = struct.pack("I", 32768)
>>> struct.unpack("B" * 4, int32)
(0, 128, 0, 0)
Jedna fajna rzecz, jaką możesz wykorzystać o pakiecie struct
, jest to, że możesz wykonać to int32
do int8
bardzo wydajne:
import numpy.random
# Generate some random int32 numbers
x = numpy.random.randint(0, (1 << 31) - 1, 1000)
# Then you can convert all of them to int8 with just one command
x_int8 = struct.unpack('B' * (4*len(x)), buffer(x))
# To verify that the results are valid:
x[0]
Out[29]: 1219620060
int32_to_int8(x[0])
Out[30]: [220, 236, 177, 72]
x_int8[:4]
Out[31]: (220, 236, 177, 72)
# And it's FAST!
%timeit struct.unpack('B' * (4*len(x)), buffer(x))
10000 loops, best of 3: 32 µs per loop
%timeit [int32_to_int8(i) for i in x]
100 loops, best of 3: 6.01 ms per loop
Aktualizacja: porównaj struct.unpack
za pomocą ndarray.view
:
import numpy as np
# this is fast because it only creates the view, without involving any creation
# of objects in Python
%timeit x.view(np.int8)
1000000 loops, best of 3: 570 ns per loop
Jeśli miałbyś wykonać jakieś rzeczywiste obliczeniowe:
uint8_type = "B" * len(x) * 4
%timeit sum(struct.unpack(uint8_type, buffer(x)))
10000 loops, best of 3: 52.6 µs per loop
# slow because in order to call sum(), implicitly the view object is converted to
# list.
%timeit sum(x.view(np.int8))
1000 loops, best of 3: 768 µs per loop
# use the numpy.sum() function - without creating Python objects
%timeit np.sum(x.view(np.int8))
100000 loops, best of 3: 8.55 µs per loop # <- FAST!
Weź wiadomość do domu: Użyj ndarray.view()
!
Podobne pytania
Nowe pytania
python
Python to wielozadaniowy, wielozadaniowy język programowania dynamicznie typowany. Został zaprojektowany tak, aby był szybki do nauczenia się, zrozumienia i użycia oraz wymuszania czystej i jednolitej składni. Należy pamiętać, że Python 2 oficjalnie nie jest obsługiwany od 01-01-2020. Mimo to, w przypadku pytań Pythona specyficznych dla wersji, dodaj znacznik [python-2.7] lub [python-3.x]. Korzystając z wariantu Pythona (np. Jython, PyPy) lub biblioteki (np. Pandas i NumPy), należy umieścić go w tagach.