Если введен массив numd 2d, такой как
100 100 100 100 100
100 0 0 0 100
100 0 0 0 100
100 0 0 0 100
100 100 100 100 100
такой выход должен быть получен
100 100 100 100 100
100 50 25 50 100
100 25 0 25 100
100 50 25 50 100
100 100 100 100 100
где каждое число, кроме границы, становится средним из его смежных чисел.
Мой текущий код работает, но мне нужно использовать его без циклов и векторизовать его с помощью numpy.
Мой текущий код:
import numpy as np
def evolve_heat_slow(u):
u2 = np.copy(u)
x=u2.shape[0]
y=u2.shape[1]
for i in range(1,x-1):
for s in range(1,y-1):
u2[i,s]=(u[i-1,s]+u[i+1,s]+u[i,s+1]+u[i,s-1])/4
return u2
Не лучше, чем другие методы, но вы также можете использовать np.roll
в каждом направлении, чтобы сделать то же самое:
def evolve_heat_slow(u):
u2 = u.copy()
u2[1:-1, 1:-1] = ((np.roll(u2,1,0) + np.roll(u2,-1,0)
+ np.roll(u2,1,1) + np.roll(u2,-1,1))/4)[1:-1, 1:-1]
return u2
теперь с u2 = evolve_heat_slow(u)
вы получаете
u2 =
array([[100, 100, 100, 100, 100],
[100, 50, 25, 50, 100],
[100, 25, 0, 25, 100],
[100, 50, 25, 50, 100],
[100, 100, 100, 100, 100]])
Это в значительной степени определение двумерной свертки. scipy
вы покрыли. Я копирую a
чтобы сохранить границы; свертка в valid
режиме сделает меньший массив (без границ), который затем вставляю внутри подготовленного "кадра".
import numpy as np
from scipy.signal import convolve2d
a = np.array([[100, 100, 100, 100, 100], [100, 0, 0, 0, 100], [100, 0, 0, 0, 100], [100, 0, 0, 0, 100], [100, 100, 100, 100, 100]])
b = np.array([[0, 0.25, 0], [0.25, 0, 0.25], [0, 0.25, 0]])
r = np.copy(a)
r[1:-1, 1:-1] = convolve2d(a, b, mode='valid')
r
# => array([[100, 100, 100, 100, 100],
# [100, 50, 25, 50, 100],
# [100, 25, 0, 25, 100],
# [100, 50, 25, 50, 100],
# [100, 100, 100, 100, 100]])
b
делает это. Свертывание с b
говорит: «Для каждого элемента умножьте элемент непосредственно выше на 0,25, элемент прямо влево на 0,25, элемент прямо вправо на 0,25, элемент непосредственно ниже на 0,25, а затем сложите их». Что в основном совпадает с вашим (u[i-1,s]+u[i+1,s]+u[i,s+1]+u[i,s-1])/4
. Это не «ввод значения» - b
эквивалент вашего усреднения формулы. Думайте об этом как о коде, а не как о данных.
Хотя Amadan scipy ответ имеет наибольший смысл для этого случая, здесь другой подход делает это "вручную":
import numpy as np
# Create your array
data = np.ones((5,5)) * 100
data[1:-1,1:-1] = 0
def evolve_heat_slow(m, should_copy=True):
if should_copy: m = m.copy()
components = (
m[:-2, 1:-1], # N
m[2:, 1:-1], # S
m[1:-1, 2:], # E
m[1:-1, :-2], # W
)
m[1:-1, 1:-1] = np.mean(np.stack(components), axis=0)
return m
for _ in range(2):
data = evolve_heat_slow(data)
print(data)
Здесь мы определяем компоненты, сначала беря центральное 3x3 "окно" и сдвигая его на 1 в каждом направлении. Затем мы складываем сдвинутые окна, принимаем среднее значение и заменяем центральное окно этими значениями.
После 1-й итерации:
[[ 100. 100. 100. 100. 100.] [ 100. 50. 25. 50. 100.] [ 100. 25. 0. 25. 100.] [ 100. 50. 25. 50. 100.] [ 100. 100. 100. 100. 100.]]
После 2 итераций:
[[ 100. 100. 100. 100. 100. ] [ 100. 62.5 50. 62.5 100. ] [ 100. 50. 25. 50. 100. ] [ 100. 62.5 50. 62.5 100. ] [ 100. 100. 100. 100. 100. ]]