NumPy 数组总和减少
NumPy array sum reduce
我有一个包含以下形式的三列的 numpy 数组:
x1 y1 f1
x2 y2 f2
...
xn yn fn
(x,y) 对可能会重复。我需要另一个数组,使每个 (x,y) 对出现一次,对应的第三列是出现在 (x,y) 旁边的所有 f 值的总和。
例如数组
1 2 4.0
1 1 5.0
1 2 3.0
0 1 9.0
会给
0 1 9.0
1 1 5.0
1 2 7.0
行的顺序无关紧要。在 Python 中最快的方法是什么?
谢谢!
这将是解决问题的一种方法 -
import numpy as np
# Input array
A = np.array([[1,2,4.0],
[1,1,5.0],
[1,2,3.0],
[0,1,9.0]])
# Extract xy columns
xy = A[:,0:2]
# Perform lex sort and get the sorted indices and xy pairs
sorted_idx = np.lexsort(xy.T)
sorted_xy = xy[sorted_idx,:]
# Differentiation along rows for sorted array
df1 = np.diff(sorted_xy,axis=0)
df2 = np.append([True],np.any(df1!=0,1),0)
# OR df2 = np.append([True],np.logical_or(df1[:,0]!=0,df1[:,1]!=0),0)
# OR df2 = np.append([True],np.dot(df1!=0,[True,True]),0)
# Get unique sorted labels
sorted_labels = df2.cumsum(0)-1
# Get labels
labels = np.zeros_like(sorted_idx)
labels[sorted_idx] = sorted_labels
# Get unique indices
unq_idx = sorted_idx[df2]
# Get counts and unique rows and setup output array
counts = np.bincount(labels, weights=A[:,2])
unq_rows = xy[unq_idx,:]
out = np.append(unq_rows,counts.ravel()[:,None],1)
输入和输出-
In [169]: A
Out[169]:
array([[ 1., 2., 4.],
[ 1., 1., 5.],
[ 1., 2., 3.],
[ 0., 1., 9.]])
In [170]: out
Out[170]:
array([[ 0., 1., 9.],
[ 1., 1., 5.],
[ 1., 2., 7.]])
当然很容易在 Python 中完成:
arr = np.array([[1,2,4.0],
[1,1,5.0],
[1,2,3.0],
[0,1,9.0]])
d={}
for x, y, z in arr:
d.setdefault((x,y), 0)
d[x,y]+=z
>>> d
{(1.0, 2.0): 7.0, (0.0, 1.0): 9.0, (1.0, 1.0): 5.0}
然后翻译回 numpy:
>>> np.array([[x,y,d[(x,y)]] for x,y in d.keys()])
array([[ 1., 2., 7.],
[ 0., 1., 9.],
[ 1., 1., 5.]])
感谢@hpaulj,终于找到了最简单的解决方案。如果 d 包含 3 列数据:
ind =d[0:2].astype(int)
x = zeros(shape=(N,N))
add.at(x,list(ind),d[2])
这个解决方案假设前两列中的 (x,y) 索引是整数并且小于 N。这是我需要的并且应该在 post 中提到的。
编辑:请注意,上述解决方案生成了一个稀疏矩阵,其总和值位于矩阵内的 (x,y) 位置。
如果您有 scipy
,稀疏模块会执行这种加法 - 再次针对前两列为整数的数组 - 即。索引。
from scipy import sparse
M = sparse.csr_matrix((d[:,0], (d[:,1],d[:,2])))
M = M.tocoo() # there may be a short cut to this csr coo round trip
x = np.column_stack([M.row, M.col, M.data]) # needs testing
为了方便构造某些类型的线性代数矩阵,csr
稀疏数组格式对具有重复索引的值求和。它是在编译代码中实现的,因此应该相当快。但是将数据放入 M
然后再取出可能会减慢速度。
(ps。我没有测试过这个脚本,因为我是在没有 scipy
的机器上写的。
我有一个包含以下形式的三列的 numpy 数组:
x1 y1 f1
x2 y2 f2
...
xn yn fn
(x,y) 对可能会重复。我需要另一个数组,使每个 (x,y) 对出现一次,对应的第三列是出现在 (x,y) 旁边的所有 f 值的总和。
例如数组
1 2 4.0
1 1 5.0
1 2 3.0
0 1 9.0
会给
0 1 9.0
1 1 5.0
1 2 7.0
行的顺序无关紧要。在 Python 中最快的方法是什么?
谢谢!
这将是解决问题的一种方法 -
import numpy as np
# Input array
A = np.array([[1,2,4.0],
[1,1,5.0],
[1,2,3.0],
[0,1,9.0]])
# Extract xy columns
xy = A[:,0:2]
# Perform lex sort and get the sorted indices and xy pairs
sorted_idx = np.lexsort(xy.T)
sorted_xy = xy[sorted_idx,:]
# Differentiation along rows for sorted array
df1 = np.diff(sorted_xy,axis=0)
df2 = np.append([True],np.any(df1!=0,1),0)
# OR df2 = np.append([True],np.logical_or(df1[:,0]!=0,df1[:,1]!=0),0)
# OR df2 = np.append([True],np.dot(df1!=0,[True,True]),0)
# Get unique sorted labels
sorted_labels = df2.cumsum(0)-1
# Get labels
labels = np.zeros_like(sorted_idx)
labels[sorted_idx] = sorted_labels
# Get unique indices
unq_idx = sorted_idx[df2]
# Get counts and unique rows and setup output array
counts = np.bincount(labels, weights=A[:,2])
unq_rows = xy[unq_idx,:]
out = np.append(unq_rows,counts.ravel()[:,None],1)
输入和输出-
In [169]: A
Out[169]:
array([[ 1., 2., 4.],
[ 1., 1., 5.],
[ 1., 2., 3.],
[ 0., 1., 9.]])
In [170]: out
Out[170]:
array([[ 0., 1., 9.],
[ 1., 1., 5.],
[ 1., 2., 7.]])
当然很容易在 Python 中完成:
arr = np.array([[1,2,4.0],
[1,1,5.0],
[1,2,3.0],
[0,1,9.0]])
d={}
for x, y, z in arr:
d.setdefault((x,y), 0)
d[x,y]+=z
>>> d
{(1.0, 2.0): 7.0, (0.0, 1.0): 9.0, (1.0, 1.0): 5.0}
然后翻译回 numpy:
>>> np.array([[x,y,d[(x,y)]] for x,y in d.keys()])
array([[ 1., 2., 7.],
[ 0., 1., 9.],
[ 1., 1., 5.]])
感谢@hpaulj,终于找到了最简单的解决方案。如果 d 包含 3 列数据:
ind =d[0:2].astype(int)
x = zeros(shape=(N,N))
add.at(x,list(ind),d[2])
这个解决方案假设前两列中的 (x,y) 索引是整数并且小于 N。这是我需要的并且应该在 post 中提到的。
编辑:请注意,上述解决方案生成了一个稀疏矩阵,其总和值位于矩阵内的 (x,y) 位置。
如果您有 scipy
,稀疏模块会执行这种加法 - 再次针对前两列为整数的数组 - 即。索引。
from scipy import sparse
M = sparse.csr_matrix((d[:,0], (d[:,1],d[:,2])))
M = M.tocoo() # there may be a short cut to this csr coo round trip
x = np.column_stack([M.row, M.col, M.data]) # needs testing
为了方便构造某些类型的线性代数矩阵,csr
稀疏数组格式对具有重复索引的值求和。它是在编译代码中实现的,因此应该相当快。但是将数据放入 M
然后再取出可能会减慢速度。
(ps。我没有测试过这个脚本,因为我是在没有 scipy
的机器上写的。