【问题标题】:How do I telescope the columns of a numpy array?如何伸缩 numpy 数组的列?
【发布时间】:2016-08-26 14:08:26
【问题描述】:

我有一个 numpy 数组,想根据第一行“望远镜”这些值。一个例子是最好的描述方式

起始数组:

9 9 8 7 7 7 6 
1 2 3 4 5 6 3 
3 4 5 6 7 6 3
5 6 7 8 9 6 4

想要的输出数组:

9 8 7 6
3  3  15  3
7  5  19  3
11 7  23  4

这个想法是唯一化顶行并沿顶行中的值分组的后续行对值进行求和。第一行将被排序,数组大约有 2000 个单元格宽和 200,000 个单元格长。顶行中可以有任意数量的连续相同数字。我目前的技巧是这样的(示例中的顶行标签略有不同,我正在打印到屏幕而不是创建最终数组来检查输出。计划是堆叠输出以生成输出数组)

import numpy as N
kk=N.array([[90,90,85,80,80,80,70],[1,2,3,4,5,6,3],[3,4,5,6,7,6,3],[5,6,7,8,9,6,4]])
ll=kk[:,0]
for i in range(1,len(kk[0])):
    if kk[0][i]==kk[0][i-1]:
        ll=ll+kk[:,i]
    elif kk[0][i]!=kk[0][i-1]: 
        print "sum=", ll, i,kk[0][i],kk[0][i-1]
        ll=kk[:,i]

有两个缺陷。主要的是它没有处理最后一列,我不明白为什么。次要的一点是它也在对第一行求和。很明显,为什么会发生这个小问题。我怀疑我可以勉强解决那个问题,但未能处理最后一列让我沮丧了一段时间,我非常感谢任何处理它的建议。

感谢您的帮助

【问题讨论】:

    标签: python arrays numpy indexing slice


    【解决方案1】:

    如果您有 200,000 行,Python 循环可能会非常慢。使用 NumPy,您可以使用 np.add.reduceat 对该操作进行矢量化处理,但您首先需要创建一个数组,其中包含第一行中每组重复条目的第一项的索引:

    mask = np.concatenate(([True], kk[0, 1:] != kk[0, :-1]))
    indices, = np.nonzero(mask)
    

    然后您可以通过使用 mask 布尔数组对其进行索引来获取第一行:

    >>> kk[0, mask]
    array([90, 85, 80, 70])
    

    以及使用reduceatindices 的数组的其余部分:

    >>> np.add.reduceat(kk[1:], indices, axis=1)
    array([[ 3,  3, 15,  3],
           [ 7,  5, 19,  3],
           [11,  7, 23,  4]])
    

    假设您的原始数组是默认整数类型,您可以通过执行以下操作来组装您的数组:

    out = np.empty((kk.shape[0], len(indices)), dtype=kk.dtype)
    out[0] = kk[0, mask]
    np.add.reduceat(kk[1:], indices, axis=1, out=out[1:])
    
    >>> out
    array([[90, 85, 80, 70],
           [ 3,  3, 15,  3],
           [ 7,  5, 19,  3],
           [11,  7, 23,  4]])
    

    【讨论】:

      【解决方案2】:

      你应该使用 numpy 的独特功能

      import numpy as np
      
      a = np.array([[90,90,85,80,80,80,70],[1,2,3,4,5,6,3],[3,4,5,6,7,6,3],[5,6,7,8,9,6,4]])
      
      u, v = np.unique(a[0], return_inverse=True)
      
      output = np.zeros((a.shape[0], u.shape[0]))
      output[0] = u.copy()
      for i in xrange(u.shape[0]):
          pos = np.where(v==i)[0]
          output[1:,i] = np.sum(a[1:,pos], axis=1)
      

      您应该注意到u 将从低到高排序。如果你想要它从最高到最低,你必须这样做

      output = output[:,::-1]
      

      在最后。

      【讨论】:

        【解决方案3】:

        您可以使用groupby:

        from itertools import groupby
        
        import numpy as N
        
        kk=N.array([[90,90,85,80,80,80,70],[1,2,3,4,5,6,3],[3,4,5,6,7,6,3],[5,6,7,8,9,6,4]])
        
        keys = kk[0]
        vals = kk[1:]
        uniq = map(lambda x: x[0], groupby(keys))
        new = [uniq]
        for row in vals:
            new.append([sum(map(lambda x: x[1], group)) for _, group in groupby(zip(keys, row), lambda x: x[0])])
        
        print N.array(new)
        

        提供输出:

        [[90 85 80 70]
         [ 3  3 15  3]
         [ 7  5 19  3]
         [11  7 23  4]]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-31
          • 1970-01-01
          • 1970-01-01
          • 2011-05-12
          • 2019-11-24
          • 2011-11-23
          • 1970-01-01
          • 2015-07-03
          相关资源
          最近更新 更多