Multiplying Vector Combinations

Multiplying vector combinations

You are probably looking for outer() or it's alias binary operator %o%:

> c(2,3,4) %o% c(1,2)
[,1] [,2]
[1,] 2 4
[2,] 3 6
[3,] 4 8
> outer(c(2,3,4), c(1,2))
[,1] [,2]
[1,] 2 4
[2,] 3 6
[3,] 4 8

In your case, outer() offers the flexibility to specify a function that is applied to the combinations; %o% only applies the * multiplication function. For your example and data

mph <- function(d, rpm) {
cir <- pi * d
cir * rpm / 63360 * 60
}

> outer(c(20,26,29), c(150,350), FUN = mph)
[,1] [,2]
[1,] 8.924979 20.82495
[2,] 11.602473 27.07244
[3,] 12.941220 30.19618

Product between all combinations of a vector's elements

We can use combn with anonymous function call

combn(vec, 2, FUN = function(x) x[1] * x[2])
#[1] 2 3 4 6 8 12

data

vec <- 1:4

Multiply permutations of two vectors in R

Use outer(A,B,'*') which will return a matrix

x<-c(1:4)
y<-c(10:14)
outer(x,y,'*')

returns

     [,1] [,2] [,3] [,4] [,5]
[1,] 10 11 12 13 14
[2,] 20 22 24 26 28
[3,] 30 33 36 39 42
[4,] 40 44 48 52 56

and if you want the result in a list you then can do

z<-outer(x,y,'*')
z.list<-as.list(t(z))

head(z.list) returns

[[1]]
[1] 10

[[2]]
[1] 11

[[3]]
[1] 12

[[4]]
[1] 13

[[5]]
[1] 14

[[6]]
[1] 20

which is x1*y1, x1*y2, x1* y3, x1*y4, x2*y1 ,... (if you want x1*y1, x2*y1, ... replace t(z) by z)

How to calculate the product from combinations of several vectors in R?

The expand.grid solution is OK, but in mathematics there is an elegant Kronecker product.

R has a function kronecker, but it takes two vectors at a time, so we need Reduce for a recursive application:

oo <- Reduce(kronecker, list(a, b, c, d))

Alternatively, use outer (the workhorse of kronecker):

rr <- Reduce(outer, list(a, b, c, d))

This is more user-friendly, as rr[i, j, u, v] gives you a[i] * b[j] * c[u] * d[v].


Remark 1

Note that elements in oo and rr differ in order. Because for two vectors a and b:

kronecker(a, b)  ## a[1] * b, a[2] * b ...
outer(a, b) ## a * b[1], a * b[2] ...

Thus the following use of kronecker produces a result identical to rr.

zz <- Reduce(kronecker, list(d, c, b, a))
dim(zz) <- c(length(a), length(b), length(c), length(d))

Remark 2

The method can be adapted to do a[i] + b[j] + c[u] + d[v], by replacing the default operation "*" in outer and kronecker to "+". For example:

Reduce(function (x, y) outer(x, y, "+"), list(a, b, c, d))

Remark 3

johannes's answer can be improved. That row-wise application of apply is a performance killer. We can do the following to get a result consistent with rr.

xx <- Reduce("*", expand.grid(a, b, c, d))
dim(xx) <- c(length(a), length(b), length(c), length(d))

Multiply two objects in R

The outer product is computed by outer:

out <- outer(P1, P2)
dimnames(out) <- setNames(dimnames(out), c("P1", "P2"))

P2
P1 Low Medium High
Low 0.0625 0.125 0.0625
Medium 0.1250 0.250 0.1250
High 0.0625 0.125 0.0625

Then you can put it in long form using the reshape2 package:

reshape2::melt(out, value.name = "P(P1*P2)")

P1 P2 P(P1*P2)
1 Low Low 0.0625
2 Medium Low 0.1250
3 High Low 0.0625
4 Low Medium 0.1250
5 Medium Medium 0.2500
6 High Medium 0.1250
7 Low High 0.0625
8 Medium High 0.1250
9 High High 0.0625

Multiplying vectors from the same list and printing the highest 2 outputs

you can use itertools.combinations to multiply each vector in the list of arrays by each other vector in the list:

import itertools

result = [mltply(v1, v2) for v1, v2 in itertools.combinations(vectors_list, 2)]

to print the 3 highest results you can use the built-in function sorted, or you can sort inline the list using list.sort then slice the top 3 elements:

print(sorted(result)[-3:])

or:

result.sort()
print(result[-3:])

Multiplying all combinations of array elements in numpy

First, the easy (and arguably "correct") way to do what you want to do: use numpy.outer(), not 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.

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.

 |   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.

  • 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.

    >>> 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.

    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:

             |   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.

  • 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.

    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.

              |  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.

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:

     |[[ 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.

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

        | [[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.

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

     |[[ 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.)



Related Topics



Leave a reply



Submit