5
$\begingroup$

Assume I have a matrix.

mat = {{1, 1, 8, 3, 5}, {2, 2, 6, 5, 3}, {3, 3, 9, 2, 7}, {4, 4, 7, 1,
     7}, {5, 5, 3, 6, 8}, {6, 6, 8, 7, 7}, {7, 7, 2, 4, 4}, {8, 8, 9, 
    1, 6}, {9, 9, 1, 1, 2}, {10, 10, 2, 1, 6}, {11, 11, 6, 2, 4}, {12,
     12, 9, 2, 1}}; 

I would like to create new matrix that has dimension $12\times3$.

First 2 column is fixed but 3rd column is randomly selected from last 3 column.

First row would be {1, 1, 8} or {1, 1, 3} or {1, 1, 5} Second row would be {2, 2, 6} or {2, 2, 5} or {2, 2, 3}

For example one sample is the following.

sem={{{1, 1, 8}, {2, 2, 3}, {3, 3, 7}, {4, 4, 7}, {5, 5, 6}, {6, 6, 8}, {7, 7, 2}, {8, 8, 6}, {9, 9, 1}, {10, 10, 6}, {11, 11, 6}, {12,12, 9}}} ; 

I need say 1000 sample like this. How can I achieve this?

$\endgroup$
4
  • $\begingroup$ Why give us a matrix and then say "First row could be..."?? $\endgroup$ Commented Jan 24, 2018 at 2:15
  • $\begingroup$ @DavidG.Stork Because it wouldn't be nearly as funny if questions would be clearly stated? :) $\endgroup$
    – halirutan
    Commented Jan 24, 2018 at 2:22
  • $\begingroup$ ...but waste valuable time and good will... $\endgroup$ Commented Jan 24, 2018 at 2:28
  • $\begingroup$ Your question is poorly worded. The phrasing of randomly selecting a column implies that within each sample, the third column in that sample comes from the same column from the original matrix. $\endgroup$ Commented Jan 24, 2018 at 16:32

3 Answers 3

8
$\begingroup$

Create a function that does this for exactly one entry. Then use this function on all your entries:

rand[{x1_, x2_, rest__}] := {x1, x2, RandomChoice[{rest}]};
rand /@ mat
(* {{1, 1, 8}, {2, 2, 5}, {3, 3, 2}, {4, 4, 1}, {5, 5, 8}, {6, 6,
   7}, {7, 7, 4}, {8, 8, 6}, {9, 9, 1}, {10, 10, 1}, {11, 11, 2}, {12,
   12, 2}} *)
$\endgroup$
0
7
$\begingroup$

Also

f0 = Extract[#, {{1}, {2}, {RandomInteger[{3, 5}]}}] &;
f0 /@ mat

{{1, 1, 3}, {2, 2, 3}, {3, 3, 2}, {4, 4, 7}, {5, 5, 6}, {6, 6, 7},
{7, 7, 4}, {8, 8, 9}, {9, 9, 1}, {10, 10, 1}, {11, 11, 2}, {12, 12, 2}}

And

f1 = Transpose@Extract[Transpose@#, {{1}, {2}, {RandomInteger[{3, 5}]}}] &;
f1 @ mat

{{1, 1, 5}, {2, 2, 3}, {3, 3, 7}, {4, 4, 7}, {5, 5, 8}, {6, 6, 7},
{7,7, 4}, {8, 8, 6}, {9, 9, 2}, {10, 10, 6}, {11, 11, 4}, {12, 12, 1}}

$\endgroup$
6
$\begingroup$

Here's a faster extractor using a single Extract and single RandomInteger call, although still with a minimally expensive MapIndexed call and a Partition for reshaping:

n = 10000;
mat = RandomInteger[n, {n, n}];

b3extract[mat_] :=
  With[{
    extractSpec =
     Join @@
      MapIndexed[
       Thread[{#2[[1]], {1, 2, #}}] &,
       RandomInteger[{3, Length@mat}, Length@mat]
       ]},
   Partition[
    Extract[mat, extractSpec],
    3
    ]
   ];

Here's a timing comparison to the other solutions:

b3extract[mat] // RepeatedTiming // First

0.028

(*halirutan imp*)
rand[{x1_, x2_, rest__}] := {x1, x2, RandomChoice[{rest}]};
rand /@ mat // RepeatedTiming // First

10.5

(*kglr imp 1*)

f0 = Extract[#, {{1}, {2}, {RandomInteger[{3, Length@mat}]}}] &;
f0 /@ mat // RepeatedTiming // First

0.597

(*kglr imp 2*)
f1 = Transpose@
    Extract[Transpose@#, {{1}, {2}, {RandomInteger[{3, 5}]}}] &;
f1@mat // RepeatedTiming // First

0.935

And here's a correctness check:

BlockRandom[
  SeedRandom[1];
  b3extract[mat]
  ] ==
 BlockRandom[
  SeedRandom[1];
  Extract[#, {{1}, {2}, {RandomInteger[{3, Length@mat}]}}] & /@ mat
  ]

True

It also scales surprisingly well (well I guess it's still $~O(n^2)$ or worse but with a good pre-factor, probably from most operations being efficiently dispatched to the kernel):

sizes =
  {100, 1000, 5000, 10000, 15000, 20000, 25000, 30000, 35000};
timings =
 Table[
  With[
   {
    mat = RandomInteger[n, {n, n}]
    },
   b3extract[mat] // RepeatedTiming // First
   ],
  {n, sizes}
  ]

{0.00025, 0.0025, 0.014, 0.030, 0.047, 0.10, 0.22, 0.30, 0.40}


fit =
  NonlinearModelFit[
   Thread[{sizes, timings}],
   prefactor*size^2,
   {prefactor},
   size
   ];
fit["BestFit"]

3.2*10^-10 size^2

ListLinePlot[
 {
  Thread[{sizes, timings}],
  Map[{#, fit["BestFit"] /. size -> #} &, sizes]
  }
 ]

asdasd

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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