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

dam*_*ien 5 python numpy

让我说我有阵列:

a = array((1,2,3,4,5))
indices = array((1,1,1,1))
Run Code Online (Sandbox Code Playgroud)

我执行操作:

a[indices] += 1
Run Code Online (Sandbox Code Playgroud)

结果是

array([1, 3, 3, 4, 5])
Run Code Online (Sandbox Code Playgroud)

换句话说,重复的内容indices被忽略

如果我希望重复项不被忽略,导致:

array([1, 6, 3, 4, 5])
Run Code Online (Sandbox Code Playgroud)

我该怎么办呢?

上面的例子有点微不足道,接下来正是我想要做的事情:

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
Run Code Online (Sandbox Code Playgroud)

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

sig*_*fpe 5

numpyhistogram功能是分散运算。

a += histogram(indices, bins=a.size, range=(0, a.size))[0]

您可能需要小心,因为如果indices包含整数,小的舍入错误可能会导致值最终出现在错误的存储桶中。在这种情况下使用:

a += histogram(indices, bins=a.size, range=(-0.5, a.size-0.5))[0]

将每个索引放入每个 bin 的中心。

更新:这有效。但我建议使用 @Eelco Hoogendoorn 基于的答案numpy.add.at


Jus*_*eel 1

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

for face in self.faces[:,0]:
    self.verts[face] += faceforces
Run Code Online (Sandbox Code Playgroud)

您还可以将 self.faces 制作成一个由 3 个字典组成的数组,其中键对应于脸部,值对应于需要添加的次数。然后你会得到如下代码:

for face in self.faces[0]:
    self.verts[face] += self.faces[0][face]*faceforces
Run Code Online (Sandbox Code Playgroud)

这可能会更快。我确实希望有人能提出更好的方法,因为今天早些时候我在尝试帮助某人加速他们的代码时就想这样做。