5

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?

OkkesDulgerci
  • 10,716
  • 1
  • 19
  • 38

3 Answers3

8

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}} *)
halirutan
  • 112,764
  • 7
  • 263
  • 474
7

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

kglr
  • 394,356
  • 18
  • 477
  • 896
6

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

b3m2a1
  • 46,870
  • 3
  • 92
  • 239