Я хочу рассчитать расстояние до каждой другой позиции в целочисленной решетке от ее центра и количество позиций на каждом расстоянии. В настоящее время я использую следующий код для расчета этого:

x = numpy.arange(-10, 11, 1)  
[X, Y] = numpy.meshgrid(x, x)  

R = numpy.sqrt(X**2+Y**2)  
R2 = numpy.ndarray.flatten(R)  
R3 = numpy.unique(R2)  
r = R3[1:] # excludes the 0  
Nr = numpy.zeros(numpy.size(r))  

for i in range(numpy.size(r)):  
    Nr[i] = numpy.count_nonzero(R2 == r[i]

Это говорит мне, что возможные расстояния 1, sqrt2, 2, sqrt5 и т. Д.
Это также говорит мне, что их 4x1, 4xsqrt2, 4x2, 8xsqrt5 и т. Д.

Поскольку это распространенная проблема в физике, мне было интересно, есть ли функция из библиотеки, например, numpy или scipy, которая могла бы легче возвращать эти значения.

1
James Downs 11 Дек 2016 в 23:40

3 ответа

Лучший ответ

Решетка центрирована в (0,0). Так что это симметрично по четырем квадрантам. Таким образом, мы можем использовать это ограничение в наших интересах, поскольку мы можем вычислить эти требуемые уникальные расстояния и счетчики для одного квадранта и умножить эти счетчики на 4 для моделирования для всех четырех квадрантов.

Итак, допустим, мы используем первый квадрант (верхний правый квад). Мы пропустили бы элементы в строке (y = 0), потому что в противном случае умножение на 4 для моделирования всех четырех квадрантов приведет к дублированию результатов. Кроме того, таким образом, нам не придется исключать первый элемент, как это было сделано в исходном посте.

Таким образом, реализация будет -

N = 11 # Lattice size
xa, ya = np.ogrid[0:N,1:N] # x's:0:N, y's:1:N 
unq_dists, count = np.unique(np.sqrt(xa**2 + ya**2), return_counts=1)
count = count*4

Для дальнейшего повышения производительности мы могли бы использовать np.unique для квадратов суммирования, а затем использовать np.sqrt для уникальных. Идея состоит в том, чтобы выполнить медленное вычисление квадратного корня на меньшем уникальном наборе, например так:

unq_dists, count = np.unique(xa**2 + ya**2, return_counts=1)
unq_dists = np.sqrt(unq_dists)
1
Divakar 11 Дек 2016 в 21:33

Ваш код может быть сделан более эффективным несколькими способами. Вы сначала формируете две большие матрицы, а затем возводите квадраты в члены. Лучше было бы сначала выйти на круги своя. Кроме того, формирование сетки сетки только для выполнения внешнего добавления не требуется: существует numpy.add.outer. Наконец, ваш цикл становится ненужным с помощью параметра return_counts=True в numpy.unique. (Что, кстати, сглаживает сам массив, так что вам не нужно.) Таким образом, код сокращен до трех строк .

x = numpy.arange(-10, 11, 1)
R = numpy.sqrt(numpy.add.outer(x**2, x**2))
r, Nr = numpy.unique(R, return_counts=True)

(И если вы хотите исключить расстояние 0, верните r[1:] и Nr[1:])

0
user6655984user6655984 11 Дек 2016 в 21:05

После того, как вы сгладили массив, преобразуйте его в Pandas Series и посчитайте уникальные значения:

distances = pandas.Series(numpy.ndarray.flatten(R))
distances.value_counts()
# 9.219544     16
# 8.062258     16
# 5.000000     12
#10.000000     12
# 7.071068     12
# 2.236068      8
# ....
0
DYZ 11 Дек 2016 в 20:55