Conditional multiplication of vector entries

Viewed 45

In R i have a vector where always each five consecutive elements are equal

v=(a, a, a, a, a, a, b, b, b, 
   b,  b....)

I want to multiplicate it with values from [0.99,1.01] because I want a slight variation over the entries but the mean has to stay the same as before, i.e the mean of the first 5 entries of the new vector has also to be a

I would prefer it if the values from [0.99,1.01] are randomly chosen (with runif for example) , but deterministic would also be okay, if it would be too complicated to achive the condition with random numbers.

Would really appreciate any kind of help

2 Answers

A little late, but here's function that is vectorized over a, b, ...

runifMean <- function(n, length, xmin, xmax){
  m <- matrix(0, nrow = n, ncol = length)
  m[, 1] <- runif(n, -1, 1)
  summ <- m[, 1]
  
  for(i in 2:(length - 1)){
    m[, i] <- -runif(n)*sign(summ)
    summ <- summ + m[, i]
  }
  
  m[, length] <- -summ
  return(m*(xmax - xmin)/2 + (xmax + xmin)/2)
}

It returns a matrix with n rows and length columns. Each row has random values between xmin and xmax that average to (xmax - xmin)/2.

set.seed(123)
v <- rep(runif(4), each = 5) # original vector
vR <- v*as.vector(t(runifMean(4, 5, 0.99, 1.01))) # with random perturbations
# check that the means from vR equal the original values from v
rowMeans(matrix(vR, nrow = 4, byrow = TRUE)) == v[seq(by = 5, length.out = 4)]
[1] TRUE TRUE TRUE TRUE

There has to be an easier way to do this, but this is a potential solution:

library(tidyverse)
vec1 <- rep(1:10, each = 5)
vec2 <- c(0.98, 0.99, 1, 1.01, 1.02)

vec3 <- c()
for (i in split(vec1, ceiling(seq_along(vec1)/5))){
  result <- i * sample(vec2)
  vec3 <- c(vec3, result)
}

vec3
#  [1]  1.02  0.99  0.98  1.00  1.01  2.04  2.02  1.98  2.00  1.96  3.03  2.97  3.00
# [14]  2.94  3.06  4.04  3.92  3.96  4.00  4.08  5.10  5.05  5.00  4.95  4.90  5.88
# [27]  5.94  6.06  6.12  6.00  7.14  6.93  7.00  6.86  7.07  7.92  7.84  8.08  8.00
# [40]  8.16  9.00  9.09  8.82  8.91  9.18  9.80 10.20 10.10 10.00  9.90  1.02  1.00
# [53]  1.01  0.98  0.99  1.96  2.00  1.98  2.04  2.02  2.94  3.00  3.06  2.97  3.03
# [66]  3.96  4.08  3.92  4.04  4.00  5.10  4.90  4.95  5.05  5.00  6.00  6.12  5.88
# [79]  6.06  5.94  7.14  7.07  7.00  6.86  6.93  7.84  8.16  7.92  8.00  8.08  9.09
# [92]  9.18  8.82  9.00  8.91 10.10  9.80 10.20  9.90 10.00

mean(c(vec3[1:5]))
[1] 1
mean(c(vec3[6:10]))
[1] 2
Related