Let list
be a list of lists, the elements of which are random integers in the interval $[1,c]$. Each element $i$ has a probability prob
to be changed to another integer, selected randomly in $[1,c] \setminus \{v_i\}$ where $v_i$ is the value of the element $i$. No particular size is requested for either list
or its sublists, but each sublist has the same size.
As an example, let's suppose that (a) list
is made of 3 sublists, (b) each sublist contains 2 elements, (c) c
equals to 3, and (d) prob
is 0.25.
A random generation would give for instance list = {{3, 1}, {2, 1}, {3, 3}}
. After "running" the probability through the elements of the sublists, we would have to change for instance the elements at positions {1, 2}
and {3, 1}
. So, 1
will be randomly changed to either 2
or 3
, and 3
to either 1
or 2
. A possible outcome of list = {{3, 1}, {2, 1}, {3, 3}}
would then be {{3, 2}, {2, 1}, {2, 3}}
.
I am interested in an efficient way of coding this problem, with the specifications given in the first paragraph.
I tried a method with three different versions, shown below. The respective computing times are given for a problem where (a) list
is made of 1000 sublists, (b) each sublist contains 30 elements, (c) c
equals to 3, and (d) prob
is 0.001.
list = RandomInteger[{1, 3}, {1000, 30}];
Version 1
ChangeV1[prob_, c_, sizelist_, sizesublist_][list_] :=
Block[{elemstochange = RandomVariate[BernoulliDistribution[prob], {sizelist, sizesublist}]},
ReplacePart[list, (# -> RandomChoice[Drop[Range[c], {Extract[list, #]}]])
& /@ Position[elemstochange, 1]]];
Timing
ChangeV1[0.001, 3, 1000, 30][list]; // AbsoluteTiming
(* {0.00297177, Null} *)
Version 2
ChangeV2[prob_, c_, sizelist_, sizesublist_][list_] :=
Block[{elemstochange = RandomVariate[BernoulliDistribution[prob], {sizelist, sizesublist}]},
MapAt[RandomChoice[Drop[Range[c], {#}]] &, list, Position[elemstochange, 1]]];
Timing
ChangeV2[0.001, 3, 1000, 30][list]; // AbsoluteTiming
(* {0.00313513, Null} *)
Version 3
ChangeV3[prob_, c_, sizelist_, sizesublist_][list_] :=
Block[{elemstochange = RandomVariate[BernoulliDistribution[prob], {sizelist, sizesublist}],
temp = list},
(temp[[Sequence @@ #]] =
RandomChoice[Drop[Range[c], {Extract[list, #]}]]) & /@ Position[elemstochange, 1];
temp];
Timing
ChangeV3[0.001, 3, 1000, 30][list]; // AbsoluteTiming
(* {0.0028965, Null} *)
I would be very interested in reading other methods that would improve the computing time for Change
.
Nest
)? If so, seems like a lot of machinations that could be done simply. How big might c be? "Small" (e.g. <thousands) or does it have a large upper bound? What of the probabilities? Will they be "small" as in your test cases, or do they cover the [0,1] space completely? It would be useful to know more about "...main routine I am working on, there are other functions involved that make modifications..." - what is th purpose of this and the overall goal for the "main" routine - there might be a much more efficient way to get there. $\endgroup$