How to get all combinations(9,2) with the following restrictions:
n1 > 2,
n2 < 7,
n1 + n2 < 11.
There are 5 combinations in result: 3 4, 3 5, 3 6, 4 5, 4 6?
Or without any apply function
comb <- t(combn(9,2))
comb[comb[, 1] > 2 & comb[, 2] < 7 & comb[, 1] + comb[, 2] < 11, ]
I did this:
library(gtools)
a= combinations(9,2)
a =apply(a, 1, function(i){
if(i[1]>2&i[2]<7&(i[1]+i[2])<11){return(i)}
})
a= matrix(unlist(a), ncol = 2,byrow = T)
the output:
>a
[,1] [,2]
[1,] 3 4
[2,] 3 5
[3,] 3 6
[4,] 4 5
[5,] 4 6
Let me know if it was what you wanted
To find all those combinations I use combn which comes as standard with R and does not need any additional packages.
For filtering I use apply with an anonymous filtering function and which to find which combinations fullfill the filter criterion:
comb <- combn(9,2)
n <- apply(comb, 2, \(x) x[1] > 2 & x[2] < 7 & sum(x) < 11) |>
which()
comb[, n]
will yield
> comb[, n]
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 3 4 4
[2,] 4 5 6 5 6
Try the code below
Filter(
length,
combn(9,
2,
FUN = function(x) if (x[1] > 2 & x[2] < 7 & sum(x) < 11) list(x) else list(NULL)
)
)
which gives
[[1]]
[1] 3 4
[[2]]
[1] 3 5
[[3]]
[1] 3 6
[[4]]
[1] 4 5
[[5]]
[1] 4 6
Related
A reproducible example:
mat1 <- matrix(c(1,2,4,2,4,2,4,6,5,7,8,3), nrow = 3, ncol = 4, byrow = T)
mat2 <- matrix(c(2,1,7,8,2,6), nrow = 3, ncol = 2, byrow = T)
mat3 <- matrix(c(3,2,3,5,7,5,4,5,6,4,2,3,4,5,2), nrow = 3, ncol = 5, byrow = T)
list.mat <- list(mat1,mat2,mat3)
> list.mat
[[1]]
[,1] [,2] [,3] [,4]
[1,] 1 2 4 2
[2,] 4 2 4 6
[3,] 5 7 8 3
[[2]]
[,1] [,2]
[1,] 2 1
[2,] 7 8
[3,] 2 6
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 3 2 3 5 7
[2,] 5 4 5 6 4
[3,] 2 3 4 5 2
Objective 1: Find the minimum of each rows of each element. Expected output [[1]]-> 1,2,3 [[2]]-> 1,7,2 [[3]]-> 2,4,2
Objective 2: Find the corresponding column numbers. Expected output [[1]]-> 1,2,4 [[2]]-> 2,1,1 [[3]]-> 2,2,1
***NOTE that in [[3]][3,] there are two minimum numbers, one in column 1 and other in column 5. In such case, only report the column that comes first.
Objective 3: Find the sum of the output found in objective 1 separately for each list. Expected outcome [[1]]-> 6 [[2]]-> 10 [[3]]-> 8
I am looking for a general solution applicable to a much larger list than the example provided.
You can use lapply :
output1 <- lapply(list.mat, function(x) apply(x, 1, min))
output1
#[[1]]
#[1] 1 2 3
#[[2]]
#[1] 1 7 2
#[[3]]
#[1] 2 4 2
output2 <- lapply(list.mat, function(x) apply(x, 1, which.min))
output2
#[[1]]
#[1] 1 2 4
#[[2]]
#[1] 2 1 1
#[[3]]
#[1] 2 2 1
output3 <- lapply(output1, sum)
output3
#[[1]]
#[1] 6
#[[2]]
#[1] 10
#[[3]]
#[1] 8
You can put the code in a function if you want to apply this for multiple such lists.
We could use dapply from collapse which could be faster
library(collapse)
lapply(list.mat, dapply, fmin, MARGIN = 1)
#[[1]]
#[1] 1 2 3
#[[2]]
#[1] 1 7 2
#[[3]]
#[1] 2 4 2
Here is a base R option using pmin
> lapply(list.mat, function(x) do.call(pmin, data.frame(x)))
[[1]]
[1] 1 2 3
[[2]]
[1] 1 7 2
[[3]]
[1] 2 4 2
I would like to use this code, which I found here: Generate N random integers that sum to M in R. I have a example data frame and I would like to use this function for each Value in data frame.
rand_vect <- function(N, M, sd = 1, pos.only = TRUE) {
vec <- rnorm(N, M/N, sd)
if (abs(sum(vec)) < 0.01) vec <- vec + 1
vec <- round(vec / sum(vec) * M)
deviation <- M - sum(vec)
for (. in seq_len(abs(deviation))) {
vec[i] <- vec[i <- sample(N, 1)] + sign(deviation)
}
if (pos.only) while (any(vec < 0)) {
negs <- vec < 0
pos <- vec > 0
vec[negs][i] <- vec[negs][i <- sample(sum(negs), 1)] + 1
vec[pos][i] <- vec[pos ][i <- sample(sum(pos ), 1)] - 1
}
vec
}
abc <- data.frame(Product = c("A", "B", "C"),
Value =c(33, 23, 12))
You can vectorize your function rand_vect for receiving a array of values
vrand_vect <- Vectorize(rand_vect,"M",SIMPLIFY = F)
which gives
res <- vrand_vect(N= 7, M = abc$Value)
> res
[[1]]
[1] 3 5 6 6 4 3 6
[[2]]
[1] 1 3 4 5 3 4 3
[[3]]
[1] 1 2 3 3 1 2 0
You can use sapply to run rand_vect with N = 7
sapply(abc$Value, rand_vect, N = 7)
# [,1] [,2] [,3]
#[1,] 4 4 0
#[2,] 5 2 2
#[3,] 5 4 2
#[4,] 4 3 3
#[5,] 5 5 3
#[6,] 6 2 1
#[7,] 4 3 1
This will give 7 random numbers which will sum upto Value.
We can verify it by
colSums(sapply(abc$Value, rand_vect, N = 7))
#[1] 33 23 12
This question already has answers here:
Add each element in one vector with each element in a second vector
(3 answers)
Closed 4 years ago.
I have 2 vectors of different sizes:
vector1 = [1, 2, 3]
vector2 = [1, 2, 3, 4, 5]
I want to make operations between them. Each number from the vector1 plus each number from the vector2. Something like that:
I'm trying unsuccessfully a for inside a for. Any help?
vector1 <- data.frame(c(1, 2, 3))
vector2 <- data.frame(c(1, 2, 3, 4, 5))
for (i in vector1) {
for (j in vector2) {
a <- i + j
}
}
This is the message error
Warning message:
In i + j : longer object length is not a multiple of shorter object length
You can use outer
> vector1 <- c(1, 2, 3)
> vector2 <- c(1, 2, 3, 4, 5)
> outer(vector1, vector2, FUN="+")
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
If you really want to use a loop, you can use a nested for loop:
> result <- matrix(0, nrow = length(vector1), ncol=length(vector2))
> for(i in seq_len(length(vector1))){
for(j in seq_len(length(vector2))){
result[i,j] <- sum(vector1[i], vector2[j])
}
}
> result
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
for is a very inefficient way to do this. Here's a way using sapply from base R although I feel there should be an even better way -
c(sapply(vector1, function(x) x + vector2))
# [1] 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8
My aim is to extract certain values from a matrix with an operator like this one: z<x<y
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
From these matrix a want to extract values which are lower than 3 and higher than 6. I would be very thankful if anybody would help me.
Try this:
z <- matrix(1:9, 3, 3, byrow = TRUE)
z[z < 3 | z > 6]
# [1] 1 7 2 8 9
Sorted:
sort(z[z < 3 | z > 6])
# [1] 1 2 7 8 9
I have a matrix with 5 columns and 4 rows. I also have a vector with 3 columns. I want to subtract the values in the vector from columns 3,4 and 5 respectively at each row of the matrix.
b <- matrix(rep(1:20), nrow=4, ncol=5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
c <- c(5,6,7)
to get
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 4 7 10
[2,] 2 6 5 8 11
[3,] 3 7 6 9 12
[4,] 4 8 7 10 13
This is exactly what sweep was made for:
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5,6,7)
b[,3:5] <- sweep(b[,3:5], 2, x)
b
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 5 4 7 10
#[2,] 2 6 5 8 11
#[3,] 3 7 6 9 12
#[4,] 4 8 7 10 13
..or even without subsetting or reassignment:
sweep(b, 2, c(0,0,x))
Perhaps not that elegant, but
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5,6,7)
b[,3:5] <- t(t(b[,3:5])-x)
should do the trick. We subset the matrix to change only the part we need, and we use t() (transpose) to flip the matrix so simple vector recycling will take care of subtracting from the correct row.
If you want to avoid the transposed, you could do something like
b[,3:5] <- b[,3:5]-x[col(b[,3:5])]
as well. Here we subset twice, and we use the second to get the correct column for each value in x because both those matrices will index in the same order.
I think my favorite from the question that #thelatemail linked was
b[,3:5] <- sweep(b[,3:5], 2, x, `-`)
Another way, with apply:
b[,3:5] <- t(apply(b[,3:5], 1, function(x) x-c))
A simple solution:
b <- matrix(rep(1:20), nrow=4, ncol=5)
c <- c(5,6,7)
for(i in 1:nrow(b)) {
b[i,3:5] <- b[i,3:5] - c
}
This can be done with the rray package in a very satisfying way (using its (numpy-like) broadcasting - operator %b-%):
#install.packages("rray")
library(rray)
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5, 6, 7)
b[, 3:5] <- b[, 3:5] %b-% matrix(x, 1)
b
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 5 4 7 10
#> [2,] 2 6 5 8 11
#> [3,] 3 7 6 9 12
#> [4,] 4 8 7 10 13
For large matrices this is even faster than sweep:
#install.packages("bench")
res <- bench::press(
size = c(10, 1000, 10000),
frac_selected = c(0.1, 0.5, 1),
{
B <- matrix(sample(size*size), nrow=size, ncol=size)
B2 <- B
x <- sample(size, size=ceiling(size*frac_selected))
idx <- sample(size, size=ceiling(size*frac_selected))
bench::mark(rray = {B2[, idx] <- B[, idx, drop = FALSE] %b-% matrix(x, nrow = 1); B2},
sweep = {B2[, idx] <- sweep(B[, idx, drop = FALSE], MARGIN = 2, x); B2}
)
}
)
plot(res)