对grid_to_graph的学习

在学习scikit_learn时,使用到了grid_to_graph方法,由于不懂该方法的作用以及为何产生得到的输出,因此对该方法进行深入的学习。

_make_edges_3d方法

要学习grid_to_graph方法,先得学习_make_edges_3d方法。
该方法的源码为:


```python
def _make_edges_3d(n_x, n_y, n_z=1):
    """Returns a list of edges for a 3D image.

    Parameters
    ----------
    n_x : int
        The size of the grid in the x direction.
    n_y : int
        The size of the grid in the y direction.
    n_z : integer, default=1
        The size of the grid in the z direction, defaults to 1
    """
    vertices = np.arange(n_x * n_y * n_z).reshape((n_x, n_y, n_z))
    edges_deep = np.vstack((vertices[:, :, :-1].ravel(),
                            vertices[:, :, 1:].ravel()))
    edges_right = np.vstack((vertices[:, :-1].ravel(),
                             vertices[:, 1:].ravel()))
    edges_down = np.vstack((vertices[:-1].ravel(), vertices[1:].ravel()))
    edges = np.hstack((edges_deep, edges_right, edges_down))
    return edges

该方法的作用是返回一个3D图形的边的列表,参数说明:

n_x:网格在x方向上的大小。
n_y:网格在y方向上的大小。
n_z:网格在z方向上的大小。默认为1

使用二维数据

为了更清楚地说明,先使用二维数据对方法中的代码进行讲解:

n_x = 3
n_y = 2
# vertices = np.arange(n_x * n_y * n_z).reshape((n_x, n_y, n_z))
vertices = np.arange(n_x * n_y).reshape((n_x, n_y))  # 使用[0,1,2,3,4,5]得到3*2的二维数组

该方法得到一个二维数组

输出:
[[0 1]
 [2 3]
 [4 5]]

先简化代码中的方法,逐步得到代码的目的:

v1 = vertices[:, :-1]
v2 = vertices[:, 1:]
输出:
v1:# 取所有的行, 取(除最后一列的)所有列
[[0]
 [2]
 [4]]
 
v2:# 取所有的行, 取(除第一列的)所有列
[[1]
 [3]
 [5]]
v1_ravel = v1.ravel()  # 降维,将v1转换为一维 [0 2 4]
v2_ravel = v2.ravel()  # 降维,将v2转换为一维 [1 3 5]
e = np.vstack(v1)  # 按垂直方向(行顺序)堆叠数组构成一个新的数组
e2 = np.hstack(v1)  # 按水平方向(列顺序)堆叠数组构成一个新的数组 [0 2 4]
输出:
e:
[[0]
 [2]
 [4]]

e2
[0 2 4]

_make_edges_3d得到的是一个3D图形的边的列表
使用简化的_make_edges_3d方法是不是得到一个2D图形的边的列表呢?

使用三维数据,z=1

n_x = 3
n_y = 2
n_z = 1
vertices = np.arange(n_x * n_y * n_z).reshape((n_x, n_y, n_z))  # 使用[0,1,2,3,4,5]得到3*2*1的三维数组

输出vertices :
(3*2*1[[[0]
  [1]]

 [[2]
  [3]]

 [[4]
  [5]]]

这样的输出对于不习惯3维数据的同学来说有点复杂。(看得懂的可以忽略这一步~)

我们先把数据看成2维的,如果数据是 0, 1, 2, 3, 4, 5
得到一维数据:0, 1, 2, 3, 4, 5
给维度加上框框 “[ ]”,得到一维数组 [0, 1, 2, 3, 4, 5]
若想要得到一个3行2列的数据,则可以表示为
0 1
2 3
4 5
给维度加上框框 “[ ]”,就可以得到
[
[0 1]
[2 3]
[4 5]
]

若把[0 1]、 [2 3]、 [4 5]看成一个元素,那这个二维数组就变成了一个“一维数组”
从这一步可以看出,每一个[ ]就是框住了一个“维度”。

最外层的"[ ]"看成一维,
那么,想要得到三维数据,就需要再把二维数据中的元素加上一个 [ ],来给它“增维”:
[
[[0] [1]]
[[2] [3]]
[[4] [5]]
]

得到三维数组之后,计算:

edges_deep = np.vstack((vertices[:, :, :-1].ravel(), vertices[:, :, 1:].ravel()))  # 获取边的深度 这跟n_z有关 后面再介绍
# 输出 []  因为数组在z上只有1个元素,切片后就没有元素了

edges_right = np.vstack((vertices[:, :-1].ravel(), vertices[:, 1:].ravel()))

再使用前面的方法分解一下这行代码:

v1 = vertices[:, :-1]  # 除最后一列
v2 = vertices[:, 1:]  # 除第一列
r1 = v1.ravel()  # [0 2 4]
r2 = v2.ravel()  # [1 3 5]
edges_right = np.vstack((r1, r2))
# [[0 2 4]
#  [1 3 5]]

同理:

edges_down = np.vstack((vertices[:-1].ravel(), vertices[1:].ravel()))
# [[0 1 2 3]
#  [2 3 4 5]]
edges = np.hstack((edges_deep, edges_right, edges_down))
# [[0 2 4 0 1 2 3]
#  [1 3 5 2 3 4 5]]

这个方法主要是计算edges_deep、edges_right、edges_down这三个属性,那么这三个属性是代表什么意思呢?
从代码可以看出,edges_deep是取的z轴上的值,edges_right是取y轴上的值,edges_down是取x轴上的值。
edges 返回一个矩阵,也就是指定形状的3D图形的边的集合

下面是使用2维数据简化该方法,并得出输出结果:

n_x = 3
n_y = 2
vertices = np.arange(n_x * n_y).reshape((n_x, n_y))
edges_right = np.vstack((vertices[:, :-1].ravel(), vertices[:, 1:].ravel()))
edges_down = np.vstack((vertices[:-1].ravel(), vertices[1:].ravel()))
edges = np.hstack((edges_right, edges_down))
# print(edges)
# [[0 2 4 0 1 2 3]
#  [1 3 5 2 3 4 5]]

n_voxels = n_x * n_y  # 6
weights = np.ones(edges.shape[1])  # [1. 1. 1. 1. 1. 1. 1.]
diag = np.ones(n_voxels)  # [1. 1. 1. 1. 1. 1.]

diag_idx = np.arange(n_voxels)  # [0 1 2 3 4 5]
i_idx = np.hstack((edges[0], edges[1]))  # [0 2 4 0 1 2 3 1 3 5 2 3 4 5]
j_idx = np.hstack((edges[1], edges[0]))  # [1 3 5 2 3 4 5 0 2 4 0 1 2 3]
n1 = np.hstack((weights, weights, diag))  # [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
o1 = np.hstack((i_idx, diag_idx))  # [0 2 4 0 1 2 3 1 3 5 2 3 4 5 0 1 2 3 4 5]
o2 = np.hstack((j_idx, diag_idx))  # [1 3 5 2 3 4 5 0 2 4 0 1 2 3 0 1 2 3 4 5]
# 加入diag_idx表示填充对角线
n2 = (o1, o2)
c1 = (n1, n2)
c2 = (n_voxels, n_voxels)
graph = sparse.coo_matrix(c1, c2)
print(graph.toarray())

# print(graph)

# 输出:
# [[1. 1. 1. 0. 0. 0.]
#  [1. 1. 0. 1. 0. 0.]
#  [1. 0. 1. 1. 1. 0.]
#  [0. 1. 1. 1. 0. 1.]
#  [0. 0. 1. 0. 1. 1.]
#  [0. 0. 0. 1. 1. 1.]]

# 对应为1的地方就是有边的地方


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值