fox
fox

Reputation: 167

Creating random matrix without one number

I want to generate a matrix of size n-1 x n such that the i-th column contains all number from 1 to n without containing i, i.e. the first column should contain all numbers from 2 to n, the second should contain 1,3,4,..., the third should contain 1,2,4,... and so on. Any ideas would be most welcomed.

Upvotes: 1

Views: 71

Answers (3)

markus
markus

Reputation: 26343

Use combn (not really random though).

n <- 5
out <- combn(n:1, n - 1)
out
#     [,1] [,2] [,3] [,4] [,5]
#[1,]    5    5    5    5    4
#[2,]    4    4    4    3    3
#[3,]    3    3    2    2    2
#[4,]    2    1    1    1    1

Shuffle each column if needed

set.seed(1)
apply(combn(n:1, n - 1), 2, sample)

If you are looking for efficiency, use the solution I posted ;)

library(microbenchmark)
n <- 1000
set.seed(1)
benchmark <- microbenchmark(
  akrun = vapply(seq_len(n), function(i) sample(setdiff(seq_len(n), i)), numeric(n-1)),
  markus = apply(combn(n:1, n - 1), 2, sample),
  A_Stam = create_matrix(n),
  times = 30L
)

enter image description here

benchmark
#Unit: milliseconds
#   expr        min         lq       mean     median         uq        max neval
#  akrun   64.32350   66.99177   73.61685   71.15608   78.79612  104.99161    30
# markus   51.65092   53.01034   59.80802   58.48310   64.76143   78.35348    30
# A_Stam 1331.52882 1379.70371 1470.31044 1407.89861 1548.28011 1896.22913    30

Upvotes: 5

akrun
akrun

Reputation: 887028

We loop through the sequence of 'n', get the sample of the sequence except the looped number (setdiff)

sapply(seq_len(n), function(i) sample(setdiff(seq_len(n), i)))
#     [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]    2    3    1    3    2    2
#[2,]    5    1    5    6    1    5
#[3,]    6    4    6    2    3    4
#[4,]    3    5    4    1    4    1
#[5,]    4    6    2    5    6    3

It can be made a bit more faster if we use vapply

vapply(seq_len(n), function(i) sample(setdiff(seq_len(n), i)), numeric(n-1))

NOTE: The OP mentioned random matrix in the post

data

n <- 6

Upvotes: 3

A. Stam
A. Stam

Reputation: 2222

This might not be the most elegant solution, but it works:

create_matrix <- function(n) {
  m <- c()
  for (i in 1:n) {
    new <- setdiff(1:n, i)
    m <- c(m, new)
  }
  matrix(m, ncol = n, byrow = FALSE)
}

create_matrix(4)

#>      [,1] [,2] [,3] [,4]
#> [1,]    2    1    1    1
#> [2,]    3    3    2    2
#> [3,]    4    4    4    3

Upvotes: 2

Related Questions