Множественный массив цифр для обработки больших целых чисел - PullRequest
2 голосов
/ 29 марта 2020

Я обрабатываю действительно большие числа, целые числа, с 10000 цифрами, поэтому я делю каждое число на массив.

Небольшая выборка данных:

#all combinations with length 3 of values in list L
N = 3
L = [[1,9,0]]*N
a = np.array(np.meshgrid(*L)).T.reshape(-1,N)
#it is number so removed first 0 and also last value is always 0
a = a[(a[:, 0] != 0) & (a[:, -1] == 0)]
print (a)
[[1 1 0]
 [1 9 0]
 [1 0 0]
 [9 1 0]
 [9 9 0]
 [9 0 0]]

Тогда мне нужно многократное число на 1,1 скаляр , Для лучшего понимания:

#joined arrays to numbers
b = np.array([int(''.join(x)) for x in a.astype(str)])[:, None]
print (b)
[[110]
 [190]
 [100]
 [910]
 [990]
 [900]]

#multiple by constant
c = b * 1.1
print (c)
[[ 121.]
 [ 209.]
 [ 110.]
 [1001.]
 [1089.]
 [ 990.]]

Но из-за 10000 цифр это решение не возможно, потому что округление. Поэтому мне нужно решение для нескольких в массивах:

Что я пытаюсь: сначала добавьте последний 0 'столбец', а затем сумму:

a1 = np.hstack((a[:, [-1]] , a[:, :-1] ))
print (a1)
[[0 1 1]
 [0 1 9]
 [0 1 0]
 [0 9 1]
 [0 9 9]
 [0 9 0]]

print (a1 + a)
[[ 1  2  1]
 [ 1 10  9]
 [ 1  1  0]
 [ 9 10  1]
 [ 9 18  9]
 [ 9  9  0]]

Но проблема в том, что значение больше похоже на 9 необходимо сдвинуть следующие цифры (например, суммирование старой школы), ожидаемый результат:

c1 = np.array([list(str(x).split('.')[0].zfill(4)) for x in np.ravel(c)]).astype(int)
print (c1)
[[0 1 2 1]
 [0 2 0 9]
 [0 1 1 0]
 [1 0 0 1]
 [1 0 8 9]
 [0 9 9 0]]

Возможно ли какое-нибудь быстрое векторизованное решение для генерации c1 массива из a массива?

РЕДАКТИРОВАТЬ: я пытаюсь использовать другие данные для тестирования и решения с помощью @yatu. Ошибка повышения:

ValueError: невозможно преобразовать плавающий NaN в целое число


from itertools import product,zip_longest

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

#real data
#M = 100000
#N = 500
#loop by chunks by length 5
M = 20
N = 5
v = [0]*M
for i in grouper(product([9, 0], repeat=M), N, v):
    a = np.array(i)
#    print (a)
    #it is number so removed first 0 and also last value is always 0
    a = a[(a[:, 0] != 0) & (a[:, -1] == 0)]
    print (a)
#

    s = np.arange(a.shape[1]-1, -1, -1)
    # concat digits along cols, and multiply
    b = (a * 10**s).sum(1)*1.1
    # highest amount of digits in b
    n_cols = int(np.log10(b.max()))
    # broadcast division to reverse
    c = b[:, None] // 10**np.arange(n_cols, -1, -1)
    # keep only last digit
    c1 = (c%10).astype(int)
    print (c1)

1 Ответ

3 голосов
/ 29 марта 2020

Вот векторизация, работающая от a. Идея состоит в том, чтобы умножить каждый столбец на 10**seq, seq - число до числа столбцов и в порядке убывания. Это будет действовать как объединение цифр вдоль столбцов, как только мы возьмем sum вдоль второй оси. Наконец, мы можем повернуть процесс вспять, применив ту же логику c, но вместо этого разделив ее и передав в результирующую форму после умножения на 1.1, и взяв по модулю 10 результата, чтобы сохранить только последний ди git:

s = np.arange(a.shape[1]-1, -1, -1, dtype=np.float64)
# concat digits along cols, and multiply
b = (a * 10**s).sum(1)*1.1
# highest amount of digits in b
n_cols = int(np.log10(b.max()))
# broadcast division to reverse
c = b[:, None] // 10**np.arange(n_cols, -1, -1, dtype=np.float64)
# keep only last digit
c1 = (c%10).astype(int)

print(c1)

array([[0, 1, 2, 1],
       [0, 2, 0, 9],
       [0, 1, 1, 0],
       [1, 0, 0, 1],
       [1, 0, 8, 9],
       [0, 9, 9, 0]])

Обновление -

Приведенный выше подход работает для целых чисел, не превышающих поддерживаемых для int64, а именно:

np.iinfo(np.int64).max
# 9223372036854775807

Однако в таких случаях можно сделать, чтобы сохранить значения массивов как python int, а не numpy dtype. Таким образом, мы могли бы определить np.arange как объект dtype, и вышеприведенное должно работать для общего примера:

s = np.arange(a.shape[1]-1, -1, -1, dtype=object)
# concat digits along cols, and multiply
b = (a * 10**s).sum(1)*1.1
# highest amount of digits in b
n_cols = int(np.log10(b.max()))
# broadcast division to reverse
c = b[:, None] // 10**np.arange(n_cols, -1, -1, dtype=object)
# keep only last digit
c1 = (c%10).astype(int)
...