openlang

Ported a short MATLAB script to R and one result came back as a matrix

Trying to redo a short MATLAB script in R, and I've barely touched MATLAB before. Most of it came over fine, except for a single line that gives different numbers.

A = [2 0; 1 3];
w = [0.5; 0.25];
s = A * w;
B = A .* A;
A <- matrix(c(2, 0, 1, 3), nrow = 2, byrow = TRUE)
w <- c(0.5, 0.25)
s <- A * w
B <- A * A
s
#>      [,1] [,2]
#> [1,] 1.00 0.00
#> [2,] 0.25 0.75

B agrees with MATLAB. s in MATLAB is two numbers, 1 and 1.25, and in R it's a whole 2 by 2 matrix with no error and no warning. I checked that A prints the same in both, so byrow isn't the problem. R didn't seem to have .*, so I just dropped the dot everywhere. Is that where it went wrong, or is it something about how I built w?

The conversation continues 7

Follow the reasoning
  1. Permalink

    You have them the wrong way round. MATLAB's .* is the matrix product and * is elementwise, same as R's *, so s should match as written. Look at w instead. c() gives a plain vector, not a column, and R recycles it across the matrix.

  2. Permalink

    Backwards. In MATLAB * between matrices is the matrix product and .* is elementwise. R has it the other way round. * is elementwise and %*% is the product.

    s <- A %*% w
    s
    #>      [,1]
    #> [1,] 1.00
    #> [2,] 1.25

    w is fine as a plain vector. %*% treats it as a column when that's what makes the shapes fit. B matched only because A .* A and A * A are both elementwise. Dropping the dot was right for that line and wrong for the other.

  3. Permalink

    Right, I had them swapped. The dot is MATLAB's elementwise marker, which is exactly why R never needed one. The c() point holds, though, a plain vector has no orientation and %*% picks one for it.

  4. Permalink

    The R line computes something real, just not MATLAB's A * w. R recycles w down each column, so row i is multiplied by w[i]. That is MATLAB's A .* w with w as a column. Your 2 by 2 result is correct for that expression.

  5. Permalink

    And it does that without a word because the lengths divide. Recycling warns only when the longer length isn't a multiple of the shorter one, and four elements over two weights divides evenly. A three-element w would at least have complained. When the weights really are per row I'd rather write sweep(A, 1, w, "*") and have the intent on the page.

  6. Permalink

    Same trap, more symbols. MATLAB A^2 is the matrix power, A * A. R A^2 squares each element. MATLAB A' transposes, t(A) in R for a real matrix. MATLAB A \ b solves the system, solve(A, b) in R, and / between matrices is a solve in MATLAB too, while R divides element by element. Go through the script and check every *, ^ and / with a matrix on both sides.

  7. Permalink

    That was it, thank you. s <- A %*% w gives 1 and 1.25 now. It comes back as a 2 by 1 matrix, so it goes through drop() before landing in the data frame. The full script has an A^2 further down too, and pgr's list caught it before it could become the next mystery.

Other sides of the same question

  1. na.rm = TRUE on a group that is all NA

    Per-group totals with tapply(x, g, sum, na.rm = TRUE), and one group came back as 0. Every value in that group is NA. Not a s…

    Replies 5r
  2. sum(X) on a matrix with one row

    A function takes a matrix of observations, rows are observations and columns are features, and normalizes each column with X…

    Replies 6matlab
  3. A loop that allocated a column at a time

    Slicing in Julia copies, which I knew and then forgot inside a loop. Take a function that walks the columns of a matrix and d…

    Replies 4julia