在Python / NumPy中使用网格的目的是什么?

有人能解释一下Numpy中meshgrid函数的目的是什么吗?我知道它创建了某种用于绘图的坐标网格,但我真的看不到它的直接好处。

我正在学习Sebastian Raschka的“Python机器学习”,他正在用它来绘制决策边界。参见输入11 在这里

我也从官方文档中尝试了这段代码,但是,同样,输出对我来说没有意义。

x = np.arange(-5, 5, 1)
y = np.arange(-5, 5, 1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)

如果可能的话,请给我展示一些真实的例子。

312404 次浏览

假设你有一个函数:

def sinus2d(x, y):
return np.sin(x) + np.sin(y)

比如说,你想看看它在0到2*范围内是什么样子。你会怎么做?这里有np.meshgrid:

xx, yy = np.meshgrid(np.linspace(0,2*np.pi,100), np.linspace(0,2*np.pi,100))
z = sinus2d(xx, yy) # Create the image on this grid

这样的图是这样的:

import matplotlib.pyplot as plt
plt.imshow(z, origin='lower', interpolation='none')
plt.show()

enter image description here

所以np.meshgrid只是一个方便。原则上,同样可以通过以下方法做到:

z2 = sinus2d(np.linspace(0,2*np.pi,100)[:,None], np.linspace(0,2*np.pi,100)[None,:])

但是您需要注意您的维度(假设您有两个以上…)和正确的广播。np.meshgrid为你做所有这些。

此外,如果你想做插值,但排除某些值,meshgrid允许你删除坐标和数据:

condition = z>0.6
z_new = z[condition] # This will make your array 1D

现在怎么做插值呢?你可以将xy赋值给像scipy.interpolate.interp2d这样的插值函数,所以你需要一种方法来知道哪些坐标被删除了:

x_new = xx[condition]
y_new = yy[condition]

然后你仍然可以插入“正确的”坐标(尝试没有网格,你会有很多额外的代码):

from scipy.interpolate import interp2d
interpolated = interp2d(x_new, y_new, z_new)

原始网格允许你再次得到原始网格上的插值:

interpolated_grid = interpolated(xx[0], yy[:, 0]).reshape(xx.shape)

这些只是我使用meshgrid的一些例子,可能还有更多。

meshgrid的目的是用一个x值数组和一个y值数组创建一个矩形网格。

例如,如果我们想创建一个网格在x和y方向上的0到4之间的每一个整数值上都有一个点。要创建一个矩形网格,我们需要xy点的每个组合。

这是25点,对吧?因此,如果我们想为所有这些点创建一个x和y数组,可以执行以下操作。

x[0,0] = 0    y[0,0] = 0
x[0,1] = 1    y[0,1] = 0
x[0,2] = 2    y[0,2] = 0
x[0,3] = 3    y[0,3] = 0
x[0,4] = 4    y[0,4] = 0
x[1,0] = 0    y[1,0] = 1
x[1,1] = 1    y[1,1] = 1
...
x[4,3] = 3    y[4,3] = 4
x[4,4] = 4    y[4,4] = 4

这将导致以下xy矩阵,这样每个矩阵中相应元素的配对就给出了网格中一点的x和y坐标。

x =   0 1 2 3 4        y =   0 0 0 0 0
0 1 2 3 4              1 1 1 1 1
0 1 2 3 4              2 2 2 2 2
0 1 2 3 4              3 3 3 3 3
0 1 2 3 4              4 4 4 4 4

然后我们可以绘制它们来验证它们是否是一个网格:

plt.plot(x,y, marker='.', color='k', linestyle='none')

enter image description here

显然,这非常乏味,特别是对于xy的大范围。相反,meshgrid实际上可以为我们生成这个:我们必须指定的是唯一的xy值。

xvalues = np.array([0, 1, 2, 3, 4]);
yvalues = np.array([0, 1, 2, 3, 4]);

现在,当我们调用meshgrid时,会自动获得之前的输出。

xx, yy = np.meshgrid(xvalues, yvalues)


plt.plot(xx, yy, marker='.', color='k', linestyle='none')

enter image description here

创建这些矩形网格对许多任务都很有用。在你的文章中提供的例子中,它只是一种在xy的值范围内采样函数(sin(x**2 + y**2) / (x**2 + y**2))的方法。

由于该函数已在矩形网格上进行采样,因此现在可以将该函数可视化为“图像”。

enter image description here

此外,结果现在可以传递给在矩形网格上期望数据的函数(即contourf)

微软Excel提供: 

enter image description here

实际上,np.meshgrid的目的已经在文档中提到了:

np.meshgrid

从坐标向量返回坐标矩阵。

在给定一维坐标数组x1, x2,…, xn。

它的主要目的是创建一个坐标矩阵。

你可能会问自己:

为什么我们需要创建坐标矩阵?

你需要用Python/NumPy坐标矩阵的原因是坐标和值之间没有直接关系,除非你的坐标从0开始并且是纯正整数。然后你可以使用数组的下标作为下标。 然而,当情况并非如此时,您需要以某种方式将坐标存储在数据旁边。

假设你的数据是:

1  2  1
2  5  2
1  2  1

但是,每个值代表3 x 2公里的面积(水平x垂直)。假设你的原点是左上角,你想用数组来表示你可以使用的距离:

import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)

其中v为:

array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])

和h:

array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])

因此,如果你有两个指标,让我们说xy(这就是为什么meshgrid的返回值通常是xxxs,而不是x,在这种情况下,我选择h水平!),那么你可以得到点的x坐标,点的y坐标和该点的值通过使用:

h[x, y]    # horizontal coordinate
v[x, y]    # vertical coordinate
data[x, y]  # value

这使得跟踪坐标而且更加容易(甚至更重要),你可以将它们传递给需要知道坐标的函数。

稍微长一点的解释

然而,np.meshgrid本身并不经常直接使用,大多数情况下只使用类似的对象中的一个np.mgridnp.ogrid。 这里np.mgrid表示sparse=False,而np.ogrid表示sparse=True情况(我指的是np.meshgridsparse参数)。请注意,两者之间存在显著差异 np.meshgridnp.ogridnp.mgrid:前两个返回值(如果有两个或多个)是反向的。通常这并不重要,但你应该根据上下文给出有意义的变量名 例如,对于2D网格和matplotlib.pyplot.imshow,将np.meshgrid的第一个返回项命名为x,将第二个返回项命名为y是有意义的,而它是 np.mgridnp.ogrid则相反

np.ogrid和稀疏网格

>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
       

如前所述,与np.meshgrid相比,输出是相反的,这就是为什么我将其解压缩为yy, xx而不是xx, yy:

>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])

这已经看起来像坐标了,特别是2D图中的x和y线。

可视化:

yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")

enter image description here

np.mgrid和密集/丰满的网格

>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
[ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
[ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2],
[ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3],
[ 4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4],
[ 5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5]])
       

这里也一样:输出与np.meshgrid相反:

>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
[ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
[ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2],
[ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3],
[ 4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4],
[ 5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5]])
       

ogrid不同,这些数组包含-5 <= xx <= 5;中的所有 xxyy坐标。-5 <= yy <= 5格。

yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")

enter image description here

功能

它不仅限于2D,这些函数适用于任意维度(好吧,Python中给函数的参数有最大数量,NumPy允许的最大维度数量):

>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
...     print('x{}'.format(i+1))
...     print(repr(x))
x1
array([[[[0]]],




[[[1]]],




[[[2]]]])
x2
array([[[[1]],


[[2]],


[[3]]]])
x3
array([[[[2],
[3],
[4]]]])
x4
array([[[[3, 4, 5]]]])


>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
...     print('x{}'.format(i+1))
...     print(repr(x))
# Identical output so it's omitted here.

即使这些也适用于1D,还有两个(更常见的)1D网格创建函数:

除了startstop参数,它还支持step参数(甚至是表示步数的复杂步骤):

>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1  # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.],
[7., 7., 7., 7.],
[9., 9., 9., 9.]])
>>> x2  # The dimension with the "number of steps"
array([[ 1.,  4.,  7., 10.],
[ 1.,  4.,  7., 10.],
[ 1.,  4.,  7., 10.],
[ 1.,  4.,  7., 10.],
[ 1.,  4.,  7., 10.]])
       

应用程序

你特别问了目的,事实上,如果你需要一个坐标系统,这些网格是非常有用的。

例如,如果你有一个计算二维距离的NumPy函数:

def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
    

你想知道每个点的距离

>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys)  # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
7.07106781, 7.        , 7.07106781, 7.28010989, 7.61577311],
[8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
6.08276253, 6.        , 6.08276253, 6.32455532, 6.70820393],
[7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
5.09901951, 5.        , 5.09901951, 5.38516481, 5.83095189],
[7.21110255, 6.40312424, 5.65685425, 5.        , 4.47213595,
4.12310563, 4.        , 4.12310563, 4.47213595, 5.        ],
[6.70820393, 5.83095189, 5.        , 4.24264069, 3.60555128,
3.16227766, 3.        , 3.16227766, 3.60555128, 4.24264069],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2.        , 2.23606798, 2.82842712, 3.60555128],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1.        , 1.41421356, 2.23606798, 3.16227766],
[6.        , 5.        , 4.        , 3.        , 2.        ,
1.        , 0.        , 1.        , 2.        , 3.        ],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1.        , 1.41421356, 2.23606798, 3.16227766],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2.        , 2.23606798, 2.82842712, 3.60555128]])
        

如果在密集网格而不是开放网格中通过,输出将是相同的。NumPys广播使之成为可能!

让我们将结果可视化:

plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel())  # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()

enter image description here

这也是NumPys mgridogrid变得非常方便的时候,因为它允许你轻松地改变你的网格的分辨率:

ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

enter image description here

然而,由于imshow不支持xy输入,因此必须手动更改刻度。如果它接受xy坐标,那将非常方便,对吧?

使用NumPy编写自然处理网格的函数很容易。此外,NumPy、SciPy和matplotlib中有几个函数希望您在网格中传递。

我喜欢图像,所以让我们探索matplotlib.pyplot.contour:

ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)

enter image description here

注意,坐标已经正确设置!如果你只是传入density,情况就不是这样了。

或者再举一个使用astropy模型的有趣例子(这次我不太关心坐标,我只是用它们来创建一些网格):

from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
g2d = models.Gaussian2D(amplitude=100,
x_mean=np.random.randint(0, 100),
y_mean=np.random.randint(0, 100),
x_stddev=3,
y_stddev=3)
z += g2d(x, y)
a2d = models.AiryDisk2D(amplitude=70,
x_0=np.random.randint(0, 100),
y_0=np.random.randint(0, 100),
radius=5)
z += a2d(x, y)
    

enter image description here

虽然那只是“for the look”;与功能模型和拟合相关的几个函数(例如scipy.interpolate.interp2dscipy.interpolate.griddata甚至显示示例使用np.mgrid)在Scipy等需要网格。其中大多数都适用于开放网格和密集网格,但有些只适用于其中一种

meshgrid有助于从两个1-D数组的所有点对中创建一个矩形网格。

x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 2, 3, 4])

现在,如果你已经定义了一个函数f(x,y),你想要将这个函数应用到数组'x'和'y'中所有可能的点的组合,那么你可以这样做:

f(*np.meshgrid(x, y))

比如说,如果你的函数只产生两个元素的乘积,那么这就是笛卡尔积的实现方式,对于大型数组来说是有效的。

引用自在这里

基本思想

给定可能的x值xs(可以把它们想象成绘图x轴上的标记)和可能的y值,ysmeshgrid生成相应的(x, y)网格点集——类似于set((x, y) for x in xs for y in yx)。例如,如果xs=[1,2,3]ys=[4,5,6],我们将得到坐标的集合{(1,4), (2,4), (3,4), (1,5), (2,5), (3,5), (1,6), (2,6), (3,6)}

返回值的形式

然而,meshgrid返回的表示与上面的表达式有两个不同之处:

第一个meshgrid在2d数组中布局网格点:行对应不同的y值,列对应不同的x值——就像在list(list((x, y) for x in xs) for y in ys)中一样,它将给出以下数组:

   [[(1,4), (2,4), (3,4)],
[(1,5), (2,5), (3,5)],
[(1,6), (2,6), (3,6)]]

第二个meshgrid分别返回x和y坐标(即在两个不同的numpy 2d数组中):

   xcoords, ycoords = (
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]),
array([[4, 4, 4],
[5, 5, 5],
[6, 6, 6]]))
# same thing using np.meshgrid:
xcoords, ycoords = np.meshgrid([1,2,3], [4,5,6])
# same thing without meshgrid:
xcoords = np.array([xs] * len(ys)
ycoords = np.array([ys] * len(xs)).T

注意,np.meshgrid也可以生成更高维度的网格。给定xs ys和zs,你会得到xcods ycods zcods作为3d数组。meshgrid还支持维度的反向排序以及结果的稀疏表示。

应用程序

为什么我们需要这种形式的输出?

在网格上的每个点上应用一个函数: 一个动机是二进制操作符(+,-,*,/,**)作为元素级操作符重载numpy数组。这意味着如果我有一个函数def f(x, y): return (x - y) ** 2在两个标量上工作,我也可以将它应用在两个numpy数组上,以获得一个elementwise结果的数组:例如,f(xcoords, ycoords)f(*np.meshgrid(xs, ys))在上面的例子中给出如下:

array([[ 9,  4,  1],
[16,  9,  4],
[25, 16,  9]])

我不确定这有多有效,但你可以通过这种方式得到高维的外积:np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0)

我在调查用matplotlib绘制等高线图绘制决策边界时遇到了meshgrid。为此,你用meshgrid生成一个网格,计算每个网格点上的函数(如上图所示),然后将xcods, ycods和计算的f值(即zcods)传递到contourf函数中。

简短的回答

meshgrid的目的是在C NumPy库中通过向量化操作来帮助替换Python循环(慢解释代码)。

这个网站借用。

enter image description here

x = np.arange(-4, 4, 0.25)
y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

meshgrid用于在-4和+4之间创建一对坐标,在X和y的每个方向上增加.25,然后每对坐标用于从中找到R和Z。这种准备“网格”的方法;坐标常用于绘制三维曲面,或为二维曲面上色。


详细信息:Python for-loop vs NumPy vector操作

举个更简单的例子,假设我们有两个值序列,

a = [2,7,9,20]
b = [1,6,7,9]    ​

我们想对每一对可能的值执行一个操作,一个从第一个列表中取出,一个从第二个列表中取出。我们还想存储结果。例如,假设我们想要得到每对可能的值的和。

缓慢而费力的方法

c = []
for i in range(len(b)):
row = []
for j in range(len(a)):
row.append (a[j] + b[i])
c.append (row)
print (c)

结果:

[[3, 8, 10, 21],
[8, 13, 15, 26],
[9, 14, 16, 27],
[11, 16, 18, 29]]

Python是解释性的,这些循环执行起来相对较慢。

快速简便的方法

meshgrid用于从代码中删除循环。它返回两个数组(下面是i和j),它们可以组合起来扫描所有现有的对,如下所示:

i,j = np.meshgrid (a,b)
c = i + j
print (c)

结果:

[[ 3  8 10 21]
[ 8 13 15 26]
[ 9 14 16 27]
[11 16 18 29]]

引擎盖下的网格

meshgrid准备的两个数组是:

(array([[ 2,  7,  9, 20],
[ 2,  7,  9, 20],
[ 2,  7,  9, 20],
[ 2,  7,  9, 20]]),


array([[1, 1, 1, 1],
[6, 6, 6, 6],
[7, 7, 7, 7],
[9, 9, 9, 9]]))

这些数组是通过重复提供的值来创建的。一个包含相同行中的值,另一个包含相同列中的其他值。行数和列数由另一个序列中的元素数决定。

因此,meshgrid创建的两个数组对于向量操作来说是形状兼容的。想象页面顶部代码中的x和y序列具有不同数量的元素,x和y生成的数组无论如何都是形状兼容的,不需要任何广播

起源

numpy.meshgrid来自从MATLAB,就像许多其他NumPy函数一样。所以你也可以研究MATLAB中的例子,看看meshgrid在使用中,3D绘图的代码看起来在MATLAB中也是一样

大多数时候你只需要list(zip(X,Y)) where X = np.linspace(x) and Y = np.linspace(y)

幕后故事:

import numpy as np


def meshgrid(x , y):
XX = []
YY = []
for colm in range(len(y)):
XX.append([])
YY.append([])
for row in range(len(x)):
XX[colm].append(x[row])
YY[colm].append(y[colm])
return np.asarray(XX), np.asarray(YY)

我们以@Sarsaparilla的回答数据集为例:

y = [7, 6, 5]
x = [1, 2, 3, 4]


xx, yy = meshgrid(x , y)

输出:

>>> xx
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])


>>> yy
array([[7, 7, 7, 7],
[6, 6, 6, 6],
[5, 5, 5, 5]])