将数组元素的所有组合在numpy中相乘

时间:2023-01-04 21:23:08

Note: I am not interested in answers of the form 'just do it using for loops' or so, I want to do it the numpyish way.

注意:我对“用for循环来做”之类的形式的答案不感兴趣,所以我想用numpyish的方式来做。

Im a beginner in Python and I want to do the following using numpy ndarray's: Given a sequence of numbers t and another sequence of numbers b, for every t[i] I want to compute the list t[i]*b and store that as a new row in a final array. Example:

我是Python的初学者,我想使用numpy ndarray的:给定一个数字t序列和另一个数字b序列,对于每个t[I],我想计算列表t[I]*b,并将其作为一个新的行存储在最终的数组中。例子:

t = [3,4]
b = [1,2,3,4]

then the outcome should be some form of list encoding

那么结果应该是某种形式的列表编码

[
  [3,6,9,12], # 3 * the array of b's
  [4,8,12,16]   # 4 * the array of b's
]

In a program I saw recently, this worked out perfectly but when I want to do it by myself, it raises an error: Running

在我最近看到的一个程序中,这种方法非常有效,但是当我想自己做的时候,它会产生一个错误:运行

import numpy

t = numpy.linspace(3,4,2)[:, None]
t = t.T

# filled with some garbage numbers
b = numpy.ndarray(shape=(4,1), dtype=numpy.float64, order='C')

res = numpy.dot(t,b)

in python (version 3.4) gives

在python中(版本3.4)给出

Traceback (most recent call last):
  File "C:\Daten\LiClipse_workspace\TestProject\MainPackage\PlayGround.py", line 9, in <module>
    res = numpy.dot(t,b)
ValueError: shapes (1,2) and (4,1) not aligned: 2 (dim 1) != 4 (dim 0)

Question:

问题:

How to make this work?

如何使它工作?

2 个解决方案

#1


5  

First, the easy (and arguably "correct") way to do what you want to do: use numpy.outer(), not numpy.dot().

首先,使用numpi .outer(),而不是numpy.dot(),这是一种简单的(可以说是“正确的”)方法来完成您想做的事情。

>>> import numpy
>>> t = [3,4]
>>> b = [1,2,3,4]
>>> numpy.outer(t, b)
array([[ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

This function computes the component-wise product of two 1D arrays - in other words, it multiplies each element of one array by each element of the other array - and returns a 2D array with the results.

该函数计算两个一维数组的组件乘积——换句话说,它将一个数组的每个元素乘以另一个数组的每个元素——并返回一个带有结果的2D数组。

Given the way Numpy displays its results, you can think of this as writing the first vector across the top of a rectangle and the second one down the left side, and filling in a multiplication table.

考虑到Numpy显示结果的方式,您可以把它看作是在一个矩形的顶部写第一个向量,然后在左边写第二个向量,然后填充一个乘法表。

 |   1   2   3   4
-+----------------
3|   3   6   9  12
4|   4   8  12  16

The function implements a common mathematical operation on vectors, called the outer product, tensor product, or Kronecker product. Note that the outer product is not commutative; in other words, you get a different result depending on which order you give the arguments. Compare the above result to this:

这个函数对向量执行一个通用的数学运算,称为外积、张量积或克罗内克积。注意,外积不是可交换的;换句话说,根据你给出参数的顺序,你会得到不同的结果。将上述结果与以下结果进行比较:

>>> numpy.outer(b, t)
array([[ 3,  4],
       [ 6,  8],
       [ 9, 12],
       [12, 16]])

Again, you can picture this as writing the first argument across the top, second argument down the side, and multiplying:

你可以把它想象成把第一个论点写在上面,第二个论点写在下面,然后相乘:

 |   3   4
-+---------
1|   3   4
2|   6   8
3|   9  12
4|  12  16

Numpy's dot() function, on the other hand, implements the dot product when applied to 1D arrays, or matrix multiplication when applied to 2D arrays, or a generalized version of matrix multiplication when applied to higher-dimensional arrays, but I'll ignore that case because it's a little tricky to understand.

在另一方面,Numpy的dot()函数在应用到一维数组时实现了点积,或者在应用到二维数组时进行矩阵乘法,或者将矩阵乘法应用到高维数组中,但我将忽略这种情况,因为这有点难以理解。

  • For two 1D arrays, dot() multiplies the two first elements together, the two second elements together, etc. and adds them all up, resulting in a number.

    对于两个1D数组,dot()将第一个元素、第二个元素等相乘,并将它们相加,得到一个数字。

    >>> numpy.dot([1,2,3], [4,5,6])
    32
    

    because 1*4+2*5+3*6 == 32. So basically, it iterates over the indices of each array, multiplies corresponding elements, and adds them up. Clearly, the two arrays must have the same length.

    因为1 * 4 + 2 * 5 + 3 * 6 = = 32。基本上,它遍历每个数组的索引,乘以相应的元素,然后相加。显然,这两个数组的长度必须相同。

    You can visualize this in a similar way to outer(), but instead of writing the 1D arrays along the edge, write them perpendicular to the edge. You should also switch the order, for reasons that will become clear later (but it's really an implementation choice): write the first one on the left and the second one on the top. An example will demonstrate:

    您可以以类似于outer()的方式对其进行可视化,但是不要沿着边缘编写1D数组,而是将它们垂直于边缘。您还应该转换顺序,原因稍后将会清楚(但这实际上是一个实现选择):在左边写第一个,在上面写第二个。一个例子将演示:

             |   4
             |   5
             |   6
    ---------+----
    1   2   3|  32
    

    To calculate the 32, I multiplied elements at the corresponding position in the column above that cell and the row next to it. 1*4, 2*5, and 3*6, and then add them all up.

    为了计算32,我在单元格的对应位置和旁边的行中增加了相应位置的元素。1*4 2*5和3*6,然后把它们加起来。

  • For two 2D arrays, dot() iterates over one axis of each array, multiplies corresponding elements, and adds them up. The axis being iterated over is the last one of the first array, and the first one (actually, next-to-last) of the second array. Clearly, these two axes must have the same length.

    对于两个2D数组,dot()遍历每个数组的一个轴,将相应的元素相乘,然后相加。被迭代的轴是第一个数组的最后一个,也是第二个数组的第一个(实际上是倒数第二个)。显然,这两个轴的长度必须相同。

    It's easy to understand this operation in terms of the diagram, so I'll jump right to that: suppose you want to compute the matrix product of

    用图来理解这个操作很容易,所以我直接说:假设你想计算矩阵的乘积

    array([[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9]])
    

    and

    array([[10, 11],
           [12, 13],
           [14, 15]])
    

    in that order. Again, just write the first argument on the side of a rectangle, and the second one over the top, and then you can multiply-and-add to fill in each cell as I did with the 1D example.

    这个顺序。再一次,把第一个参数写在一个矩形的边上,第二个参数写在上面,然后你就可以像我在1D例子中所做的那样,用multipland -add来填充每个单元格。

              |  10  11
              |  12  13
              |  14  15
    ----------+--------
     1   2   3|  76  82
     4   5   6| 184 199
     7   8   9| 292 316
    

    because, for example, 4*10+5*12+6*14 == 184.

    因为,例如,4*10+5*12+6*14 == 184。

Now, you might notice that you can use the dot() function to do the same thing as the outer() function - but your arrays have be 2D and have a dimension of length 1. That's why you had to jump through some hoops (like the [:, None] indexing) in your original code sample to make it work. And it has to be the right dimension too: it has to be the last dimension of the first array, and the next-to-last dimension of the second array. So in your specific example, where you want to compute the outer product of [3,4] and [1,2,3,4], in that order, you need to convert the first list into an array of shape (2,1), and the second list into an array of shape (1,4). If you do that, when you pass them to dot(), it effectively constructs this diagram and fills in the cells:

现在,您可能注意到您可以使用dot()函数来做与外部()函数相同的事情——但是您的数组是2D的,并且具有长度为1的维度。这就是为什么您必须在原始代码示例中跳过一些限制(比如[:,None]索引)以使其工作。它也必须是正确的维度:它必须是第一个数组的最后一个维度,以及第二个数组的倒数第二个维度。在特定的例子中,如果你想计算[3,4]和[1,2,3,4]的外积,按照这个顺序,你需要把第一个列表转换成一个形状数组(2,1),第二个列表转换成形状数组(1,4)。如果你这样做,当你将它们传递给点()时,它有效地构造了这个图并填充了单元格:

     |[[ 1,  2,  3,  4]]
-----+------------------
[[3],|   3   6   9  12
 [4]]|   4   8  12  16

I added some brackets to help you relate these requirements to Numpy syntax.

我添加了一些括号,以帮助您将这些需求与Numpy语法关联起来。

What you were trying to do, in the code sample in your question (numpy.dot(t, b)), would have corresponded to this diagram:

在问题中的代码示例中(numpy)。点(t, b)会对应于这个图:

        | [[1],
        |  [2],
        |  [3],
        |  [4]]
--------+------------------
[[3, 4]]|   ?

See, when you try to apply the multiply-and-add procedure to this, it doesn't work, because you've got two elements in one array and four in the other array, and you can't pair them up to do the multiplications. That's the root of the error Numpy shows you.

你看,当你试着对它应用multipland -add过程时,它不起作用,因为你在一个数组中有两个元素,而在另一个数组中有四个元素,你不能把它们配对来做乘法。这是错误Numpy的根。

When you reverse the order, numpy.dot(b, t), you get this diagram:

当你颠倒顺序时,numpy。点(b, t)得到这个图

     |[[ 3,  4]]
-----+----------
[[1],|   3   4
 [2],|   6   8
 [3],|   9  12
 [4]]|  12  16

That does give you a sensible result, but be careful about whether it's really the one you want. This is an array of shape (4,2), whereas if you fix up the other procedure in the most straightforward way, you would get a result of shape (1,1), or really, just a number. In any given situation, only one of these options (at most) will work. And it seems like the logistic function in the screenshot you posted in a comment is expecting a single number to come out of that dot() function; it's not going to work with a larger matrix. (Well, it might, but it won't do what you think.)

这确实会给你一个合理的结果,但是要注意它是否真的是你想要的。这是一个形状数组(4,2),而如果你用最直接的方式修复另一个过程,你会得到一个形状(1,1)的结果,或者说,一个数字。在任何给定的情况下,这些选项中只有一个(最多)有效。看起来你在评论中发布的截屏中的逻辑函数期望从那个点()函数中得到一个数字;它不会和一个更大的矩阵一起工作。(嗯,可能会,但它不会照你的想法去做。)

#2


0  

Here is an alternative way that does the same computation, but produces a different shape.

这里有一种替代方法,它可以进行相同的计算,但产生不同的形状。

a = np.array(range(2 * 5 * 3)).reshape((2, 5, 3))
b = np.array(range(4 * 6)).reshape((4, 6))

c = np.zeros((2, 5, 3, 4, 6))
for i1 in range(2):
    for i2 in range(5):
        for i3 in range(3):
            for i4 in range(4):
                for i5 in range(6):
                    c[i1, i2, i3, i4, i5] = a[i1, i2, i3] * b[i4, i5]

d = np.multiply.outer(a, b)

assert np.all(c == d)

To compare:

比较:

>>> np.multiply.outer(a, b).shape
(2, 5, 3, 4, 6)

>>> np.outer(a, b).shape
(30, 24)

You can also use this if you want to look smart: np.einsum('ijk,lm->ijklm', a, b)

如果你想看起来很聪明,你也可以用它:np。einsum(ijk,lm - > ijklm,a,b)

#1


5  

First, the easy (and arguably "correct") way to do what you want to do: use numpy.outer(), not numpy.dot().

首先,使用numpi .outer(),而不是numpy.dot(),这是一种简单的(可以说是“正确的”)方法来完成您想做的事情。

>>> import numpy
>>> t = [3,4]
>>> b = [1,2,3,4]
>>> numpy.outer(t, b)
array([[ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

This function computes the component-wise product of two 1D arrays - in other words, it multiplies each element of one array by each element of the other array - and returns a 2D array with the results.

该函数计算两个一维数组的组件乘积——换句话说,它将一个数组的每个元素乘以另一个数组的每个元素——并返回一个带有结果的2D数组。

Given the way Numpy displays its results, you can think of this as writing the first vector across the top of a rectangle and the second one down the left side, and filling in a multiplication table.

考虑到Numpy显示结果的方式,您可以把它看作是在一个矩形的顶部写第一个向量,然后在左边写第二个向量,然后填充一个乘法表。

 |   1   2   3   4
-+----------------
3|   3   6   9  12
4|   4   8  12  16

The function implements a common mathematical operation on vectors, called the outer product, tensor product, or Kronecker product. Note that the outer product is not commutative; in other words, you get a different result depending on which order you give the arguments. Compare the above result to this:

这个函数对向量执行一个通用的数学运算,称为外积、张量积或克罗内克积。注意,外积不是可交换的;换句话说,根据你给出参数的顺序,你会得到不同的结果。将上述结果与以下结果进行比较:

>>> numpy.outer(b, t)
array([[ 3,  4],
       [ 6,  8],
       [ 9, 12],
       [12, 16]])

Again, you can picture this as writing the first argument across the top, second argument down the side, and multiplying:

你可以把它想象成把第一个论点写在上面,第二个论点写在下面,然后相乘:

 |   3   4
-+---------
1|   3   4
2|   6   8
3|   9  12
4|  12  16

Numpy's dot() function, on the other hand, implements the dot product when applied to 1D arrays, or matrix multiplication when applied to 2D arrays, or a generalized version of matrix multiplication when applied to higher-dimensional arrays, but I'll ignore that case because it's a little tricky to understand.

在另一方面,Numpy的dot()函数在应用到一维数组时实现了点积,或者在应用到二维数组时进行矩阵乘法,或者将矩阵乘法应用到高维数组中,但我将忽略这种情况,因为这有点难以理解。

  • For two 1D arrays, dot() multiplies the two first elements together, the two second elements together, etc. and adds them all up, resulting in a number.

    对于两个1D数组,dot()将第一个元素、第二个元素等相乘,并将它们相加,得到一个数字。

    >>> numpy.dot([1,2,3], [4,5,6])
    32
    

    because 1*4+2*5+3*6 == 32. So basically, it iterates over the indices of each array, multiplies corresponding elements, and adds them up. Clearly, the two arrays must have the same length.

    因为1 * 4 + 2 * 5 + 3 * 6 = = 32。基本上,它遍历每个数组的索引,乘以相应的元素,然后相加。显然,这两个数组的长度必须相同。

    You can visualize this in a similar way to outer(), but instead of writing the 1D arrays along the edge, write them perpendicular to the edge. You should also switch the order, for reasons that will become clear later (but it's really an implementation choice): write the first one on the left and the second one on the top. An example will demonstrate:

    您可以以类似于outer()的方式对其进行可视化,但是不要沿着边缘编写1D数组,而是将它们垂直于边缘。您还应该转换顺序,原因稍后将会清楚(但这实际上是一个实现选择):在左边写第一个,在上面写第二个。一个例子将演示:

             |   4
             |   5
             |   6
    ---------+----
    1   2   3|  32
    

    To calculate the 32, I multiplied elements at the corresponding position in the column above that cell and the row next to it. 1*4, 2*5, and 3*6, and then add them all up.

    为了计算32,我在单元格的对应位置和旁边的行中增加了相应位置的元素。1*4 2*5和3*6,然后把它们加起来。

  • For two 2D arrays, dot() iterates over one axis of each array, multiplies corresponding elements, and adds them up. The axis being iterated over is the last one of the first array, and the first one (actually, next-to-last) of the second array. Clearly, these two axes must have the same length.

    对于两个2D数组,dot()遍历每个数组的一个轴,将相应的元素相乘,然后相加。被迭代的轴是第一个数组的最后一个,也是第二个数组的第一个(实际上是倒数第二个)。显然,这两个轴的长度必须相同。

    It's easy to understand this operation in terms of the diagram, so I'll jump right to that: suppose you want to compute the matrix product of

    用图来理解这个操作很容易,所以我直接说:假设你想计算矩阵的乘积

    array([[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9]])
    

    and

    array([[10, 11],
           [12, 13],
           [14, 15]])
    

    in that order. Again, just write the first argument on the side of a rectangle, and the second one over the top, and then you can multiply-and-add to fill in each cell as I did with the 1D example.

    这个顺序。再一次,把第一个参数写在一个矩形的边上,第二个参数写在上面,然后你就可以像我在1D例子中所做的那样,用multipland -add来填充每个单元格。

              |  10  11
              |  12  13
              |  14  15
    ----------+--------
     1   2   3|  76  82
     4   5   6| 184 199
     7   8   9| 292 316
    

    because, for example, 4*10+5*12+6*14 == 184.

    因为,例如,4*10+5*12+6*14 == 184。

Now, you might notice that you can use the dot() function to do the same thing as the outer() function - but your arrays have be 2D and have a dimension of length 1. That's why you had to jump through some hoops (like the [:, None] indexing) in your original code sample to make it work. And it has to be the right dimension too: it has to be the last dimension of the first array, and the next-to-last dimension of the second array. So in your specific example, where you want to compute the outer product of [3,4] and [1,2,3,4], in that order, you need to convert the first list into an array of shape (2,1), and the second list into an array of shape (1,4). If you do that, when you pass them to dot(), it effectively constructs this diagram and fills in the cells:

现在,您可能注意到您可以使用dot()函数来做与外部()函数相同的事情——但是您的数组是2D的,并且具有长度为1的维度。这就是为什么您必须在原始代码示例中跳过一些限制(比如[:,None]索引)以使其工作。它也必须是正确的维度:它必须是第一个数组的最后一个维度,以及第二个数组的倒数第二个维度。在特定的例子中,如果你想计算[3,4]和[1,2,3,4]的外积,按照这个顺序,你需要把第一个列表转换成一个形状数组(2,1),第二个列表转换成形状数组(1,4)。如果你这样做,当你将它们传递给点()时,它有效地构造了这个图并填充了单元格:

     |[[ 1,  2,  3,  4]]
-----+------------------
[[3],|   3   6   9  12
 [4]]|   4   8  12  16

I added some brackets to help you relate these requirements to Numpy syntax.

我添加了一些括号,以帮助您将这些需求与Numpy语法关联起来。

What you were trying to do, in the code sample in your question (numpy.dot(t, b)), would have corresponded to this diagram:

在问题中的代码示例中(numpy)。点(t, b)会对应于这个图:

        | [[1],
        |  [2],
        |  [3],
        |  [4]]
--------+------------------
[[3, 4]]|   ?

See, when you try to apply the multiply-and-add procedure to this, it doesn't work, because you've got two elements in one array and four in the other array, and you can't pair them up to do the multiplications. That's the root of the error Numpy shows you.

你看,当你试着对它应用multipland -add过程时,它不起作用,因为你在一个数组中有两个元素,而在另一个数组中有四个元素,你不能把它们配对来做乘法。这是错误Numpy的根。

When you reverse the order, numpy.dot(b, t), you get this diagram:

当你颠倒顺序时,numpy。点(b, t)得到这个图

     |[[ 3,  4]]
-----+----------
[[1],|   3   4
 [2],|   6   8
 [3],|   9  12
 [4]]|  12  16

That does give you a sensible result, but be careful about whether it's really the one you want. This is an array of shape (4,2), whereas if you fix up the other procedure in the most straightforward way, you would get a result of shape (1,1), or really, just a number. In any given situation, only one of these options (at most) will work. And it seems like the logistic function in the screenshot you posted in a comment is expecting a single number to come out of that dot() function; it's not going to work with a larger matrix. (Well, it might, but it won't do what you think.)

这确实会给你一个合理的结果,但是要注意它是否真的是你想要的。这是一个形状数组(4,2),而如果你用最直接的方式修复另一个过程,你会得到一个形状(1,1)的结果,或者说,一个数字。在任何给定的情况下,这些选项中只有一个(最多)有效。看起来你在评论中发布的截屏中的逻辑函数期望从那个点()函数中得到一个数字;它不会和一个更大的矩阵一起工作。(嗯,可能会,但它不会照你的想法去做。)

#2


0  

Here is an alternative way that does the same computation, but produces a different shape.

这里有一种替代方法,它可以进行相同的计算,但产生不同的形状。

a = np.array(range(2 * 5 * 3)).reshape((2, 5, 3))
b = np.array(range(4 * 6)).reshape((4, 6))

c = np.zeros((2, 5, 3, 4, 6))
for i1 in range(2):
    for i2 in range(5):
        for i3 in range(3):
            for i4 in range(4):
                for i5 in range(6):
                    c[i1, i2, i3, i4, i5] = a[i1, i2, i3] * b[i4, i5]

d = np.multiply.outer(a, b)

assert np.all(c == d)

To compare:

比较:

>>> np.multiply.outer(a, b).shape
(2, 5, 3, 4, 6)

>>> np.outer(a, b).shape
(30, 24)

You can also use this if you want to look smart: np.einsum('ijk,lm->ijklm', a, b)

如果你想看起来很聪明,你也可以用它:np。einsum(ijk,lm - > ijklm,a,b)