检查单元格和更改与数据帧中的条件匹配的邻居的最有效方法
Most efficient way to check cells and change neighbors matching a condition in a dataframe
我正在使用 pandas 数据框为 rougelike 风格的游戏地图编辑器存储动态 2D 游戏地图。玩家可以绘制和擦除房间。我需要在这些更衣室周围画墙。
我有这个:
0 1 2 3 4 5 6
0 . . . x . .
1 . . x x . .
2 . x x x . .
3 . . . . . .
4 . . . . . .
需要这个:
0 1 2 3 4 5 6
0 . # # x # .
1 # # x x # .
2 # x x x # .
3 # # # # # .
4 . . . . . .
最有效的方法是什么?
到目前为止,我遵循了 here 概述的方法,但这使我在 lambda
前后留下了一些嵌套的 if
和 for
。因为我必须首先检查当前是否挖出了一个单元格。然后在更改匹配单元格之前检查所有八个邻居是否被挖出。这确实需要一个关于帧速率的工具。我不可能是第一个遇到这种事情的人,但一直在寻找解决方案。
我希望通过应用 mask
或类似的二进制比较找到一种方法。尽管如此,我仍然不知道如何有效地进行邻居检查而不会退回到嵌套循环中。
您想要做的是二元膨胀。您可以使用 scipy.ndimage.morphology.binary_dilation
:
在底层 numpy 数组上执行此操作
from scipy.ndimage.morphology import binary_dilation
import numpy as np
a = df.eq('x').to_numpy()
# [[False False True True True False]
# [False True True True True False]
# [ True True True True True False]
# [False True True True False False]
# [False False False False False False]]
df = pd.DataFrame(np.where(binary_dilation(a), 'x', df))
输出:
0 1 2 3 4 5
0 . . x x x .
1 . x x x x .
2 x x x x x .
3 . x x x . .
4 . . . . . .
现在要获得不同的符号,您可以使用更复杂的掩码 (binary_dilation(a)^a
) 和 XOR 运算 (^
):
a = df.eq('x').to_numpy()
df = pd.DataFrame(np.where(binary_dilation(a)^a, '#', df))
输出:
0 1 2 3 4 5
0 . . # x # .
1 . # x x # .
2 # x x x # .
3 . # # # . .
4 . . . . . .
所有邻居
使用不同的结构元素(这里是 1 的 3x3 矩阵):
from scipy.ndimage.morphology import binary_dilation
a = df.eq('x').to_numpy()
kernel = np.ones((3,3))
df = pd.DataFrame(np.where(binary_dilation(a, kernel)^a, '#', df))
输出:
0 1 2 3 4 5
0 . # # x # .
1 # # x x # .
2 # x x x # .
3 # # # # # .
4 . . . . . .
其他内核
您可以轻松调整代码以具有任意邻居组合
示例:左上角
kernel = np.array([[1, 1, 0],
[1, 1, 0],
[0, 0, 0]])
0 1 2 3 4 5
0 . # # x . .
1 # # x x . .
2 # x x x . .
3 . . . . . .
4 . . . . . .
我正在使用 pandas 数据框为 rougelike 风格的游戏地图编辑器存储动态 2D 游戏地图。玩家可以绘制和擦除房间。我需要在这些更衣室周围画墙。
我有这个:
0 1 2 3 4 5 6
0 . . . x . .
1 . . x x . .
2 . x x x . .
3 . . . . . .
4 . . . . . .
需要这个:
0 1 2 3 4 5 6
0 . # # x # .
1 # # x x # .
2 # x x x # .
3 # # # # # .
4 . . . . . .
最有效的方法是什么?
到目前为止,我遵循了 here 概述的方法,但这使我在 lambda
前后留下了一些嵌套的 if
和 for
。因为我必须首先检查当前是否挖出了一个单元格。然后在更改匹配单元格之前检查所有八个邻居是否被挖出。这确实需要一个关于帧速率的工具。我不可能是第一个遇到这种事情的人,但一直在寻找解决方案。
我希望通过应用 mask
或类似的二进制比较找到一种方法。尽管如此,我仍然不知道如何有效地进行邻居检查而不会退回到嵌套循环中。
您想要做的是二元膨胀。您可以使用 scipy.ndimage.morphology.binary_dilation
:
from scipy.ndimage.morphology import binary_dilation
import numpy as np
a = df.eq('x').to_numpy()
# [[False False True True True False]
# [False True True True True False]
# [ True True True True True False]
# [False True True True False False]
# [False False False False False False]]
df = pd.DataFrame(np.where(binary_dilation(a), 'x', df))
输出:
0 1 2 3 4 5
0 . . x x x .
1 . x x x x .
2 x x x x x .
3 . x x x . .
4 . . . . . .
现在要获得不同的符号,您可以使用更复杂的掩码 (binary_dilation(a)^a
) 和 XOR 运算 (^
):
a = df.eq('x').to_numpy()
df = pd.DataFrame(np.where(binary_dilation(a)^a, '#', df))
输出:
0 1 2 3 4 5
0 . . # x # .
1 . # x x # .
2 # x x x # .
3 . # # # . .
4 . . . . . .
所有邻居
使用不同的结构元素(这里是 1 的 3x3 矩阵):
from scipy.ndimage.morphology import binary_dilation
a = df.eq('x').to_numpy()
kernel = np.ones((3,3))
df = pd.DataFrame(np.where(binary_dilation(a, kernel)^a, '#', df))
输出:
0 1 2 3 4 5
0 . # # x # .
1 # # x x # .
2 # x x x # .
3 # # # # # .
4 . . . . . .
其他内核
您可以轻松调整代码以具有任意邻居组合
示例:左上角
kernel = np.array([[1, 1, 0],
[1, 1, 0],
[0, 0, 0]])
0 1 2 3 4 5
0 . # # x . .
1 # # x x . .
2 # x x x . .
3 . . . . . .
4 . . . . . .