Этот numpy алгоритм, работающий с целыми числами, иногда возвращает число с плавающей точкой, почему? - PullRequest
3 голосов
/ 23 апреля 2020

Это часть алгоритма для генерации концентрических c колец точек на гексагональной решетке, которые я переписываю.

Я думал, что это целочисленная математика, но я обнаружил, что что в некоторых случаях массивы неожиданно создаются как float!

В приведенной ниже последовательности p0 - это float64 для n=1, но int64 для n>1, и я просто не могу понять, почему это происходит.

I ' m работает numpy версия 1.17.3, установка Anaconda Python 3.7.3 на MacOS

import numpy as np
n_max = 3
for n in range(1, n_max+1):
    seq = np.arange(n, -n-1, -1, dtype=int)
    p0  = np.hstack((seq, (n-1)*[-n], seq[::-1], (n-1)*[n]))
    print('n: ', n)
    print('seq: ', seq)
    print('p0: ', p0.dtype, p0)
    print('')

возвращает

n:  1
seq:  [ 1  0 -1]
p0:  float64 [ 1.  0. -1. -1.  0.  1.]

n:  2
seq:  [ 2  1  0 -1 -2]
p0:  int64 [ 2  1  0 -1 -2 -2 -2 -1  0  1  2  2]

n:  3
seq:  [ 3  2  1  0 -1 -2 -3]
p0:  int64 [ 3  2  1  0 -1 -2 -3 -3 -3 -3 -2 -1  0  1  2  3  3  3]

Это ожидаемое поведение?

обновление 1: хорошо np.hstack(([1, 0, -1], 1*[7])) возвращает int64, но np.hstack(([1, 0, -1], 0*[7])) возвращает float64, так что это 0*[n] в кортеже, на котором работает np.hstack это вызывает повышение до float64.

обновление 2: Только что спросили в Code Review: Есть ли лучший, более чистый или иным образом "менее хитрый" способ получить эти гексагональные массивы точек, расположенных в этой спирали?

Ответы [ 2 ]

2 голосов
/ 23 апреля 2020

То, что вызывает приведение всего массива к np.float64, это пустой список, полученный, когда n=0 с (n-1)*[n] и (n-1)*[-n]:

print((n-1)*[n])
# []

np.hstack создает массив из каждый из его входных массивов должен быть сцеплен. Для каждого массива есть вызов np.atleast_1d, который по умолчанию приводит пустые массивы к np.float64 dtype:

np.atleast_1d([])
# array([], dtype=float64)
1 голос
/ 23 апреля 2020

Причина этого в том, что NumPy создает ndarrays из всех входов перед их объединением.

[0]*n оценивается как [], который является пустым списком и, следовательно, не имеет числового типа c поэтому при приведении к массиву он становится пустым массивом с типом данных по умолчанию , который должен использовать число с плавающей запятой .

Этого можно избежать, применив входные данные к ndarrays самостоятельно и указав тип данных как int, например, так:

import numpy as np
n_max = 3
for n in range(1, n_max+1):
    seq = np.arange(n, -n-1, -1, dtype=int)
    p0  = np.hstack((seq, np.array((n-1)*[-n], dtype=np.int32), seq[::-1], np.array((n-1)*[-n], dtype=np.int32)))
    print('n: ', n)
    print('seq: ', seq)
    print('p0: ', p0.dtype, p0)
    print('')

Я не могу точно сказать, является ли это ожидаемым поведением или нет, но это действительно имеет некоторый смысл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...