在Python中高效地进行二维地图扩散

2 投票
3 回答
2654 浏览
提问于 2025-04-17 06:10

我刚开始学Python,所以在做一个项目。这个项目的一部分是要在地图上进行扩散。我实现这个功能的方法是,遍历每个格子,把当前格子的值设为它周围邻居(北、西、南、东)的值之和乘以0.2。如果我用C语言来做,我会用两个循环遍历一个数组,像这样:arr[i*宽度 + j] = arr[j+1]、arr[j-1]、arr[i+1]、arr[i-1](就是邻居的值),然后对几个不同的数组做同样的操作(因为我会改变地图的不同特性)。但是,我不确定在Python中这样做是否是最快的。有些人建议我使用像numPy这样的库,但我的地图宽度大概不会超过200(最多4-5万个元素),我不确定使用这些库是否值得。我其实也不知道有什么内置函数可以实现我想要的功能。有没有什么建议呢?

补充:这个计算会非常复杂,也就是说每个位置都会有不简单的计算。

3 个回答

0

这个对unutbu代码的修改保持了数组的全局总和不变,同时又让数组中的值发生了变化:

        import numpy as np

        def diffuse(arr, d):
            contrib = (arr * d)
            w = contrib / 8.0
            r = arr - contrib
            N = np.roll(w, shift=-1, axis=0)
            S = np.roll(w, shift=1, axis=0)
            E = np.roll(w, shift=1, axis=1)
            W = np.roll(w, shift=-1, axis=1)
            NW = np.roll(N, shift=-1, axis=1)
            NE = np.roll(N, shift=1, axis=1)
            SW = np.roll(S, shift=-1, axis=1)
            SE = np.roll(S, shift=1, axis=1)
            diffused = r + N + S + E + W + NW + NE + SW + SE
            return diffused
1

使用卷积。

from numpy import *
from scipy.signal import convolve2d

mapArr=array(map)
kernel=array([[0  , 0.2,   0],
              [0.2,   0, 0.2],
              [0  , 0.2,   0]])
diffused=convolve2d(mapArr,kernel,boundary='wrap')

这是在说蚂蚁挑战吗?如果是的话,在蚂蚁的这个背景下,我的实现中,convolve2d的速度比循环快了大约20倍。

3

这件事用NumPy来处理非常简单。函数np.roll可以返回一个数组的副本,并且可以按照指定的方向“滚动”这个数组。

比如,给定一个数组x

x=np.arange(9).reshape(3,3)
# array([[0, 1, 2],
#        [3, 4, 5],
#        [6, 7, 8]])

你可以用下面的方式把列向右滚动:

np.roll(x,shift=1,axis=1)
# array([[2, 0, 1],
#        [5, 3, 4],
#        [8, 6, 7]])

使用np.roll时,边界会像在一个环面上那样连接起来。如果你不想要这种连接的边界,可以在数组的边缘加上一圈零,然后在每次迭代之前把边缘的值重置为零。

import numpy as np

def diffusion(arr):
    while True:
        arr+=0.2*np.roll(arr,shift=1,axis=1) # right
        arr+=0.2*np.roll(arr,shift=-1,axis=1) # left
        arr+=0.2*np.roll(arr,shift=1,axis=0) # down
        arr+=0.2*np.roll(arr,shift=-1,axis=0) # up
        yield arr

N=5
initial=np.random.random((N,N))
for state in diffusion(initial):
    print(state)
    raw_input()

撰写回答