簡體   English   中英

在二維 numpy 陣列中獲取鄰居的有效方法

[英]Efficient way of getting the neighbors in 2d numpy array

我想將 3x3 網格中的元素與隨機鄰居交換。 但當然有些元素有 2 個鄰居,有些 3 和 1 個元素有 4 個鄰居。 當我想選擇一個隨機鄰居時,我必須知道每個元素有多少個鄰居。

如果其他查詢,我很確定我可以做很多事情,但這對於這個簡單的問題來說太難看了。 但我沒有不同的想法如何更優雅地做到這一點。

將 3x3 網格嵌入到 5x5 網格中。 在邊界中,有一些永遠不會出現在 3x3 網格中的值,比如 -1。

-1 -1 -1 -1 -1 
-1          -1
-1 Your Grid-1
-1          -1
-1 -1 -1 -1 -1

現在,每個內部網格單元都有 4 個鄰居。 對於這些單元格,請進行拒絕采樣。 那就是不斷地從附近循環一個樣本,直到你抽取一個不是 -1 的樣本。

這里有兩種可能的解決方案。

在這兩種情況下,都假定單元格的 position 是網格中 0 索引坐標(行、列)的元組。

解決方案 1:剪裁

不需要循環,並且有 1/n 的概率可以在 n 個可能的鄰居中找到任何鄰居。

import random
import itertools
import numpy as np
# All the possible moves are combination of 2 numbers among 3 (-1, 0 and 1)... 
all_moves = list(itertools.product([-1,0,1], repeat=2))
#... except (0,0) which is keeping the current position.
all_moves.remove((0,0))    

def random_neighbour(current_pos): 
    # Adding them to your current position gives you all virtual neighbours
    choices =  np.array(current_pos) + np.array(all_moves)
    # ... but we must remove the impossible positions
    choices = choices[((choices>=0)&(choices<=2)).all(axis=1)]
    # Now we can choose randomly among the remaining possibilities:
    return random.choice(choices)

解決方案 2:字典

這也確保我們獲得相同的概率來獲得任何鄰居到一個單元格。 在啟動腳本時,我們可以初始化一個字典,為每個單元格(鍵)提供所有鄰居(值)。

import random
neighbours_dict = {
(p // 3, p % 3): [(p // 3 + x_inc-1, p % 3 + y_inc - 1) 
             for x_inc in range(3) if 1 <= p // 3 + x_inc <= 3
             for y_inc in range(3) if 1 <= p % 3 + y_inc <= 3 and not y_inc == x_inc == 1] 
for p in range(9)}

那么我們可以簡單的給它當前position的索引。 請注意,位置必須是元組,因為列表不可散列且不能構成索引。 因此,我們將進行強制轉換以確保我們不會收到 TypeError。

random.choice(neighbours_dict[tuple(current_pos)])

初始化字典的更好方法

當然,我們也可以手動初始化字典以滿足我們的特定需求,像這樣:

neighbours_dict = {(0, 0): [(0, 1), (1, 0), (1, 1)],
 (1, 0): [(0, 0), (0, 1), (1, 1), (2, 0), (2, 1)],
 (2, 0): [(1, 0), (1, 1), (2, 1)],
 (0, 1): [(0, 0), (0, 2), (1, 0), (1, 1), (1, 2)],
 (1, 1): [(0, 0), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1), (2, 2)],
 (2, 1): [(1, 0), (1, 1), (1, 2), (2, 0), (2, 2)],
 (0, 2): [(0, 1), (1, 1), (1, 2)],
 (1, 2): [(0, 1), (0, 2), (1, 1), (2, 1), (2, 2)],
 (2, 2): [(1, 1), (1, 2), (2, 1)]}

或者我們可以泛化字典理解,使其兼容任何網格形狀和大小:

grid_width, grid_height = 3, 3
neighbours_dict = {
    (p // grid_width, p % grid_width):
        [(p // grid_width + y_inc - 1, p % grid_width + x_inc - 1) 
            for y_inc in range(3) if 1 <= p // grid_width + y_inc <= grid_height
            for x_inc in range(3) if 1 <= p % grid_width + x_inc <= grid_width 
                    and not y_inc == x_inc == 1] 
    for p in range(grid_width * grid_height) }

對我來說,后者是其中最優雅的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM