【问题标题】:Create a numpy matrix with elements as a function of indices创建一个 numpy 矩阵,其中元素作为索引的函数
【发布时间】:2011-09-09 10:17:24
【问题描述】:

如何创建一个 numpy 矩阵,其元素是其索引的函数? 比如一个乘法表:a[i,j] = i*j

Un-numpy 和 un-pythonic 将创建一个零数组,然后循环。

毫无疑问,有更好的方法可以做到这一点,而无需循环。

不过,最好直接创建矩阵。

【问题讨论】:

    标签: python matrix numpy


    【解决方案1】:

    这是一种方法:

    >>> indices = numpy.indices((5, 5))
    >>> a = indices[0] * indices[1]
    >>> a
    array([[ 0,  0,  0,  0,  0],
           [ 0,  1,  2,  3,  4],
           [ 0,  2,  4,  6,  8],
           [ 0,  3,  6,  9, 12],
           [ 0,  4,  8, 12, 16]])
    

    为了进一步解释,numpy.indices((5, 5)) 生成两个数组,其中包含一个 5x5 数组的 x 和 y 索引,如下所示:

    >>> numpy.indices((5, 5))
    array([[[0, 0, 0, 0, 0],
            [1, 1, 1, 1, 1],
            [2, 2, 2, 2, 2],
            [3, 3, 3, 3, 3],
            [4, 4, 4, 4, 4]],
    
           [[0, 1, 2, 3, 4],
            [0, 1, 2, 3, 4],
            [0, 1, 2, 3, 4],
            [0, 1, 2, 3, 4],
            [0, 1, 2, 3, 4]]])
    

    当你将这两个数组相乘时,numpy 将两个数组在每个位置的值相乘并返回结果。

    【讨论】:

    • 对于 a[i,j] = f(i,j) 是否可以推广?
    • 如果f 的表达式是矢量化的。
    【解决方案2】:

    我现在不在我的 python 上,但是这个有用吗?

    array( [ [ i*j for j in xrange(5)] for i in xrange(5)] )
    

    【讨论】:

    • 确实如此... array() 看似强大!
    • 请注意,如果你使用它,你必须小心不要执行np.array(( ( i*j for j in xrange(4096)) for i in xrange(4096)) ),因为它的结果是出乎意料的。 jim-holmstroem.github.io/numpy/2014/11/23/…
    • 吉姆,我无法理解您的链接。我认为您是在警告不要将生成器表达式传递给 numpy? stackoverflow.com/q/367565/770038 也涵盖了这一点。
    【解决方案3】:

    只是想补充一点,@Senderle 的响应可以推广到任何功能和维度:

    dims = (3,3,3) #i,j,k
    ii = np.indices(dims)
    

    然后您可以将a[i,j,k] = i*j*k 计算为

    a = np.prod(ii,axis=0)
    

    a[i,j,k] = (i-1)*j*k:

    a = (ii[0,...]-1)*ii[1,...]*ii[2,...]
    

    【讨论】:

      【解决方案4】:

      对于乘法

      np.multiply.outer(np.arange(5), np.arange(5))  # a_ij = i * j
      

      一般来说

      np.frompyfunc(
          lambda i, j: f(i, j), 2, 1
      ).outer(
          np.arange(5),
          np.arange(5),
      ).astype(np.float64)  # a_ij = f(i, j)
      

      基本上,您通过np.frompyfunc 创建一个np.ufunc,然后使用索引创建outer

      编辑

      不同解决方案之间的速度比较。

      小矩阵:

      Eyy![1]: %timeit np.multiply.outer(np.arange(5), np.arange(5))
      100000 loops, best of 3: 4.97 µs per loop
      
      Eyy![2]: %timeit np.array( [ [ i*j for j in xrange(5)] for i in xrange(5)] )
      100000 loops, best of 3: 5.51 µs per loop
      
      Eyy![3]: %timeit indices = np.indices((5, 5)); indices[0] * indices[1]
      100000 loops, best of 3: 16.1 µs per loop
      

      更大的矩阵:

      Eyy![4]: %timeit np.multiply.outer(np.arange(4096), np.arange(4096))
      10 loops, best of 3: 62.4 ms per loop
      
      Eyy![5]: %timeit indices = np.indices((4096, 4096)); indices[0] * indices[1]
      10 loops, best of 3: 165 ms per loop
      
      Eyy![6]: %timeit np.array( [ [ i*j for j in xrange(4096)] for i in xrange(4096)] )
      1 loops, best of 3: 1.39 s per loop
      

      【讨论】:

        【解决方案5】:

        一个通用的解决方案是使用np.fromfunction()

        来自文档:

        numpy.fromfunction(function, shape, **kwargs)

        通过在每个坐标上执行一个函数来构造一个数组。这 因此,结果数组在坐标 (x, y, z)。

        下面的行应该提供所需的矩阵。

        numpy.fromfunction(lambda i, j: i*j, (5,5))

        输出:

        array([[  0.,   0.,   0.,   0.,   0.],
               [  0.,   1.,   2.,   3.,   4.],
               [  0.,   2.,   4.,   6.,   8.],
               [  0.,   3.,   6.,   9.,  12.],
               [  0.,   4.,   8.,  12.,  16.]])
        

        函数的第一个参数是对每个坐标执行的可调用对象。如果foo 是作为第一个参数传递的函数,则foo(i,j) 将是(i,j) 的值。这也适用于更高的维度。坐标数组的形状可以通过shape参数修改。

        【讨论】:

        • 这不适用于涉及复杂操作/逻辑的功能。这是因为numpy 不会为每个坐标调用您的函数,而是将 x 和 y 坐标作为数组传递一次。例如,如果你想使用函数构造一个矩阵:lambda x,y: 2*x if x > y else y/2。在这种情况下,朴素的方法是唯一的选择,这是真的吗?
        • @AdityaSriram,您可以使用与天真的方法一起使用的函数作为可调用对象。但是,是的,fromfunction() 的唯一优势是它将生成索引列表,而不是用户显式生成它。
        猜你喜欢
        • 2021-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-20
        相关资源
        最近更新 更多