【问题标题】:NumPy array sum reduceNumPy 数组总和减少
【发布时间】:2015-06-19 03:44:00
【问题描述】:

我有一个包含三列形式的 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 中执行此操作的最快方法是什么?

谢谢!

【问题讨论】:

标签: python performance numpy sum reduce


【解决方案1】:

这将是解决它的一种方法 -

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.]])

【讨论】:

    【解决方案2】:

    感谢@hpaulj,终于找到了最简单的解决方案。如果 d 包含 3 列数据:

    ind =d[0:2].astype(int)
    x = zeros(shape=(N,N))
    add.at(x,list(ind),d[2])
    

    此解决方案假定前两列中的 (x,y) 索引是整数且小于 N。这是我需要并且应该在帖子中提到的。

    编辑:请注意,上述解决方案会生成一个稀疏矩阵,其和值位于矩阵内 (x,y) 的位置。

    【讨论】:

    • 看看一些运行时测试会很有趣吗?
    • 你确定这行得通吗?我用问题中列出的输入进行了尝试,并得到了一些其他意想不到的值。我为此假设N = 3
    • 这不会在问题的输出附近产生任何东西。它产生一个稀疏矩阵,其和在 x、y 坐标处。
    • @Colt45,这是正确的。然而,从稀疏矩阵很容易恢复所需的输出形式。不过,对于大 N 来说,这可能不是最佳选择。我完全承认我的问题并不清楚。
    【解决方案3】:

    用 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.]])
    

    【讨论】:

    • 不错的字典解决方案,但是它涉及到一堆 for 循环
    【解决方案4】:

    如果您有scipy,稀疏模块会执行这种加法 - 再次针对第 2 列是整数的数组 - 即。索引。

    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的机器上写这个的)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2021-05-06
      • 1970-01-01
      • 2022-01-13
      • 2019-11-14
      • 2014-01-03
      • 1970-01-01
      相关资源
      最近更新 更多