这就是我获取我的N-D数据的方式(func
是IRL不可矢量化):
import numpy
import xarray
import itertools
xs = numpy.linspace(0, 10, 100)
ys = numpy.linspace(0, 0.1, 20)
zs = numpy.linspace(0, 5, 200)
def func(x, y, z):
return x * y / z
vals = list(itertools.product(xs, ys, zs))
result = [func(x, y, z) for x, y, z in vals]
我有一种感觉,我所做的事情可以简化。我想把它放在xarray.DataArray
而不重塑数据。但是,我现在就是这样做的:
arr = np.array(result).reshape(len(xs), len(ys), len(zs))
da = xarray.DataArray(arr, coords=[('x', xs), ('y', ys), ('z', zs)])
这是一个简单的例子,但通常我使用〜10D数据,我通过映射itertools.product
(并行)获得。
我的问题:如何在不重塑我的数据和使用vals
并且不使用xs
,ys
和zs
的长度的情况下如何做到这一点?
与您的工作方式类似:
index = pandas.MultiIndex.from_tuples(vals, names=['x', 'y', 'z'])
df = pandas.DataFrame(result, columns=['result'], index=index)
编辑:这是我解决它的方式,受到@hpaulj答案的启发,谢谢!
import numpy
import xarray
import itertools
coords = dict(x=numpy.linspace(0, 10, 100),
y=numpy.linspace(0, 0.1, 20),
z=numpy.linspace(0, 5, 200))
def func(x, y, z):
return x * y / z
result = [func(x, y, z) for x, y, z in itertools.product(*coords.values())]
xarray.DataArray(numpy.reshape(result, [len(i) for i in coords.values()]), coords=coords)
经验丰富的numpy
用户倾向于专注于删除迭代步骤。因此,我们放大了你的result
计算,并将reshape
视为微不足道的东西。因此,迄今为止的答案都集中在广播和计算你的功能上。
但是我开始怀疑那真正困扰你的是那个
reshape(len(xs), len(ys), len(zs))
如果你有10个这样的尺寸,而不仅仅是3,可能会变得笨拙。这不是计算速度,而是输入len(..)
10次所需的努力。或者可能是代码看起来很难看。
无论如何,这是一种绕过所有打字的方式。关键是在列表中收集维数组
In [495]: dims = [np.linspace(0,10,4), np.linspace(0,.1,3), np.linspace(0,5,5)]
In [496]: from itertools import product
In [497]: vals = list(product(*dims))
In [498]: len(vals)
Out[498]: 60
In [499]: result = [sum(ijk) for ijk in vals] # a simple func
现在只需使用简单的列表理解即可获得len's
:
In [501]: arr=np.array(result).reshape([len(i) for i in dims])
In [502]: arr.shape
Out[502]: (4, 3, 5)
另一种可能性是在开始时将linspace
参数放在列表中。
In [504]: ldims=[4,3,5]
In [505]: ends=[10,.1,5]
In [506]: dims=[np.linspace(0,e,l) for e,l in zip(ends, ldims)]
In [507]: vals = list(product(*dims))
In [508]: result=[sum(ijk) for ijk in vals]
In [509]: arr=np.array(result).reshape(ldims)
reshape
本身并不昂贵。通常它会创建一个视图,这是您可以使用数组执行的最快速的事情之一。
@Divakar
在他删除的答案中暗示了这种解决方案,*np.meshgrid(*A)
可以替代你的product(xs,ys)
。
顺便说一句,我的回答也不涉及xarray
- 因为我没有安装该软件包。我假设你知道你在将3d形状的arr
传递给它时你在做什么,而不是更长的1d数组。看看标签号码,qzxswpoi的5k粉丝,numpy
的23个粉丝。
xarray
xarray
参数也可以从coords
构建(附加名单)。
如果这个答案不符合您的喜好,我建议关闭这个问题,然后用dims
标签开始一个新问题。那样你就不会吸引无数的xarray
苍蝇。
第二次编辑我忘记了einsum!如果你可以折磨你的功能以适应这将更快(下面的时间1.5ms)
numpy
您需要重塑并广播到相同形状的阵列。正如巴尔佐拉所说,如果每个方向的10D和100(10 ** 20个元素),这将非常大。正如hpaulj所说,重塑一个numpy数组通常是微不足道的,在这种情况下是如此,尽管广播确实需要一些工作。但是比itertools.product()方法要少得多。以你为榜样
result = np.einsum('i,j,k', xs, ys, 1.0 / zs)
使用如下的timeit我得到numpy计算为4ms,itertools方法为150ms。我认为对于更多维度而言差异会更大。
import numpy as np
xs = np.linspace(0, 10, 100)
ys = np.linspace(0, 0.1, 20)
zs = np.linspace(0.1, 5, 200)
xn, yn, zn = len(xs), len(ys), len(zs)
xs_b = np.broadcast_to(xs.reshape(xn, 1, 1), (xn, yn, zn))
ys_b = np.broadcast_to(ys.reshape(1, yn, 1), (xn, yn, zn))
zs_b = np.broadcast_to(zs.reshape(1, 1, zn), (xn, yn, zn))
result = xs_b * ys_b / zs_b
编辑PS。我改变你的zs以通过除以零来防止numpy警告,因为这可能影响了时间比较。
我的回答:[删除因为问题意外改变]