问题
I am trying to make a code that converts integers in array to a given base and padding them to make them from the same size. The following code which I manipulated from a code on stackoverflow by Alex Martelli, doesn't work when I apply numpy.vectorize
on it, although it works for single arrays:
def int2base(x, base,size):
ret=np.zeros(size)
if x==0: return ret
digits = []
while x:
digits.append(x % base)
x /= base
digits.reverse()
ret[size-len(digits):]=digits[:]
return ret
vec_int2base=np.vectorize(int2base)
vec_int2base(np.asarray([2,1,5]),base=3,size=3)
Which terminates with the following error:
...
1640 if ufunc.nout == 1:
1641 _res = array(outputs,
-> 1642 copy=False, subok=True, dtype=otypes[0])
1643 else:
1644 _res = tuple([array(_x, copy=False, subok=True, dtype=_t)
ValueError: setting an array element with a sequence.
Is there any better way to write it for vectors case, and what am I missing here.
回答1:
Here's a version that is vectorized:
import numpy as np
def int2base(x, base, size=None, order='decreasing'):
x = np.asarray(x)
if size is None:
size = int(np.ceil(np.log(np.max(x))/np.log(base)))
if order == "decreasing":
powers = base ** np.arange(size - 1, -1, -1)
else:
powers = base ** np.arange(size)
digits = (x.reshape(x.shape + (1,)) // powers) % base
return digits
If x
has shape shp
, the result has shape shp + (size,)
.
If size
is not given, the size is based on the largest value in x
. order
determines the order of the digits; use order="decreasing"
(the default) to convert, say, 123 to [1, 2, 3]. Use order="increasing"
to get [3, 2, 1]. (The latter might be more natural, as the index of the digit in the result matches the power of the base for that digit.)
Examples:
In [97]: int2base([255, 987654321], 10)
Out[97]:
array([[0, 0, 0, 0, 0, 0, 2, 5, 5],
[9, 8, 7, 6, 5, 4, 3, 2, 1]])
In [98]: int2base([255, 987654321], 10, size=12)
Out[98]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 5],
[0, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1]])
In [99]: int2base([255, 987654321], 10, order="increasing")
Out[99]:
array([[5, 5, 2, 0, 0, 0, 0, 0, 0],
[1, 2, 3, 4, 5, 6, 7, 8, 9]])
In [100]: int2base([255, 987654321], 16)
Out[100]:
array([[ 0, 0, 0, 0, 0, 0, 15, 15],
[ 3, 10, 13, 14, 6, 8, 11, 1]])
回答2:
I use the "fromBase10" function (below) a fair amount while I am programming in assembly. Note that it doesn't pad the output, but numpy.vectorize
does work with it. Just don't forget to pad.
## Execute this to convert a base 10 into any arbitrary base
def fromBase10(number, base):
if not number:
return '0'
sign = 1 if number > 0 else -1
alphanum = string.digits + string.ascii_lowercase
nums = alphanum[:base]
res = ''
number *= sign
while number:
number, mod = divmod(number, base)
res += nums[mod]
return ('' if sign == 1 else '-') + res[::-1]
Note that I copied the basic routine from someone else on Stack Exchange, but I no longer remember where. I just don't want to claim credit where it isn't mine :)
回答3:
Thank you Warren for this vectorized implementation.
I made another vectorized implementation based on yours that is more efficient.
def base_representation(x, base, size=None):
x = np.asarray(x)
if size is None:
size = int(np.floor(np.log(np.max(x))/np.log(base)))+1
arrays = []
for _ in range(size):
x, reminder = np.divmod(x, base)
arrays.append(reminder)
return np.stack(arrays, axis=-1)
Note that a bug on size has been corrected : the formula should be size=floor(log(x)/log(base))+1.
Best regards.
来源:https://stackoverflow.com/questions/20225613/base-conversion-for-an-array-of-integers