Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在numpy中执行分散/聚集操作_Python_Numpy - Fatal编程技术网

Python 如何在numpy中执行分散/聚集操作

Python 如何在numpy中执行分散/聚集操作,python,numpy,Python,Numpy,假设我有数组: a = array((1,2,3,4,5)) indices = array((1,1,1,1)) 我执行以下操作: a[indices] += 1 结果是 array([1, 3, 3, 4, 5]) 换句话说,索引中的重复项将被忽略 如果我不想忽略重复项,导致: array([1, 6, 3, 4, 5]) 我该怎么办 上面的例子有些琐碎,下面正是我想要做的: def inflate(self,pressure): faceforces = pressure

假设我有数组:

a = array((1,2,3,4,5))
indices = array((1,1,1,1))
我执行以下操作:

a[indices] += 1
结果是

array([1, 3, 3, 4, 5])
换句话说,
索引
中的重复项将被忽略

如果我不想忽略重复项,导致:

array([1, 6, 3, 4, 5])
我该怎么办

上面的例子有些琐碎,下面正是我想要做的:

def inflate(self,pressure):
    faceforces = pressure * cross(self.verts[self.faces[:,1]]-self.verts[self.faces[:,0]], self.verts[self.faces[:,2]]-self.verts[self.faces[:,0]])
    self.verts[self.faces[:,0]] += faceforces
    self.verts[self.faces[:,1]] += faceforces
    self.verts[self.faces[:,2]] += faceforces

def constrain_lengths(self):
    vectors = self.verts[self.constraints[:,1]] - self.verts[self.constraints[:,0]]
    lengths = sqrt(sum(square(vectors), axis=1))
    correction = 0.5 * (vectors.T * (1 - (self.restlengths / lengths))).T
    self.verts[self.constraints[:,0]] += correction
    self.verts[self.constraints[:,1]] -= correction

def compute_normals(self):
    facenormals = cross(self.verts[self.faces[:,1]]-self.verts[self.faces[:,0]], self.verts[self.faces[:,2]]-self.verts[self.faces[:,0]])
    self.normals.fill(0)
    self.normals[self.faces[:,0]] += facenormals
    self.normals[self.faces[:,1]] += facenormals
    self.normals[self.faces[:,2]] += facenormals
    lengths = sqrt(sum(square(self.normals), axis=1))
    self.normals = (self.normals.T / lengths).T

由于在索引分配操作中忽略了重复项,我得到了一些非常错误的结果。

我不知道有什么方法比以下方法更快:

for face in self.faces[:,0]:
    self.verts[face] += faceforces
您还可以将self.faces制作成一个包含3个字典的数组,其中键对应于面,值对应于需要添加的次数。然后您会得到如下代码:

for face in self.faces[0]:
    self.verts[face] += self.faces[0][face]*faceforces

这可能更快。我真的希望有人能想出一个更好的方法,因为我想在今天早些时候帮助别人加速他们的代码时这样做。

numpy
直方图
函数是一个分散操作

a+=柱状图(索引、箱子=a.size,范围=(0,a.size))[0]

您可能需要注意一些,因为如果
索引
包含整数,小的舍入错误可能会导致值最终进入错误的存储区。在这种情况下,请使用:

a+=直方图(指数、仓位=a.size,范围=(-0.5,a.size-0.5))[0]

将每个索引放入每个箱子的中心


更新:这是有效的。但我建议使用@Eelco Hoogendoorn基于
numpy.add.at
的答案来回答派对,但考虑到这种操作的普遍性,以及它似乎仍然不是标准numpy的一部分,我将我的解决方案放在这里以供参考:

def scatter(rowidx, vals, target):
    """compute target[rowidx] += vals, allowing for repeated values in rowidx"""
    rowidx = np.ravel(rowidx)
    vals   = np.ravel(vals)
    cols   = len(vals)
    data   = np.ones(cols)
    colidx = np.arange(cols)
    rows   = len(target)
    from scipy.sparse import coo_matrix
    M = coo_matrix((data,(rowidx,colidx)), shape=(rows, cols))
    target += M*vals
def gather(idx, vals):
    """for symmetry with scatter"""
    return vals[idx]
对于初学者来说,numpy中的自定义C例程的速度可以轻松地提高一倍,从而消除了多余的1分配和与1的乘法,但是与python中的循环相比,它在性能上有很大的不同

除了性能方面的考虑外,使用分散操作在风格上更符合其他numpy矢量化代码,而不是在代码中混搭一些for循环

编辑:

好吧,忘掉上面的事。从最新的1.8版本开始,numpy以最佳效率直接支持分散操作

def scatter(idx, vals, target):
    """target[idx] += vals, but allowing for repeats in idx"""
    np.add.at(target, idx.ravel(), vals.ravel())