R double loop with where - r

I have the the following data frame and variables:
u0 <- c(1,1,1,1,1)
df <- data.frame (u0)
a = .793
b = 2.426
r = 0.243
q = 1
w = 2
j = 1
z = .314
using the following loop I am doing some calculations and put the results in the first row of my data frame.
while (j<5){
df[q,w] <- df[q, w-1] * (r+j-1)*(b+j-1)*(z) / ((a+b+j-2)*j)
j = j + 1
w = w + 1
}
now I want to create another loop to do the same calculations for all rows (i.e I need the 'q' variable to vary) of my data frame. I would be thankful if anyone helps me.

You could either do this by putting your while loop inside of a for loop that goes over q, but a more R-tastic way would be to simply define q <- 1:5, and leave the rest of your code as-is. Then df will fill up entirely. I take it in this example you want all rows to be identical?

Can't you just put it in a for loop?
df <- data.frame (d1=u0, d2=u0+1, d3=u0+2, d4=u0+4, d5=u0+5)
for (q in 2:5) {
while (j<5){
df[q,w] <- df[q, w-1] * (r+j-1)*(b+j-1)*(z) / ((a+b+j-2)*j)
j = j + 1
w = w + 1
} }
You may want to check the algorithm. It doesn't seem to be doing anything very interesting.

Related

Is it possible to use the value of a vector as the name of another vector?

suppose I have a vector:
outYr
in a loop with the value of outYr changing every time it loops:
require(Metrics)
itrcnt <- 10
count <- 0
x <- c(1:99)
y <- (2:100)
for( i in 1:itrcnt)
{
outYr = 1998 + count
print(paste(outYr,'has been excluded'))
RMSE(outYr value) <- rmse(x,y)
count <-count + 1
}
I wish to use the value of outYr at the end of the loop as a name for another vector, for example:
RMSE(outYr value) <- rmse(x,y)
would end up looking like
RMSE1998 <- rmse (x,y)
Is there a way to do this?
Edit1: I have been pointed toward using paste() and will update if I can figure it out.
I initialized an empty list:
RMSE <-list()
Then filled the indices in the loop:
require(Metrics)
itrcnt <- 10
count <- 0
RMSE <- list()
x <- c(1:99)
y <- (2:100)
for( i in 1:itrcnt)
{
outYr = 1998 + count
print(paste(outYr,'has been excluded'))
RMSE[count +1] <- rmse(x,y)
count <-count + 1
}

How to use grep function in for loop

I have troubles using the grep function within a for loop.
In my data set, I have several columns where only the last 5-6 letters change. With the loop I want to use the same functions for all 16 situations.
Here is my code:
situations <- c("KKKTS", "KKKNL", "KKDTS", "KKDNL", "NkKKTS", "NkKKNL", "NkKDTS", "NkKDNL", "KTKTS", "KTKNL", "KTDTS", "KTDNL", "NkTKTS", "NkTKNL", "NkTDTS", "NkTDNL")
View(situations)
for (i in situations[1:16]) {
## Trust Skala
a <- vector("numeric", length = 1L)
b <- vector("numeric", length = 1L)
a <- grep("Tru_1_[i]", colnames(cleandata))
b <- grep("Tru_5_[i]", colnames(cleandata))
cleandata[, c(a:b)] <- 8-cleandata[, c(a:b)]
attach(cleandata)
cleandata$scale_tru_[i] <- (Tru_1_[i] + Tru_2_[i] + Tru_3_[i] + Tru_4_[i] + Tru_5_[i])/5
detach(cleandata)
}
With the grep function I first want to finde the column number of e.g. Tru_1_KKKTS and Tru_5_KKKTS. Then I want to reverse code the items of the specific column numbers. The last part worked without the loop when I manually used grep for every single situation.
Here ist the manual version:
# KKKTS
grep("Tru_1_KKKTS", colnames(cleandata)) #29 -> find the index of respective column
grep("Tru_5_KKKTS", colnames(cleandata)) #33
cleandata[,c(29:33)] <- 8-cleandata[c(29:33)] # trust scale ranges from 1 to 7 [8-1/2/3/4/5/6/7 = 7/6/5/4/3/2/1]
attach(cleandata)
cleandata$scale_tru_KKKTS <- (Tru_1_KKKTS + Tru_2_KKKTS + Tru_3_KKKTS + Tru_4_KKKTS + Tru_5_KKKTS)/5
detach(cleandata)
You can do:
Mean5 <- function(sit) {
cnames <- paste0("Tru_", 1:5, "_", sit)
rowMeans(cleandata[cnames])
}
cleandata[, paste0("scale_tru_", situations)] <- sapply(situations, FUN=Mean5)
how about something like this. It's a bit more compact and you don't have to use attach..
situations <- c("KKKTS", "KKKNL", "KKDTS", "KKDNL", "NkKKTS", "NkKKNL", "NkKDTS", "NkKDNL", "KTKTS", "KTKNL", "KTDTS", "KTDNL", "NkTKTS", "NkTKNL", "NkTDTS", "NkTDNL")
for (i in situations[1:16]) {
cols <- paste("Tru", 1:5, i, sep = "_")
result <- paste("scale_tru" , i, sep = "_")
cleandata[cols] <- 8 - cleandata[cols]
cleandata[result] <- rowMeans(cleandata[cols])
}
I took for granted that when you write a:b you mean all the columns between those, which I assumed were named from 2 to 4
situations <- c("KKKTS", "KKKNL", "KKDTS", "KKDNL", "NkKKTS", "NkKKNL", "NkKDTS", "NkKDNL", "KTKTS", "KTKNL", "KTDTS", "KTDNL", "NkTKTS", "NkTKNL", "NkTDTS", "NkTDNL")
# constructor for column names
get_col_names <- function(part) paste("Tru", 1:5, part, sep="_")
for (situation in situtations) {
# revert the values in the columns in situ
cleandata[, get_col_names(situation)] <- 8 - cleandata[, get_col_names(situtation)]
# and calculate the average
subdf <- cleandata[, get_col_names(situation)]
cleandata[, paste0("scale_tru_", situation)] <- rowSums(subdf)/ncol(subdf)
}
By the way, you call it "scale" but your code shows an average/mean calculation.
(Scale without centering).

How to define a recursive for loop in R?

I have a priorly unknown number of variables, and for each variable I need to define a for loop and perform a series of operations. For each subsequent variable, I need to define a nested loop inside the previous one, performing the same operations. I guess there must be a way of doing this recursively, but I am struggling with it.
Consider for instance the following easy example:
results = c()
index = 0
for(i in 1:5)
{
a = i*2
for(j in 1:5)
{
b = a*2 + j
for(k in 1:5)
{
index = index + 1
c = b*2 + k
results[index] = c
}
}
}
In this example, I would have 3 variables. The loop on j requires information from the loop i, and the loop on k requires information from the loop j. This is a simplified example of my problem and the operations here are pretty simple. I am not interested on another way of getting the "results" vector, what I would like to know is if there is a way to recursevily do this operations for an unknown number of variables, lets say 10 variables, so that I do not need to nest manually 10 loops.
Here is one approach that you might be able to modify for your situation...
results <- 0 #initialise
for(level in 1:3){ #3 nested loops - change as required
results <- c( #converts output to a vector
outer(results, #results so far
1:5, #as in your loops
FUN = function(x,y) {x*2+y} #as in your loops
)
)
}
The two problems with this are
a) that your formula is different in the first (outer) loop, and
b) the order of results is different from yours
However, you might be able to find workarounds for these depending on your actual problem.
I have tried to change the code so that it is a function that allows to define how many iterations need to happen.
library(tidyverse)
fc <- function(i_end, j_end, k_end){
i <- 1:i_end
j <- 1:j_end
k <- 1:k_end
df <- crossing(i, j, k) %>%
mutate(
a = i*2,
b = a*2 + j,
c = b*2 + k,
index = row_number())
df
}
fc(5,5,5)

R fill several empty matrices with loop

I would like to fill my created empty matrices with a loop:
First I have created my empty matrizes, which works fine:
for(q in (15:30)){
assign(paste0("P",q), matrix(, nrow = q, ncol = q+1))}
But now when I want to fill these matrices with my formula, I get an dimension mistake:
for(c in (1:q+1)){
for(i in (1:q)){assign(paste0("P",q)[i,c],
((((((q-c) + 1 -(q-c+1- i))/q)^.69)/(((((q-c) + 1 - (q-c+1-i))/q)^.69+(((1 - ((q-c) + 1 -(q-c+1-i))/q))^.69))^(1/.69))) - (((((q-c)-(q-c+1-i))/q)^.69)/(((((q-c) - (q-c+1-i))/q)^.69+(((1 - ((q-c)-(q-c+1-i))/q))^.69))^(1/.69)))))}}}
Nevertheless when I use this loop for a single matrix it works e.g.:
t <- 20
c <- 1
i <- 1
for(c in (1:t+1)){
for(i in (1:t)){P20[i,c]<-( (((((t-c) + 1 -(t-c+1-i))/t)^.69)/
(((((t-c) + 1 - (t-c+1-i))/t)^.69+(((1 - ((t-c) + 1 -(t-c+1-i))/t))^.69))^(1/.69))) -
(((((t-c)-(t-c+1-i))/t)^.69)/(((((t-c) - (t-c+1-i))/t)^.69+(((1 - ((t-c)-(t-c+1-i))/t))^.69))^(1/.69))))}}
The formula is giving out probability weights according to Cummulative Prospect Theory, if anyone is interested.
Do you guys have an idea how I can make this more elegant? Should I better write a user-defined function?
If you are happy with your resultant matrices being in a list with the same names you were assigning to you could do something like:
l = lapply(15:30, function(q){
t = q
matrix(apply(expand.grid(1:q,1:(q+1)),1,
function(x){
i = x[1]
c = x[2]
( (((((t-c) + 1 -(t-c+1-i))/t)^.69)/
(((((t-c) + 1 - (t-c+1-i))/t)^.69+(((1 - ((t-c) + 1 -(t-c+1-i))/t))^.69))^(1/.69))) -
(((((t-c)-(t-c+1-i))/t)^.69)/(((((t-c) - (t-c+1-i))/t)^.69+(((1 - ((t-c)-(t-c+1-i))/t))^.69))^(1/.69))))
}),nrow = q, ncol = q+1, byrow = TRUE)
})
names(l) = paste0("P",15:30)
I have used bits like t=q and i=x[1]; c=x[2] such that I could just copy paste your formula for probability.
What we are doing here is using lapply to loop over the given row numbers in your question, we then use expand.grid to give the pairs of indicies for all cells in the resultant vector. To the indicies we apply a function which given row i, column c calculates the probability according to your formula. The values are then cast as a matrix such that the result has the appropriate structure.
You end up with a list l of matrices with components called "P15", "P16", ...

R - how to evaluate a text string

I'm quite new to R and failed to google the answer. The question is, how can I tell R to treat a character string value as a part of code, in a manner SAS resolve() function does?
Say, I have a data frame containing numeric columns V1, ..., Vn and exactly n rows. I wish to sum up all the 'diagonal' elements V = V1[1] + V2[2]... + Vn[n] but n is large enough for manual summation (below, n=2 for simplicity).
I'm trying to put the strings "dat$V1[1]", "dat$V2[2]" in a character C and then extract the corresponding numerical value (all in a loop step):
> dat <- data.frame(V1 = c(2,3), V2 = c(7,11))
> dat
V1 V2
1 2 7
2 3 11
V = 0
for(i in 1:nrow(dat))
{
C = paste('dat$V',format(i,trim=TRUE),'[',format(i,trim=TRUE),']',
sep="" )
f = Xfun(C)
V = V + f
}
What should be used instead of Xfun? I've tried as.formula(), asOneSidedFormula(), get("...") and some other, but it's essential that dat$V1 is not an object:
> exists("dat")
[1] TRUE
> exists("dat$V1")
[1] FALSE
Your help is much appreciated.
If you just want to sum the diagonal elements of a square matrix, just do
dat <- data.frame(V1 = c(2,3), V2 = c(7,11))
sum(diag(as.matrix(dat)))
If you want to evaluate a text string in R, read up a bit on eval or do ? eavl in R.
For your problem, you can do this:
dat <- data.frame(V1 = c(2,3), V2 = c(7,11))
dat
V = 0
for(i in 1:nrow(dat))
{
C = paste('dat$V',format(i,trim=TRUE),'[',format(i,trim=TRUE),']',
sep="" )
f = eval(parse(text=C))
V = V + f
}
To finalize:
a) correct answer using text parsing and evaluation
V = 0
for(i in 1:nrow(dat))
{ C = paste('dat$V',as.character(i),'[',as.character(i),']',
sep='' )
V = V + eval(parse(text=C))
}
b) correct action ESPECIALLY for a data frame - without requiring text evaluation but addressing data frame columns directly by name
V = 0
for(i in 1:nrow(dat))
{ col = paste('V',as.character(i),
sep='')
V = V + dat[i,col]
}

Resources