Python 从列表构建点的三维立方体
我有一个列表Python 从列表构建点的三维立方体,python,numpy,Python,Numpy,我有一个列表pts包含N点(Python浮动)。我希望构造一个维度为N*N*N*3的NumPy数组,使该数组等价于: for i in xrange(0, N): for j in xrange(0, N): for k in xrange(0, N): arr[i,j,k,0] = pts[i] arr[i,j,k,1] = pts[j] arr[i,j,k,2] = pts[k] 我想知道如何利
pts
包含N
点(Python浮动)。我希望构造一个维度为N*N*N*3
的NumPy数组,使该数组等价于:
for i in xrange(0, N):
for j in xrange(0, N):
for k in xrange(0, N):
arr[i,j,k,0] = pts[i]
arr[i,j,k,1] = pts[j]
arr[i,j,k,2] = pts[k]
我想知道如何利用NumPy的阵列广播规则和功能(如
tile
)来简化这一过程。我认为以下方法应该有效:
pts = np.array(pts) #Skip if pts is a numpy array already
lp = len(pts)
arr = np.zeros((lp,lp,lp,3))
arr[:,:,:,0] = pts[:,None,None] #None is the same as np.newaxis
arr[:,:,:,1] = pts[None,:,None]
arr[:,:,:,2] = pts[None,None,:]
快速测试:
import numpy as np
import timeit
def meth1(pts):
pts = np.array(pts) #Skip if pts is a numpy array already
lp = len(pts)
arr = np.zeros((lp,lp,lp,3))
arr[:,:,:,0] = pts[:,None,None] #None is the same as np.newaxis
arr[:,:,:,1] = pts[None,:,None]
arr[:,:,:,2] = pts[None,None,:]
return arr
def meth2(pts):
lp = len(pts)
N = lp
arr = np.zeros((lp,lp,lp,3))
for i in xrange(0, N):
for j in xrange(0, N):
for k in xrange(0, N):
arr[i,j,k,0] = pts[i]
arr[i,j,k,1] = pts[j]
arr[i,j,k,2] = pts[k]
return arr
pts = range(10)
a1 = meth1(pts)
a2 = meth2(pts)
print np.all(a1 == a2)
NREPEAT = 10000
print timeit.timeit('meth1(pts)','from __main__ import meth1,pts',number=NREPEAT)
print timeit.timeit('meth2(pts)','from __main__ import meth2,pts',number=NREPEAT)
结果:
True
0.873255968094 #my way
11.4249279499 #original
因此,这种新方法也快了一个数量级。我认为以下方法应该有效:
pts = np.array(pts) #Skip if pts is a numpy array already
lp = len(pts)
arr = np.zeros((lp,lp,lp,3))
arr[:,:,:,0] = pts[:,None,None] #None is the same as np.newaxis
arr[:,:,:,1] = pts[None,:,None]
arr[:,:,:,2] = pts[None,None,:]
import numpy as np
N = 10
pts = xrange(0,N)
l = [ [ [ [ pts[i],pts[j],pts[k] ] for k in xrange(0,N) ] for j in xrange(0,N) ] for i in xrange(0,N) ]
x = np.array(l, np.int32)
print x.shape # (10,10,10,3)
快速测试:
import numpy as np
import timeit
def meth1(pts):
pts = np.array(pts) #Skip if pts is a numpy array already
lp = len(pts)
arr = np.zeros((lp,lp,lp,3))
arr[:,:,:,0] = pts[:,None,None] #None is the same as np.newaxis
arr[:,:,:,1] = pts[None,:,None]
arr[:,:,:,2] = pts[None,None,:]
return arr
def meth2(pts):
lp = len(pts)
N = lp
arr = np.zeros((lp,lp,lp,3))
for i in xrange(0, N):
for j in xrange(0, N):
for k in xrange(0, N):
arr[i,j,k,0] = pts[i]
arr[i,j,k,1] = pts[j]
arr[i,j,k,2] = pts[k]
return arr
pts = range(10)
a1 = meth1(pts)
a2 = meth2(pts)
print np.all(a1 == a2)
NREPEAT = 10000
print timeit.timeit('meth1(pts)','from __main__ import meth1,pts',number=NREPEAT)
print timeit.timeit('meth2(pts)','from __main__ import meth2,pts',number=NREPEAT)
结果:
True
0.873255968094 #my way
11.4249279499 #original
因此,这种新方法的速度也快了一个数量级。这可以通过两行完成:
import numpy as np
N = 10
pts = xrange(0,N)
l = [ [ [ [ pts[i],pts[j],pts[k] ] for k in xrange(0,N) ] for j in xrange(0,N) ] for i in xrange(0,N) ]
x = np.array(l, np.int32)
print x.shape # (10,10,10,3)
def meth3(pts):
arrs = np.broadcast_arrays(*np.ix_(pts, pts, pts))
return np.concatenate([a[...,None] for a in arrs], axis=3)
然而,这种方法的速度不如的答案快,因为concatenate
的速度非常慢。不过,他的答案的广义版本的性能也大致相同,并且可以为任何数组集生成您想要的结果(即,包含在n维网格中的n维笛卡尔积)
def meth4(arrs): # or meth4(*arrs) for a simplified interface
arr = np.empty([len(a) for a in arrs] + [len(arrs)])
for i, a in enumerate(np.ix_(*arrs)):
arr[...,i] = a
return arr
这可以接受任何序列,只要它可以转换为numpy数组序列:
>>> meth4([[0, 1], [2, 3]])
array([[[ 0., 2.],
[ 0., 3.]],
[[ 1., 2.],
[ 1., 3.]]])
这种通用性的成本并不太高——对于小型pts
阵列来说,它的速度只有原来的两倍:
>>> (meth4([pts, pts, pts]) == meth1(pts)).all()
True
>>> %timeit meth4([pts, pts, pts])
10000 loops, best of 3: 27.4 us per loop
>>> %timeit meth1(pts)
100000 loops, best of 3: 13.1 us per loop
对于较大的,它实际上要快一点(虽然速度的提高可能是因为我使用了空
而不是零
):
这可以通过两行完成:
def meth3(pts):
arrs = np.broadcast_arrays(*np.ix_(pts, pts, pts))
return np.concatenate([a[...,None] for a in arrs], axis=3)
然而,这种方法的速度不如的答案快,因为concatenate
的速度非常慢。不过,他的答案的广义版本的性能也大致相同,并且可以为任何数组集生成您想要的结果(即,包含在n维网格中的n维笛卡尔积)
def meth4(arrs): # or meth4(*arrs) for a simplified interface
arr = np.empty([len(a) for a in arrs] + [len(arrs)])
for i, a in enumerate(np.ix_(*arrs)):
arr[...,i] = a
return arr
这可以接受任何序列,只要它可以转换为numpy数组序列:
>>> meth4([[0, 1], [2, 3]])
array([[[ 0., 2.],
[ 0., 3.]],
[[ 1., 2.],
[ 1., 3.]]])
这种通用性的成本并不太高——对于小型pts
阵列来说,它的速度只有原来的两倍:
>>> (meth4([pts, pts, pts]) == meth1(pts)).all()
True
>>> %timeit meth4([pts, pts, pts])
10000 loops, best of 3: 27.4 us per loop
>>> %timeit meth1(pts)
100000 loops, best of 3: 13.1 us per loop
对于较大的,它实际上要快一点(虽然速度的提高可能是因为我使用了空
而不是零
):
我不知道
xrange
是可索引的。有点漂亮。我不知道xrange
是可索引的。这是一个很好的回答!请注意,numpy.ix
会更自动地执行上面的一些操作。+1——回答得好!请注意,numpy.ix
可以更自动地执行上面的一些操作。非常好。我总是发现numpy.ix
对我来说有点太密集了,以至于我无法真正地去摸索(尽管我并没有试着把我的脑袋绕得太紧)。一般来说,我会发现构造长度为N的元组更容易,除了“I”(即slice()
)之外,每个元素都填充None
)。我会用它来索引pts
,然后像你一样在LHS上使用省略号。e、 g.idx=tuple(如果i==j else slice()表示xrange(N)中的j,则无);arr[…,i]=pts[idx]
。我也花了一段时间摸索numpy.ix,直到有一天我意外地重新发明了它。但这基本上就是你在上面所做的<代码>九(pts,pts,pts)
只返回元组(pts[:,None,None],pts[None,:,None],pts[None,None,:])
。哦——那么,我想这也让我更容易记住,因为我基本上也重新发明了它。。。现在我更了解您的解决方案(谢谢)。从API的角度来看,我可能会将meth4
定义为defmeth4(*arrs)
。然后将其称为meth4(pts,pts,pts)
,而不是meth4((pts,pts,pts))
。对我来说,这似乎有点干净。是什么阻止了arr[…,:]=np.ix_(*arrs)代替显式for循环工作?(我试过了,但在分配数组元素时出现了一个错误。)@FreddieWitherden,基本答案是np.ix(*arrs)
返回的值不是numpy
数组。它是数组的元组,每个数组都有不同的形状,因此numpy
无法直接使用它。此外,给定ix=np.ix_u(*arrs)
,arr[…,i]=ix[0]
与arr[…,i]=ix[1]
有很大不同,因为ix[0]
和ix[1]
具有不同的形状,因此广播规则的应用也不同。最后,arr[…,:]
和arr[…,:,:,:]
是相同的numpy
不能很好地区分椭圆和切片,所以它无法判断要在哪个轴上运行。非常好。我总是发现numpy.ix
对我来说有点太密集了,以至于我无法真正地去摸索(尽管我并没有试着把我的脑袋绕得太紧)。一般来说,我会发现构造长度为N的元组更容易,除了“I”(即slice()
)之外,每个元素都填充None
)。我会用它来索引pts
,然后像你一样在LHS上使用省略号。e、 g.idx=tuple(如果i==j else slice()表示xrange(N)中的j,则无);arr[…,i]=pts[idx]
。我也花了一段时间摸索numpy.ix,直到有一天我意外地重新发明了它。但这基本上就是你在上面所做的<代码>九(pts,pts,pts)
只返回元组(pts[:,None,None],pts[None,:,None],pts[None,None,:])
。哦——那么,我想这也让我更容易记住,因为我基本上也重新发明了它。。。现在我更了解您的解决方案(谢谢)。从API的角度来看,我可能会将meth4
定义为defmeth4(*arrs)
。然后将其称为meth4(pts,pts,pts)
,而不是meth4((pts,pts,pts))
。对我来说,这似乎有点干净。是什么阻止了arr[…,:]=np.ix_(*arrs)代替显式for循环工作?(我试过了,但在分配数组元素时出错。)@FreddieWitherden,b