【问题标题】:how to split numpy array and perform certain actions on split arrays [Python]如何拆分 numpy 数组并对拆分数组执行某些操作 [Python]
【发布时间】:2017-06-14 16:38:00
【问题描述】:

之前只问过这个问题的一部分 ([1][2]) ,它解释了如何拆分 numpy 数组。我对 Python 很陌生。我有一个包含 262144 个项目的数组,想将其拆分为长度为 512 的小数组,分别对它们进行排序并总结它们的前五个值,但我不确定如何超出这条线:

np.array_split(vector, 512)

如何调用和分析每个数组?继续使用 numpy 数组是个好主意,还是应该恢复使用字典?

【问题讨论】:

    标签: python arrays numpy split


    【解决方案1】:

    这样的拆分不是一个有效的解决方案,相反我们可以重塑,这有效地将子数组创建为2D 数组的行。这些将是输入数组的视图,因此那里不需要额外的内存。然后,我们将获取 argsort 索引并选择每行的前五个索引,最后将它们相加得到所需的输出。

    因此,我们会有这样的实现 -

    N = 512 # Number of elements in each split array
    M = 5   # Number of elements in each subarray for sorting and summing
    
    b = a.reshape(-1,N)
    out = b[np.arange(b.shape[0])[:,None], b.argsort(1)[:,:M]].sum(1)
    

    分步运行示例 -

    In [217]: a   # Input array
    Out[217]: array([45, 19, 71, 53, 20, 33, 31, 20, 41, 19, 38, 31, 86, 34])
    
    In [218]: N = 7 # 512 for original case, 7 for sample
    
    In [219]: M = 5
    
    # Reshape into M rows 2D array
    In [220]: b = a.reshape(-1,N)
    
    In [224]: b
    Out[224]: 
    array([[45, 19, 71, 53, 20, 33, 31],
           [20, 41, 19, 38, 31, 86, 34]])
    
    # Get argsort indices per row
    In [225]: b.argsort(1)
    Out[225]: 
    array([[1, 4, 6, 5, 0, 3, 2],
           [2, 0, 4, 6, 3, 1, 5]])
    
    # Select first M ones
    In [226]: b.argsort(1)[:,:M]
    Out[226]: 
    array([[1, 4, 6, 5, 0],
           [2, 0, 4, 6, 3]])
    
    # Use fancy-indexing to select those M ones per row
    In [227]: b[np.arange(b.shape[0])[:,None], b.argsort(1)[:,:M]]
    Out[227]: 
    array([[19, 20, 31, 33, 45],
           [19, 20, 31, 34, 38]])
    
    # Finally sum along each row
    In [228]: b[np.arange(b.shape[0])[:,None], b.argsort(1)[:,:M]].sum(1)
    Out[228]: array([148, 142])
    

    np.argpartition 的性能提升 -

    out = b[np.arange(b.shape[0])[:,None], np.argpartition(b,M,axis=1)[:,:M]].sum(1)
    

    运行时测试-

    In [236]: a = np.random.randint(11,99,(512*512))
    
    In [237]: N = 512
    
    In [238]: M = 5
    
    In [239]: b = a.reshape(-1,N)
    
    In [240]: %timeit b[np.arange(b.shape[0])[:,None], b.argsort(1)[:,:M]].sum(1)
    100 loops, best of 3: 14.2 ms per loop
    
    In [241]: %timeit b[np.arange(b.shape[0])[:,None], \
                    np.argpartition(b,M,axis=1)[:,:M]].sum(1)
    100 loops, best of 3: 3.57 ms per loop
    

    【讨论】:

    • 很好的答案。谢谢!!
    • 正在考虑这样的事情,但使用索引切片,这要好得多!
    【解决方案2】:

    做你想做的事的更详细的版本

    import numpy as np
    from numpy.testing.utils import assert_array_equal
    
    vector = np.random.rand(262144)
    
    splits = np.array_split(vector, 512)
    
    sums = []
    for split in splits:
       # sort it
       split.sort()
       # sublist
       subSplit = split[:5]
       #build sum
       splitSum = sum(subSplit)
       # add to new list
       sums.append(splitSum)
    
    print np.array(sums).shape
    

    与@Divakar 的解决方案的输出相同

    【讨论】:

    • Python 是一种单行语言,所以@Divakar 的答案更好:)
    • 为什么要将拆分列表变成数组?只需在列表上循环即可。
    猜你喜欢
    • 1970-01-01
    • 2015-04-14
    • 2019-05-08
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2014-01-04
    • 2011-06-17
    • 2013-04-19
    相关资源
    最近更新 更多