【问题标题】:Make opperations with the elements of an array without a for loop在没有 for 循环的情况下对数组元素进行操作
【发布时间】:2021-05-13 11:12:51
【问题描述】:

我有一个问题,我需要将数组的一个元素分别与该元素和具有较高索引的元素相加。我用一个 for 循环完成了这个,比如:

sumtot = np.array([])
for j in range(0,len(matpos)-1):
    sum = matpos[j] + matpos[j+1:]
    sumtot = np.append(sumtot, sum)

但这需要大量的计算时间,因为数组matpos 是一个非常大的数组,所以我想是否有办法在没有for 循环的情况下做到这一点。

一个简单的例子是:

-输入:

matpos = np.array([0, 1, 2, 3])

-输出

sumtot = np.array([1, 2, 3, 3, 4, 5])

这是[0+1, 0+2, 0+3, 1+2, 1+3, 2+3]

非常感谢大家!

【问题讨论】:

  • 循环的意义何在?您没有累积结果,因此您丢弃了早期迭代的所有总和。
  • 对不起,我没有添加那部分代码,我必须积累结果,让我编辑它。谢谢!
  • 请显示输入输出示例...
  • 在反向数组上看起来像 np.cumsum。或者使用列表,使用itertools.accumulate(同样在反向列表中)。
  • @hpaulj。我开始写了,但 OP 实际上并没有对数组的位求和

标签: python arrays python-3.x numpy optimization


【解决方案1】:

要获得您想要的数组,您可以使用 np.triu_indices 之类的东西并进行一些额外的操作:

r, c = np.triu_indices(len(matpos), 1)
totsum = matpos[r] + matpos[c]

这可能是你所能得到的最清晰的。如果你想要一个单行,你可以堆叠索引并将结果相加:

totsum = matpos[np.stack(np.triu_indices(len(matpos), 1))].sum(0)

请注意,这些术语的总和如下:

 [matpos[0], matpos[0], matpos[0], ...] + [matpos[1], matpos[2], matpos[3], ...]
 [matpos[1], matpos[1], ...] + [matpos[2], matpos[3], ...]
 [matpos[2], ...] + [matpos[3], ...]

选择的索引和重复次数完全对应triu_indices的结果(列减一),它返回矩阵上三角形的索引。

另一种表述:

r, c = np.triu_indices(len(matpos) - 1)
totsum = matpos[r] + matpos[c + 1]

或

totsum = matpos[np.stack(np.triu_indices(len(matpos) - 1), -1) + [0, 1]].sum(1)

【讨论】:

    【解决方案2】:

    您确实应该包含一个示例运行 - 这样我们就可以看到您的代码产生了什么,而无需自己运行它。

    In [85]: matpos = np.arange(10)
    In [86]: sumtot = np.array([])
        ...: for j in range(0,len(matpos)-1):
        ...:     sum = matpos[j] + matpos[j+1:]
        ...:     sumtot = np.append(sumtot, sum)
        ...: 
    In [87]: sumtot
    Out[87]: 
    array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.,  3.,  4.,  5.,  6.,
            7.,  8.,  9., 10.,  5.,  6.,  7.,  8.,  9., 10., 11.,  7.,  8.,
            9., 10., 11., 12.,  9., 10., 11., 12., 13., 11., 12., 13., 14.,
           13., 14., 15., 15., 16., 17.])
    

    但这并不是特别有指导意义。另外np.append 比列表追加慢。

    所以让我们使用列表:

    In [88]: sumtot = []
        ...: for j in range(0,len(matpos)-1):
        ...:     sum = matpos[j] + matpos[j+1:]
        ...:     sumtot.append(sum)
        ...: 
        ...: 
    In [89]: sumtot
    Out[89]: 
    [array([1, 2, 3, 4, 5, 6, 7, 8, 9]),
     array([ 3,  4,  5,  6,  7,  8,  9, 10]),
     array([ 5,  6,  7,  8,  9, 10, 11]),
     array([ 7,  8,  9, 10, 11, 12]),
     array([ 9, 10, 11, 12, 13]),
     array([11, 12, 13, 14]),
     array([13, 14, 15]),
     array([15, 16]),
     array([17])]
    

    这样可以更好地了解您在做什么 - 并不是说​​它看起来特别合乎逻辑:)

    或者要得到一个平面列表,使用extend:

    In [90]: sumtot = []
        ...: for j in range(0,len(matpos)-1):
        ...:     sum = matpos[j] + matpos[j+1:]
        ...:     sumtot.extend(sum)
        ...: 
    In [91]: sumtot
    Out[91]: 
    [1,
     2,
     3,
     ...
     16,
     17]
    

    或者为了更漂亮的显示:

    In [92]: np.array(sumtot)
    Out[92]: 
    array([ 1,  2,  3,  4,  5,  6,  7,  8,  9,  3,  4,  5,  6,  7,  8,  9, 10,
            5,  6,  7,  8,  9, 10, 11,  7,  8,  9, 10, 11, 12,  9, 10, 11, 12,
           13, 11, 12, 13, 14, 13, 14, 15, 15, 16, 17])
    

    我怀疑这个列表扩展版本和我们得到的一样好。 [89] 中的参差不齐的列表表明“纯”numpy 解决方案不太可能,或者充其量是复杂的。

    编辑

    用你的新例子:

    In [93]: matpos = np.array([0, 1, 2, 3])
    ...
    In [96]: sumtot = []
        ...: for j in range(0,len(matpos)-1):
        ...:     sum = matpos[j] + matpos[j+1:]
        ...:     sumtot.append(sum)
        ...: 
        ...: 
    In [97]: sumtot
    Out[97]: [array([1, 2, 3]), array([3, 4]), array([5])]
    

    triu:

    另一个答案使用triu。

    让我们实验一下:

    In [98]: matpos[:,None]+matpos
    Out[98]: 
    array([[0, 1, 2, 3],
           [1, 2, 3, 4],
           [2, 3, 4, 5],
           [3, 4, 5, 6]])
    In [100]: np.tril(__,-1)
    Out[100]: 
    array([[0, 0, 0, 0],
           [1, 0, 0, 0],
           [2, 3, 0, 0],
           [3, 4, 5, 0]])
    

    对于更大的例子:

    In [101]: matpos = np.arange(10)
    In [102]: matpos[:,None]+matpos
    Out[102]: 
    array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
           [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
           [ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
           [ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12],
           [ 4,  5,  6,  7,  8,  9, 10, 11, 12, 13],
           [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
           [ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
           [ 7,  8,  9, 10, 11, 12, 13, 14, 15, 16],
           [ 8,  9, 10, 11, 12, 13, 14, 15, 16, 17],
           [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]])
    In [103]: np.tril(_,-1)
    Out[103]: 
    array([[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
           [ 1,  0,  0,  0,  0,  0,  0,  0,  0,  0],
           [ 2,  3,  0,  0,  0,  0,  0,  0,  0,  0],
           [ 3,  4,  5,  0,  0,  0,  0,  0,  0,  0],
           [ 4,  5,  6,  7,  0,  0,  0,  0,  0,  0],
           [ 5,  6,  7,  8,  9,  0,  0,  0,  0,  0],
           [ 6,  7,  8,  9, 10, 11,  0,  0,  0,  0],
           [ 7,  8,  9, 10, 11, 12, 13,  0,  0,  0],
           [ 8,  9, 10, 11, 12, 13, 14, 15,  0,  0],
           [ 9, 10, 11, 12, 13, 14, 15, 16, 17,  0]])
    

    所以非零值匹配。

    并使用triu_indices提取值:

    In [112]: idx = np.triu_indices_from(Out[102],1)
    In [113]: Out[102][idx]
    Out[113]: 
    array([ 1,  2,  3,  4,  5,  6,  7,  8,  9,  3,  4,  5,  6,  7,  8,  9, 10,
            5,  6,  7,  8,  9, 10, 11,  7,  8,  9, 10, 11, 12,  9, 10, 11, 12,
           13, 11, 12, 13, 14, 13, 14, 15, 15, 16, 17])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 2022-01-12
      • 2013-02-16
      • 1970-01-01
      • 2013-10-24
      • 2021-11-18
      • 1970-01-01
      相关资源
      最近更新 更多