Reputation: 43
I want to make a random matrix with n rows and m columns. I want the elements of each row of the matrix to be randomly chosen from a set of numbers. I want to have at least one different number in each row. I don't want all the elements of a row to be the same. I once asked my question here, but I don't know why the function I was provided still gives me some rows with all the same elements. How can I adjust this function?
f2 <- function(x, n, m) {
if ( length(unique(x)) == 1 ) {
stop('x has only one unique element.', call. = FALSE)
}
result <- t(replicate(n, sample(x, m, replace = TRUE)))
while ( any(apply(result, 1, function(x) length(unique(result)) == 1)) ) {
result <- t(replicate(n, sample(x, m, replace = TRUE)))
}
return(result)}
Here is an example:
x <- c(1, 1.5, 2, 3,4)
set.seed(123456)
matall=f2(x, 1200, 4)
View(matall)
[,1] [,2] [,3] [,4]
[1,] 3.0 3.0 1.5 1.5
[2,] 1.5 1.0 2.0 1.0
[3,] 4.0 1.0 3.0 2.0
[4,] 4.0 4.0 4.0 4.0
Upvotes: 0
Views: 114
Reputation: 42544
There is a typo in the function definition. The while
clause should read
while ( any(apply(result, 1, function(x) length(unique(x)) == 1)) ) {
instead of
while ( any(apply(result, 1, function(x) length(unique(result)) == 1)) ) {
However, the function does not terminate quickly as it tries to create the whole matrix anew each time a row with identical values is found.
The improved version only replaces rows with identical values
f3 <- function(x, n, m) {
if ( length(unique(x)) == 1 ) {
stop('x has only one unique element.', call. = FALSE)
}
result <- replicate(m, sample(x, n, replace = TRUE))
uni_rows <- apply(result, 1, function(x) length(unique(x)) == 1)
while ( any(uni_rows) ) {
result[which(uni_rows), ] <- replicate(m, sample(x, sum(uni_rows), replace = TRUE))
uni_rows <- apply(result, 1, function(x) length(unique(x)) == 1)
}
return(result)
}
Now,
x <- c(1, 1.5, 2, 3, 4)
set.seed(123456)
matall <- f3(x, 1200, 4)
any(apply(matall, 1, function(x) length(unique(x)) == 1))
[1] FALSE
returns
head(matall, 11)
[,1] [,2] [,3] [,4] [1,] 3.0 3 1.5 1.5 [2,] 1.5 1 2.0 1.0 [3,] 4.0 1 3.0 2.0 [4,] 2.0 4 3.0 1.0 [5,] 4.0 1 1.5 3.0 [6,] 4.0 3 2.0 3.0 [7,] 2.0 3 4.0 4.0 [8,] 4.0 1 2.0 4.0 [9,] 1.5 1 4.0 1.0 [10,] 4.0 4 3.0 3.0 [11,] 1.5 3 4.0 1.5
Upvotes: 1
Reputation: 54237
I want to make a random matrix with n rows and m columns.
cols <- 3; rows <- 3
m <- matrix(ncol = cols, nrow = rows)
I want the elements of each row of the matrix to be randomly chosen from a set of numbers.
set.seed(2)
set <- seq(ncol(m)-1L)
m[] <- sample(set, length(m), replace = T)
m
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 2 2 2
# [3,] 2 2 1
I want to have at least one different number in each row.
rowRanges <- matrixStats::rowRanges(m)
(isSingle <- rowRanges[,2]-rowRanges[,1]==0)
# [1] TRUE TRUE FALSE
m[isSingle,1] <- vapply(rowRanges[isSingle, 1], function(x) set[set!=x][1], 0L)
m
# [,1] [,2] [,3]
# [1,] 2 1 1
# [2,] 1 2 2
# [3,] 2 2 1
or, if you want to randomize the assignment in terms of which set value and which column to choose:
vsample <- Vectorize(function(x) sample(set[set!=x], size = 1L), "x")
idx <- cbind(row=which(isSingle), col=sample(ncol(m), sum(isSingle), replace = TRUE))
mvals <- vsample(rowRanges[isSingle, 1])
m[idx] <- mvals
Upvotes: 1