使用numpy.vectorize创建多维数组触发ValueError,求错误原因解析
这个问题我之前也碰到过,其实核心原因是np.vectorize的默认行为和你预期的不一样~
先解释错误里的"序列"到底是什么
当你调用np.vectorize(dummy)(x)时,vectorize会逐个遍历x中的元素,把每个x_i传入dummy函数。而dummy(x_i)返回的是一个长度为2的numpy数组(比如当x_i=0时,返回array([0., 1.]))——这个返回的数组就是错误提示里说的"序列"。
默认情况下,np.vectorize期望每个函数调用返回一个标量(单个数值),这样它可以把这些标量直接拼接成一个一维数组。但现在你的函数返回的是一个序列(数组),numpy不知道该怎么把这些序列塞进一个常规数组里(除非你明确告诉它要存对象),所以就抛出了ValueError: setting an array element with a sequence。
给你两个解决办法
办法1:给vectorize指定otypes参数(不推荐,性能没提升)
如果你一定要用np.vectorize,可以显式告诉它每个输出是一个对象(也就是允许存数组):
import numpy as np def dummy(x): y = np.array([np.sin(x), np.cos(x)]) return y x = np.array([0, np.pi/2, np.pi]) # 指定otypes为object,让vectorize知道每个返回值是一个对象 vec_dummy = np.vectorize(dummy, otypes=[object]) y = vec_dummy(x) # 再把结果堆叠成你需要的(N,2)数组 y = np.stack(y)
不过要注意:np.vectorize本质上还是循环,只是做了一层包装,没有性能优化,所以这个方法只适合临时救急。
办法2:直接向量化dummy函数(强烈推荐)
numpy的三角函数本身就是向量化函数,完全不需要循环或者vectorize。你可以直接修改dummy,让它接受数组输入,一次性计算所有结果:
import numpy as np def dummy(x): # 当x是数组时,np.sin(x)和np.cos(x)会自动逐个计算元素,返回同长度的数组 y = np.array([np.sin(x), np.cos(x)]) return y.T # 转置后得到(N,2)的数组,和你原来循环的结果完全一致 x = np.array([0, np.pi/2, np.pi]) y = dummy(x)
这样写不仅代码更简洁,而且是真正的numpy向量化操作,运行速度比循环和vectorize快得多,完全符合numpy的使用习惯。
你可以验证一下,这个方法得到的y和你原来循环生成的结果完全相同~
内容的提问来源于stack exchange,提问作者finefoot
相关产品推荐
相关产品推荐

