【问题标题】:Looping through, and updating, array values until a condition is met, or until 100 loops have been completed?循环并更新数组值直到满足条件,或者直到完成 100 次循环?
【发布时间】:2026-01-31 04:40:02
【问题描述】:

在 Jupyter Notebook 上使用 Python 3.7。我正在做一个项目,该项目将遍历 2D Numpy 数组(“板”,如果你愿意的话)检查数字 1 的所有实例。当它找到数字 1 时,我需要它检查左边的值,对,在它上面,在它下面。如果它旁边的任何值是 2,那么该元素本身就会变成 2。

在遍历整个数组之后,我需要代码来检查板是否从单个循环的开始发生了变化。如果它没有改变,那么模拟(循环)应该结束。但是,如果它已更改,则应再次运行模拟。但是,模拟循环不应超过 100 圈。

这是通往我的问题单元的设置:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import numpy.random as rand
import time
from IPython.display import display, clear_output

def set_board(height=5,width=10,density=.75):
    city = np.zeros((height,width),dtype='int64')
    for i in range(height):
        for j in range(width):
            if rand.random() <= density:
                city[i,j] = 1
    return city

def VisMap(Map=set_board(),Colors=plt.cm.RdYlGn):
    MapVis = plt.imshow(Map, Colors)
    return MapVis

def onBoard(i, j, array):
    if (i >= 0 and i < array.shape[0]-1 
        and j >= 0 and j < array.shape[1]-1):
        return True
    return False

def getNeighborValues(i, j, board):
    neighborhood_indices = [(i-1,j),(i,j-1),(i+1,j),(i,j+1)]
    neighborhood_values = []
    for index in neighborhood_indices:
        if onBoard(index[0],index[1],board) == True:
            neighborhood_values.append(board[index[0],index[1]])
        pass
    return neighborhood_values

def startRumor(board):
    height, width = board.shape 
    height_quarters = int(height/4)
    width_quarters = int(width/4)
    starting_middle_height_index = height_quarters
    ending_middle_height_index = 3*height_quarters
    starting_middle_width_index = width_quarters
    ending_middle_width_index = 3*width_quarters
    found_starting_point = False 
    if np.all(board[starting_middle_height_index:ending_middle_height_index, starting_middle_width_index:ending_middle_width_index] == 0):
        i = rand.randint(starting_middle_height_index, ending_middle_height_index)
        j = rand.randint(starting_middle_width_index, ending_middle_width_index)
        board[i,j] = 2
        found_starting_point = True
    while not found_starting_point:
        i = rand.randint(starting_middle_height_index, ending_middle_height_index)
        j = rand.randint(starting_middle_width_index, ending_middle_width_index)
        if board[i,j] == 1:
            found_starting_point = True
            board[i, j] = 2

这是我遇到问题的单元格(特别是从第 5 步开始):

#Step 1: Initializing my board
StartingBoard = set_board(100,200,.4)

#Step 2: Visualizing my board
PreRumorVis = VisMap(StartingBoard)

#Step 3: Starting the rumor
startRumor(StartingBoard)

#Step 4: Visualizing the board after the rumor has started
PostRumorVis = VisMap(StartingBoard)

#Step 5: Create a copy of the city, and turn anything 
#with a 2 around it into a 2, and keep doing that for 100 
#loops. Or, if the city at the end of the loop is equal to 
#the one from the beginning of the loop, break it. If there 
#is some change, though, set the new city to now be the 
#updated copy, and loop through again. (In this case, it 
#probably should loop all 100 times).

City_Copy = StartingBoard.copy()
New_City = City_Copy.copy()
iterations = 0
for num in range(100):
    for i in range(City_Copy.shape[0]):
        for j in range(City_Copy.shape[1]):
            if City_Copy[i,j] == 1:
                if 2 in getNeighborValues(i,j, City_Copy):
                    New_City[i,j] = 2
                else:
                    New_City[i,j] = 1
    if np.array_equal(New_City, City_Copy) == True:
        break
    else:
        City_Copy = New_City.copy()
        iterations += 1

print("This rumor has been around for", iterations, "days.")            
New_City

编辑:感谢其中一位评论者,我发现我一开始缺少复制功能。但是,我还有大约 18 天,应该是 100 天(或非常接近)。想知道我是否应该使用 for 循环或 while 循环打开。问题可能出在将变量设置为副本的某个地方……这让我有点困惑。从逻辑上讲,这一切都是有道理的,但是某个地方的螺丝松了。

【问题讨论】:

    标签: python arrays for-loop while-loop agent-based-modeling


    【解决方案1】:

    在 Python 中,赋值语句不复制对象,而是在目标和对象之间创建绑定。当我们使用 = 运算符时,用户认为这会创建一个新对象,其实并没有。它只创建一个共享原始对象引用的新变量。

    示例:-

    >>> a=np.array([[0,1],[0,2]])
    >>> b=a
    >>> np.array_equal(b,a)
    True
    >>> b[0][1]=1
    >>> b
    array([[0, 1],
           [0, 2]])
    >>> a
    array([[0, 1],
           [0, 2]])
    >>> np.array_equal(b,a)
    True
    

    发生这种情况是由于浅拷贝。浅拷贝只限于列表等复合对象。要避免这种情况,请进行深拷贝。

    >>> import copy
    >>> a=np.array([[0,1],[0,2]])
    >>> b=copy.deepcopy(a) 
    >>> np.array_equal(b,a)
    True
    >>>b[0][0]=1
    >>> np.array_equal(b,a)
    False
    

    解决方案:-

    由于您已分配 New_City=City_Copy,因此 New_City 中所做的任何更改都会反映在 City_Copy 中。因此它们都是相等的,并且循环本身第一次中断。所以 循环不是递增。尝试使用 deepcopy 来解决这个问题。

    参考:-

    1. Shallow copy vs Deep copy

    【讨论】:

    • 好点。缺少复制功能。我的教授说暂时远离 deepcopy。那似乎不是问题。现在我正在使用副本,运行它大约需要 18 天。我已经在上面编辑了我的代码,如果你可以看一下。
    • @CornelWestside 实际上,谣言完全取决于“1”的数量,而“1”的数量又取决于给定的密度。如果密度如此之大,谣言传播得很快更多的“1”分散在周围,因此谣言很快就会结束。如果密度较小,谣言就无法传播并且很快就会消失。我已经检查了你的程序,它运行良好。顺便说一句,我检查了 (10,20,.99)。
    • 这绝对是合乎逻辑的......我会问我的教授它是否返回了正确的答案。非常感谢!