Random walk sum of values greater than 0 in R - r

I want to write a function such that rwabovex is the sum of the values of S that are greater than 0. (My S is a random walk simulation)
Here's what I have so far but I'm not getting the right output. Can you please help?
rwabovex=function(n){
if (n <= 0) {
return(cat("n must be greater than 0"))
} else {
S=numeric(n)
S[1] = 0
above = 0
for(i in 2:n) {
step=c(1, -1)
S[i]=S[i-1]+sample(step, 1, prob = c(0.5, 0.5), replace = TRUE)
if (S[i] > 0) {
above = above + S[i]
}
print(above)
}
}
}
For example: if n=4 and the S values are -1, 2, 1, 0 then "above" should equal to 3 (since 2 and 1 are greater than 0).
Thanks!

First, you're not using vectorization to compute S, which will make the procedure slow for large n. You can vectorize using cumsum. Secondly, you can use sum to compute the sum of values in S greater than 0:
rwabovex = function(n) {
step = c(1, -1)
S = c(0, cumsum(sample(step, n-1, prob=c(.5, .5), replace=T)))
print(S)
return(sum(S[S > 0]))
}
set.seed(144)
rwabovex(10)
# [1] 0 -1 0 1 2 1 2 1 2 1
# [1] 10

Related

Random Sample in R: Limiting Number of Repetitionsout of a 2 digit vector

I have the following vector in R: c(0,1).
I am wishing to randomly sample from this vector 10 elements at a time, but such that no more than 2 elements repeat.
The code I have tried is sample(c(0,1),10,replace=T)
But I would like to get
sample(c(0,1),10,replace=T) = (0,1,1,0,1,1,0,0,1,0)
sample(z,4,replace=T) = (0,1,0,1,0,0,1,0,1,0)
but not
sample(z,4,replace=T) = (1,0,0,0,1,1,0,0,0)
And so on.
How could I accomplish this?
Since the number of repeats can only be 1 or 2, and since the value needs to alternate, you can achieve this in a one-liner by randomly choosing 1 or 2 repeats of each of a sequence of 1s and 0s, and truncating the result to 10 elements.
rep(rep(0:1, 5), times = sample(c(1:2), 10, TRUE))[1:10]
#> [1] 0 0 1 1 0 1 1 0 1 0
If you wish to remove the constraint of the sequence always starting with a zero, you can randomly subtract the result from 1:
abs(sample(0:1, 1) - rep(rep(0:1, 5), times = sample(c(1:2), 10, TRUE))[1:10])
#> [1] 1 1 0 0 1 0 0 1 1 0
foo <- function(){
innerfunc <- function(){sample(c(0, 1), 10, T)}
x <- innerfunc()
while(max(rle(x)$lengths) > 2){
x <- innerfunc()
}
x
}
foo()
This function will look at the max length of a sequence of zeroes and ones. If this is > 2, it reruns your sample function, named innerfunc in here.
I think this is an interesting coding practice if you would like to use recurssions, and below might be an option that gives some hints
f <- function(n) {
if (n <= 2) {
return(sample(c(0, 1), n, replace = TRUE))
}
m <- sample(c(1, 2), 1)
v <- Recall(n - m)
c(v, rep((tail(v, 1) + 1) %% 2, m))
}

How to use function "caralloc" (in R package SeqAlloc) to randomize people into three conditions?

I want to use function "caralloc" from SeqAlloc package to randomize people into three rather than default two conditions.
function (xmat, carwt, p, tol)
{
if (!is.matrix(xmat))
xmat = as.matrix(xmat)
n = nrow(xmat)
result = rbinom(n, 1, 0.5)
if (n > 1) {
for (j in 2:n) {
matchx = apply(xmat[1:(j - 1), , drop = FALSE],
1, function(x, xrow) {
as.numeric(x == xrow)
}, xmat[j, ])
sumsofar = matchx %*% (2 * result[1:(j - 1)] - 1)
imbalance1 = crossprod(abs(sumsofar + 1), carwt)
imbalance0 = crossprod(abs(sumsofar - 1), carwt)
if (imbalance1 < imbalance0 & imbalance0 >= tol)
result[j] = rbinom(1, 1, p)
if (imbalance0 < imbalance1 & imbalance1 >= tol)
result[j] = rbinom(1, 1, 1 - p)
}
}
result
}
Use the package example:
sampsize <- 200
percent <- c(0.5,0.8,0.2,0.4)
carwt <- c(.4,.3,.2,.1)
set.seed(5798)
xmat <- matrix(rbinom(sampsize*length(percent),1,rep(percent,sampsize)),
nrow=sampsize,ncol=length(percent),byrow=TRUE)
colnames(xmat) = c("C1","C2","C3","C4")
strat_factor = xmat[,1]*4 + xmat[,2]*2 + xmat[,4] + 1
caralloc(xmat,carwt,1,3)
The default two conditions would be like:
1 1 0 0 1 0 0 1 0 0 0 ...
I want to see three conditions like:
1 1 2 0 1 0 0 2 0 1 0 ...
That sounds incredibly hard to just randomise your groups.
Can't you just use the sample() function?
df <- data.frame(
# some 1000 test patients:
patient = paste0(letters, round(runif(1000, 100, 999))),
# assigning a group: 0, 1 or 2:
group = sample(c(0:2), 1000, replace = TRUE))
head(df)
#> patient group
#> 1 a729 1
#> 2 b633 2
#> 3 c831 2
#> 4 d111 2
#> 5 e406 1
#> 6 f491 0
# evenly distributed?
hist(df$group)
To use predefined sizes of groups, use the prob argument:
df <- data.frame(
# some 1000 test patients:
patient = paste0(letters, round(runif(1000, 100, 999))),
# assigning a group: 0, 1 or 2:
group = sample(c(0:2), 1000, replace = TRUE, prob = c(0.1, 0.4, 0.5)))
hist(df$group)

Sum from each 0 position in a 0 1 vector in R

I am trying to calculate the sum of all 1s after each 0 in a vector of 0s and 1s.
E.g.,
0 0 1 0 1
would be:
2 (all 1s after 1st 0) + 2 (all 1s after 2nd zero) + 1 (one 1 after 3rd zero on the 4th position) = 5
So not 6 what would be the case if you just sum the whole vector for each 0 in the vector (3*2).
This is what I have tried but does not work:
a <- rbinom(10, 1, 0.5)
counter <- 0
for (i in a){
if(i == 0)
counter <- counter + sum(a[i:10])
}
print(counter)
I first create a vector of 10 random 0s and 1s. I make a counter which starts at 0, then I try to calculate the sum from each i position until the final position (10th), but only when i equals 0.
What it actually does is just calculate the sum of all 1s for each 0 in the vector.
Thanks for any help on this!
Given
x <- c(0, 0, 1, 0, 1)
Here is a vectorized way
sum(rev(cumsum(rev(x))) * !x)
#[1] 5
Or using this input
set.seed(1)
a <- rbinom(10, 1, 0.5)
a
# [1] 0 0 1 1 0 1 1 1 1 0
The result is
sum(rev(cumsum(rev(a))) * !a)
# [1] 16
step by step
When we calculate the reversed cumulative sum of rev(x) we get
rev(cumsum(rev(x)))
# [1] 2 2 2 1 1
The result shows us for each element in x how many 1s there are until the end of the vector.
The idea to multiply this vector by !x is that we later only want to sum those elements for which x is zero, i.e. not 1 (or not TRUE).
Result
rev(cumsum(rev(x))) * !x
# [1] 2 2 0 1 0
This needs to be summed up to get desired output.
Try this:
a <- rbinom(10, 1, 0.5)
counter <- 0
for (i in seq_along(a)){
if(a[i] == 0)
counter <- counter + sum(a[i:10])
}
print(counter)
In yours example i is not an iterator. It's a value of a vector. So a[i:10] gives either a[0:10] or a[1:10].

generating random vector in r with particular sum

My aim is to create a vector, with sum 0, in which there are the same number of entries -x and the same number of entry equals x, the length of the vector is even, so it sums up to 0.
I created a function, that has x as an input.
there i insert a sample of the vectorlength but i the end it doesn't work out.
vector<-function(x){
for(i in length(sample)){
if(i %% 2!=0){
output[sample[i]]<-(-x)
}
if(i %% 2 ==0){
output[sample[i]]<-x
}
}
return(output)
}
Try this:
vector <- function(x, sample){
c(rep(x, sample/2), rep(-x, sample/2))
}
print(vector(x = 1, sample = 4))
# [1] 1 1 -1 -1
Edit
If alterning is required:
vector <- function(x, sample){
c(rbind(rep(-x, sample/2), rep(x, sample/2)))
}
print(vector(x = 1, sample = 4))
# [1] -1 1 -1 1
You can try
foo <- function(x, sample){
a <- sample(sample, x/2, replace = T)
c(a,-a)
# or alternating
# c(rbind(a,-a))
}
set.seed(123)
foo(4, 1:10)
[1] 3 8 -3 -8
According to the title you are looking for a random vector. In that case you can simply first generate an ordered vector with the desired properties and then use sample to shuffle it:
f <- function(x, size){
sample(c(rep(x, size/2), rep(-x, size/2), if(size %% 2 != 0) 0))
}
f(x = 1, size = 6)
#> [1] 1 -1 -1 1 -1 1
f(x = 1, size = 7)
#> [1] 0 -1 -1 1 -1 1 1
Edit: Now the function even allows for an odd size.

swap n percent of ones to zeros in R

I have a vector A which contains zeros and ones. I would like to randomly change n percent of the ones to zero. Is this the best way to do it in R (10% change):
for (i in 1:length(A))
{
if(A[i] > 0)
{
if(runif(1) <= 0.1)
{
A[i] = 0
}
}
}
Thanks.
You can do this without using the for loops and if statements:
##Generate some data
R> A = sample(0:1, 100, replace=TRUE)
##Generate n U(0,1) random numbers
##If any of the U's are less then 0.1
##Set the corresponding value in A to 0
R> A[runif(length(A)) < 0.1] = 0
The other point to note, is that you don't have to do anything special for values of A that actually equal 0, as the probability of change a 1 to a 0 is still 0.1.
As Hadley points out, your code doesn't randomly change 10% of 1's to 0. If that is really your intention, then:
##Select the rows in A equal to 1
R> rows_with_1 = (1:length(A))[A==1]
##Randomly select a % of these rows and set equal to zero
##Warning: there will likely be some rounding here
R> A[sample(rows_with_1, length(rows_with_1)*0.1)] = 0
If this is your A:
A <- round(rnorm(100, 0.5, 0.1))
This should do it:
n <- 10
A[sample(A[A==1], length(A[A==1])*n/100)] <- 0
where n is the percentage of your 1s that you want to change to 0s.
You can vectorize that:
A <- round(runif(20), 0)
A[sample(which(A == 1), 0.1 * length(A == 1))] <- 0
HTH

Resources