I am attempting to write R code that will draw from a binomial distribution but will repeat for every value in a specified column in a data frame. I generated a data frame in r such that the first column "Lambda" represents annual population change. I repeated this value 50 times so each row in the data frame represents one year. I created a second column "Truth.Pop" to represent the true population size projected for 50 years assuming initial population size = 50,000.
I am running into issues when I attempt to fill in my column 3 "Avail1". I would like for each row in the Avail1 column to be a draw from a binomial distribution using the corresponding population size in the Total.Pop column and a probability of 0.82.
lambda<-as.data.frame(vec_rep(0.99,50)) # create dataframe
colnames(lambda)<-c("Lambda")
lambda$Truth.Pop<-vec_rep(NA,50) # projected lambda for 50 yrs
lambda[1,2]=50000 # initial population size
for (i in 2:50) { # fill in the remaining rows
lambda$Truth.Pop[i] <- lambda[i-1,2]*lambda[i,1]
}
# issues begin here:
lambda$Avail1<-vec_rep(NA,50)
lambda[1,3]<-rbinom(1,lambda[1,2],0.82)
rbinom(50,lambda$Truth.Pop,0.82)
I attempted to write a for loop structured very similarly to the one I used to fill in column two which would replace the last line of code above:
for (i in 2:50) {
lambda$Avail1[i]<-rbinom(1,lambda$Truth.Pop[i],0.82)
}
# ALTERNATIVE
for (i in seq_len(nrow(lambda))) {
lambda[i,3]<-rbinom(1,lambda[i,2],0.82)
}
I also attempted in various capacities the sapply(), lapply() and replicate() functions but none of them worked. In addition, changing n=1 to n=50 within rbinom() did not work.
In any attempt, the most common result was for the code to run but the first three values within the Avail1 column to be the only ones filled in with the rest being NAs. Another result I achieved was for all values to be filled in but such that they were all the same. That should not happen as each size input changes for each row of data.
Many thanks in advance.
rbinom
expects an integer value for the size
argument. I would suggest using round
, floor
, or as.integer
:
lambda <- data.frame(Truth.Pop = 5e4*0.99^(0:49))
transform(lambda,
AvailNA = rbinom(50, Truth.Pop, 0.82),
Avail = rbinom(50, round(Truth.Pop), 0.82))
#> Warning in rbinom(50, Truth.Pop, 0.82): NAs produced
#> Truth.Pop AvailNA Avail
#> 1 50000.00 41082 41062
#> 2 49500.00 40502 40563
#> 3 49005.00 40298 40275
#> 4 48514.95 NA 39775
#> 5 48029.80 NA 39216
#> 6 47549.50 NA 38930
#> 7 47074.01 NA 38654
#> 8 46603.27 NA 38138
#> 9 46137.23 NA 37992
#> 10 45675.86 NA 37460
#> 11 45219.10 NA 37054
#> 12 44766.91 NA 36595
#> 13 44319.24 NA 36284
#> 14 43876.05 NA 35926
#> 15 43437.29 NA 35530
#> 16 43002.92 NA 35210
#> 17 42572.89 NA 34954
#> 18 42147.16 NA 34602
#> 19 41725.69 NA 34237
#> 20 41308.43 NA 33928
#> 21 40895.35 NA 33507
#> 22 40486.39 NA 33147
#> 23 40081.53 NA 32762
#> 24 39680.71 NA 32693
#> 25 39283.91 NA 32262
#> 26 38891.07 NA 31893
#> 27 38502.16 NA 31585
#> 28 38117.14 NA 31304
#> 29 37735.96 NA 30923
#> 30 37358.60 NA 30754
#> 31 36985.02 NA 30376
#> 32 36615.17 NA 30014
#> 33 36249.02 NA 29777
#> 34 35886.53 NA 29413
#> 35 35527.66 NA 29212
#> 36 35172.38 NA 28788
#> 37 34820.66 NA 28710
#> 38 34472.45 NA 28222
#> 39 34127.73 NA 28000
#> 40 33786.45 NA 27654
#> 41 33448.59 NA 27344
#> 42 33114.10 NA 27132
#> 43 32782.96 NA 27028
#> 44 32455.13 NA 26546
#> 45 32130.58 NA 26123
#> 46 31809.27 NA 26089
#> 47 31491.18 NA 25875
#> 48 31176.27 NA 25448
#> 49 30864.51 NA 25272
#> 50 30555.86 NA 24895