4
$\begingroup$

I have a list containing 500 rows, each of 37 elements; i.e., a 500 x 37 matrix.

My goal is to substract in each row each element from the first. My approach in mind is to call each list by a PureFunction and then to subtract the second element from the first, then the third from the first so in the end I would have a list with 500 sublists, each with 36 elements. I failed to figure out how to call single elements if, as in my case, the the list is called by a PureFunction. I also tried to work with slots, again failing to call the single elements of the already called list. I highly appreciat any help or comments!

$\endgroup$
  • 1
    $\begingroup$ Maybe #[[1]] - #[[2 ;;]] & /@ lst? $\endgroup$ – user1066 Jun 3 '17 at 18:19
8
$\begingroup$

If mat is your matrix, the following should be fast:

mat . SparseArray[
    {{1,_} -> 1, Band[{2,1}] -> -1},
    Dimensions[mat][[2]]+{0,-1}
]

Addendum

Here is a brief speed comparison of the 4 suggested methods:

wreach[m_] := m[[All, 1]] - m[[All, 2 ;;]]
carl[m_] := m . SparseArray[
    {{1, _} -> 1, Band[{2, 1}] -> -1}, 
    Dimensions[m][[2]] + {0, -1}
]
goldberg[m_] := #1 - {##2} & @@@ m
tom[m_] := #[[1]] - #[[2 ;;]] & /@ m

A sample matrix:

mat = RandomReal[10^6, {10^5, 30}];

Speed comparison:

r1 = carl[mat]; // AbsoluteTiming
r2 = wreach[mat]; // AbsoluteTiming
r3 = goldberg[mat]; // AbsoluteTiming
r4 = tom[mat]; // AbsoluteTiming
r1 === r2 === r3 === r4

{0.013968, Null}

{0.029711, Null}

{1.4249, Null}

{0.346468, Null}

True

$\endgroup$
  • 1
    $\begingroup$ Incredible. Care to explain how your at first glance complicated solution is faster than the obvious vectorization approach of wreach? +1 $\endgroup$ – LLlAMnYP Jun 4 '17 at 6:59
  • $\begingroup$ @LLlAMnYP My solution constructs a SparseArray object (basically instantaneous) and then does 1 Dot product of two matrices. Matrix multiplication is probably one of the most highly optimized algorithms in the numerical analysis literature, and even more highly optimized would be matrix multiplication with a sparse array. So, I'm not surprised my solution is fast. It is a bit surprising that it is faster than a single subtraction of a matrix from a vector. Probably there is some overhead in threading the vector/matrix subtraction. $\endgroup$ – Carl Woll Jun 6 '17 at 1:35
  • 1
    $\begingroup$ It is a bit surprising that it is faster than a single subtraction of a matrix from a vector. Exactly that was my question. It is surprising. $\endgroup$ – LLlAMnYP Jun 6 '17 at 12:33
6
$\begingroup$

If the use of a pure function is not mandatory, then given a matrix m we can write:

m[[All, 1]] - m[[All, 2;;]]

Here is a small example:

m = {{10, 1, 2, 3}, {100, 10, 20, 30}, {1000, 100, 200, 300}};

m // MatrixForm

matrix

m[[All, 1]] - m[[All, 2;;]] // MatrixForm

matrix

$\endgroup$
  • $\begingroup$ Obvious approach I would go for as well. +1 now I have to think of something better... $\endgroup$ – LLlAMnYP Jun 4 '17 at 7:04
4
$\begingroup$

A 4 x 3 matrix is good enough to demonstrate a pure function that will do what you ask.

SeedRandom[2]; a = RandomInteger[10, {4, 3}]

{{8, 4, 5}, {4, 7, 4}, {0, 1, 0}, {4, 3, 7}}

{##2} - #1 & @@@ a

{{-4, -3}, {3, 0}, {1, 0}, {-1, 3}}

Note that @@@ applies the pure function at level 1 of the matrix, i.e., at the level of the rows. See Apply

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.