4
$\begingroup$

I am trying to generate a binary matrix (whose elements are 0 or 1) of dimension 20x20. To do this, I want to supply as input the number of matrix elements that will take value 1. After, I want to draw randomly distinct position of those elements (values 1). I thought of doing this:

n = 20; (*matrix dimension*)
d = 300; (*number of matrix elements that will assume value 1*)
rules = RandomInteger[{1, n}, {d, 2}]; (*defines the position of the matrix elements*)
rules2 = Table[rules[[i]] -> 1, {i, Length[rules]}]; (*applies the list of random positions the value 1*)
s = SparseArray[rules2] (*creates the binary random matrix*)

However, this method is not efficient because it does not create 300 different random positions (some are repeated). For example, the result appears 212 filled matrix elements (many of the positions contains summed values).

SparseArray[<212>,{20,20}]

I would like to know if anyone could help me solve this problem of generating 300 numbers 1 in random positions in a 20x20 dimension matrix.

Thanks in advance

$\endgroup$
6
$\begingroup$

This might work:

n = 20;
d = 300;
s = Join[ConstantArray[1, d], ConstantArray[0, n^2 - d]];
a = Partition[RandomSample[s], n]

Total[a, 2]

300

$\endgroup$
6
$\begingroup$
r = RandomSample[Range[400], 300];
q = Array[0 &, 400];
q[[r]] = 1;
Q = ArrayReshape[q, {20, 20}] // MatrixForm

enter image description here

$\endgroup$
  • $\begingroup$ Quite nice. Here's a shorter variation: ArrayReshape[SparseArray[Transpose[{RandomSample[Range[400], 300]}] -> 1, {400}], {20, 20}] $\endgroup$ – J. M. is away Mar 17 at 14:34
  • $\begingroup$ @J. M. Thank you! And I like your version too! Have not been as familiar with SparseArray[] as some of the other commands, because I never really use it. But now I see its benefit here. Ironically, most (75%) of the entries are ones! $\endgroup$ – mjw Mar 17 at 15:11
  • $\begingroup$ Indeed, it's not actually "sparse" in that sense. So, just turn things around a bit: ArrayReshape[SparseArray[Transpose[{RandomSample[Range[400], 100]}] -> 0, {400}, 1], {20, 20}] $\endgroup$ – J. M. is away Mar 17 at 15:27
  • $\begingroup$ Yes! Very much agreed. Even more efficient! $\endgroup$ – mjw Mar 17 at 15:30
3
$\begingroup$

In a situation where generating all admissible matrix indices can get prohibitive (e.g. the result of Tuples[] having too many elements), here is an approach that generates just the needed nonzero indices:

(* random k-subset *)
rs[n_, k_] := Take[PermutationList[RandomPermutation[n]], k]

BlockRandom[SeedRandom[1023, Method -> "ExtendedCA"]; (* for reproducibility *)
            With[{n = 20, p = 300},
                 Block[{k = 1, idl, id},
                       idl = {rs[n, 2]};
                       While[k < p, id = rs[n, 2];
                             If[! MemberQ[idl, id], k++; AppendTo[idl, id]]];
                       mat = SparseArray[idl -> 1, {n, n}]]]];

Check:

Total[mat, 2]
   300
$\endgroup$
3
$\begingroup$

Here is a variation of JM's comment to mjw's answer that will be much faster when large matrices (e.g., 10^5 by 10^5) are to be created:

randomBinary[dim_, count_] := ArrayReshape[
    SparseArray[Thread[RandomSample[1;;dim^2, count]->1], dim^2],
    {dim, dim}
] 

The key idea is that one can use Span (e.g., 1;;max) as the first argument of RandomSample. For example:

mat = randomBinary[10^5, 300]; //RepeatedTiming
Total[mat, Infinity]

{0.000327, Null}

300

Of the other answers, only JM's answer will be able to produce a result, and does so about 4 orders of magnitude more slowly.

$\endgroup$
2
$\begingroup$
sa = SparseArray[RandomSample[Tuples[Range@20, {2}], 300] -> 1, {20, 20}]

enter image description here

Total[sa, 2]

300

Alternatively, without Tuples:

a2 = Unitize @ Threshold[RandomReal[1, {20, 20}], {"LargestValues", 300}]

a3 = Partition[SparseArray[Partition[RandomSample[Range[20^2], 300], 1] -> 1, {20^2}], 20]

a4  = SparseArray[(1 + QuotientRemainder[RandomSample[Range[20^2 - 1], 300], 20]) -> 1, 
 {20, 20}]

Total[#, 2] & /@ {a2, a3, a4}

{300, 300, 300}

$\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.