Python 在不使用两个for循环的情况下重塑numpy阵列
我有两个numpy阵列Python 在不使用两个for循环的情况下重塑numpy阵列,python,arrays,numpy,Python,Arrays,Numpy,我有两个numpy阵列 import numpy as np x = np.linspace(1e10, 1e12, num=50) # 50 values y = np.linspace(1e5, 1e7, num=50) # 50 values x.shape # output is (50,) y.shape # output is (50,) 我想创建一个函数,它返回一个形状为50,50的数组,这样第一个x值x0就可以计算所有y值,等等 我正在使用的当前函数相当复杂,因此让我们使用
import numpy as np
x = np.linspace(1e10, 1e12, num=50) # 50 values
y = np.linspace(1e5, 1e7, num=50) # 50 values
x.shape # output is (50,)
y.shape # output is (50,)
我想创建一个函数,它返回一个形状为50,50的数组,这样第一个x值x0就可以计算所有y值,等等
我正在使用的当前函数相当复杂,因此让我们使用一个更简单的示例。假设函数是
def func(x,y):
return x**2 + y**2
我如何将其形状设置为50,50数组?目前,它将输出50个值。您会在数组中使用for循环吗
比如:
np.array([[func(x,y) for i in x] for j in y)
但不使用两个for循环。这需要永远运行
编辑:有人要求我分享我复杂的功能。下面是:
有一个数据向量,它是一个包含4000个测量值的1D numpy阵列。还有一个规格化的_矩阵,形状为40004000——它没有什么特别的,只是一个整数输入值在0到1之间的矩阵,例如0.5567878。这是两个给定的输入
我的函数返回TransportAvector*matrix*datavector的矩阵乘积,它是一个值
现在,正如您在代码中看到的,我初始化了两个数组,x和y,它们通过一系列x参数和y参数。也就是说,funcx,y为值x1和值y1返回什么,即funcx1,y1
matrix1的形状是5040004000。matrix2的形状是5040004000。总_矩阵同上
规格化的_矩阵的形状为40004000,id_mat的形状为40004000
normalized_matrix
print normalized_matrix.shape #output (4000,4000)
data_vector = datarr
print datarr.shape #output (4000,)
def func(x, y):
matrix1 = x [:, None, None] * normalized_matrix[None, :, :]
matrix2 = y[:, None, None] * id_mat[None, :, :]
total_matrix = matrix1 + matrix2
# transpose(datavector) * matrix * datavector
# by matrix multiplication, equals single value
return np.array([ np.dot(datarr.T, np.dot(total_matrix, datarr) ) ])
如果我尝试使用np.meshgrid,也就是说,如果我尝试
x = np.linspace(1e10, 1e12, num=50) # 50 values
y = np.linspace(1e5, 1e7, num=50) # 50 values
X, Y = np.meshgrid(x,y)
z = func(X, Y)
我得到以下值错误:ValueError:操作数无法与形状50,1,1,50 140004000一起广播 您对列表的理解是正确的,您只需要添加一个额外的迭代级别:
np.array([[func(i,j) for i in x] for j in y])
我认为有一个更好的办法,就在我嘴边,但作为一项临时措施: 您正在meshgrid的1x2窗口上操作。可以使用从numpy.lib.stride跨步的as_技巧将网格网格重新排列为两个元素窗口,然后将函数应用于结果数组。我喜欢使用通用的nd解决方案,而不是我的来转换数组
import numpy as np
a = np.array([1,2,3])
b = np.array([.1, .2, .3])
z= np.array(np.meshgrid(a,b))
def foo((x,y)):
return x+y
>>> z.shape
(2, 3, 3)
>>> t = sliding_window(z, (2,1,1))
>>> t
array([[ 1. , 0.1],
[ 2. , 0.1],
[ 3. , 0.1],
[ 1. , 0.2],
[ 2. , 0.2],
[ 3. , 0.2],
[ 1. , 0.3],
[ 2. , 0.3],
[ 3. , 0.3]])
>>> v = np.apply_along_axis(foo, 1, t)
>>> v
array([ 1.1, 2.1, 3.1, 1.2, 2.2, 3.2, 1.3, 2.3, 3.3])
>>> v.reshape((len(a), len(b)))
array([[ 1.1, 2.1, 3.1],
[ 1.2, 2.2, 3.2],
[ 1.3, 2.3, 3.3]])
>>>
这应该更快一些
您可能需要修改函数的参数签名
如果johnvinyard.com博客的链接中断,我已经在其他SO答案中发布了滑动窗口实现-
四处搜索,你会发现许多其他棘手的解决方案 在numpy中重塑为不同的含义。当您从100开始,并将其更改为5,20或10,10二维阵列时,即“重塑”。有一种功能可以做到这一点
您希望获取2个一维数组,并使用这些数组从函数生成二维数组。这就像取2的外积,将其值的所有组合传递给函数
某种形式的双循环是实现这一点的一种方法,无论是显式循环还是列表理解。但是加速这个过程取决于这个函数
对于x**2+y**2示例,它可以非常容易地“矢量化”:
In [40]: x=np.linspace(1e10,1e12,num=10)
In [45]: y=np.linspace(1e5,1e7,num=5)
In [46]: z = x[:,None]**2 + y[None,:]**2
In [47]: z.shape
Out[47]: (10, 5)
这充分利用了numpy广播的优势。如果为“无”,则x将被重塑为10,1,y将被重塑为1,5,并且+将取外部和
十、 Y=np.meshgridx,Y,indexing='ij'生成两个10,5数组,它们可以以相同的方式使用。查看is文档了解其他参数
因此,如果您的更复杂的函数可以这样用2d数组编写,那么“矢量化”就很容易了
但如果该函数必须接受2个标量,并返回另一个标量,那么您将陷入某种双循环
双循环的列表理解形式为:
np.array([[x1**2+y1**2 for y1 in y] for x1 in x])
另一个是:
z=np.empty((10,5))
for i in range(10):
for j in range(5):
z[i,j] = x[i]**2 + y[j]**2
使用np.vectorize可以在一定程度上加快这种双循环。它接受一个用户定义的函数,并返回一个可以接受可广播数组的函数:
In [65]: vprod=np.vectorize(lambda x,y: x**2+y**2)
In [66]: vprod(x[:,None],y[None,:]).shape
Out[66]: (10, 5)
我在过去所做的测试表明,向量化可以在列表理解路径上提高20%左右,但这一改进与首先编写用于处理2d数组的函数完全不同
顺便说一句,这种“矢量化”问题在这么短的时间内已经被问过很多次了。除了这些广泛的例子,我们不能帮助你不知道更多关于更复杂的函数。只要它是一个接受标量的黑盒,我们就可以帮助您实现np.vectorize。您仍然需要了解有无meshgrid帮助的广播。回答您编辑的问题:
normalized_matrix
print normalized_matrix.shape #output (4000,4000)
data_vector = datarr
print datarr.shape #output (4000,)
def func(x, y):
matrix1 = x [:, None, None] * normalized_matrix[None, :, :]
matrix2 = y[:, None, None] * id_mat[None, :, :]
total_matrix = matrix1 + matrix2
# transpose(datavector) * matrix * datavector
# by matrix multiplication, equals single value
# return np.array([ np.dot(datarr.T, np.dot(total_matrix, datarr))])
return np.einsum('j,ijk,k->i',datarr,total_matrix,datarr)
由于datarr是形状4000,所以转置不起任何作用。我相信你希望这两个点的结果是形状50,。我建议使用einsum。但是它可以用tensordot来完成,或者我认为甚至可以用np.dotnp.dottotal_矩阵,datarr,datarr来完成。使用较小的数组测试表达式,重点是获得正确的形状
x = np.linspace(1e10, 1e12, num=50) # 50 values
y = np.linspace(1e5, 1e7, num=50) # 50 values
z = func(x,y)
# X, Y = np.meshgrid(x,y)
# z = func(X, Y)
十、 你错了。func取1d的x和y。请注意如何使用[:,无,无]展开尺寸标注。此外,您也不是从x和y的外部组合创建二维阵列。没有你的阵列
在func中为50,50或50,50,。。。。更高的尺寸由nomalied_矩阵和id_mat提供
在向我们显示ValueError时,您还应该指出代码中发生错误的位置。否则我们必须猜测,或者自己重新创建代码
事实上,当我运行编辑过的funcX,Y时,会出现以下错误:
----> 2 matrix1 = x [:, None, None] * normalized_matrix[None, :, :]
3 matrix2 = y[:, None, None] * id_mat[None, :, :]
4 total_matrix = matrix1 + matrix2
5 # transpose(datavector) * matrix * datavector
ValueError: operands could not be broadcast together with shapes (50,1,1,50) (1,400,400)
请参阅,错误就发生在一开始。标准化的_矩阵扩展到1400400[我使用的是较小的示例]。50,50 X扩展为50,1,1,50。x扩展到50,1,1,可以正常广播。要解决编辑和编辑中的广播错误,请执行以下操作: 在您的函数中,您正在向数组添加维度,以尝试让它们进行广播
matrix1 = x [:, None, None] * normalized_matrix[None, :, :]
此表达式看起来像是要用二维数组广播一维数组
网格网格的结果是两个二维阵列:
X,Y = np.meshgrid(x,y)
>>> X.shape, Y.shape
((50, 50), (50, 50))
>>>
当您尝试在广播表达式中使用X时,尺寸不对齐,这就是导致ValueError的原因-请参阅:
我不知道你到底想要什么样的输出。如果输出为50倍;50矩阵是M,你期望M[i,j]的公式是什么?x0在y0到y49处求值,然后x1在y0到y49处求值,等等。这是似曾相识,在它的另一个化身中得到了回答。你尝试了np.meshgrid,但它不起作用?编辑的问题,以及更详细的函数是很有帮助的。但您应该指出ValueError发生的位置。人们喜欢对省略此类信息投反对票。请看我的第二个答案。谢谢你的全面回答。看起来我一直在使用两个for循环,除非我以某种方式更改网格,否则可以轻松地将x和y转换为50,50个数组,但是要将它们组合到所需的输出中,这取决于您的代码。numpy函数和运算符可以快速地对一些常见操作执行此操作,如+、*,以及所有ufunc函数。但诀窍是用这些术语来表达你的函数。我想我上面的函数基本上是一个ufunc,我恐怕我自己有点搞糊涂了。我们基本上有50个矩阵。然后,该函数进行矩阵乘法,得到50个值,每个矩阵一个值,即`funcx1,y1,funcx2,y2,funcx3,y3,等等`我试图找出如何创建形状为50,50的输出,这样funcx1,y1,funcx1,y2,funcx1,y3,。。。funcx2,y1,funcx2,y2,funcx2,y3,。。。funcx3,y1,funcx3,y2,funcx3,y3,。。。。我认为meshgrid是实现这一点的正确方法……无论如何,感谢您的回复。ValueError在包含网格时发生。我不知道为什么你的函数会出错——我不知道。在上面的函数中,matrix1乘以x形50,再乘以规格化的_矩阵形40004000。结果矩阵1的形状为5040004000。当我运行代码时没有问题。啊,我理解你现在说的。x被扩展到50,1,1,这是有效的。使用网格会创建一个50,50形状的输入,但实际上不是这样。我现在明白为什么会有广播错误了。现在,为了弄清楚如何创建输出矩阵,x1,y1,x1,y2,x1,y3,。。。x2,y1,x2,y2,…。@ShanZhengYang请看下面我的另一个答案-使用numpy.meshgrid和基于numpy.lib.stride的滑动窗口函数。
>>> x1 = X[:, np.newaxis, np.newaxis]
>>> nm = normalized_matrix[np.newaxis, :, :]
>>> x1.shape
(50, 1, 1, 50)
>>> nm.shape
(1, 4000, 4000)
>>>