Having trouble with nested loops (R) - r

I've wrote this nested loop so that, in the inner loop, the code runs through the first row; then, the outer one updates the loop so as to allow the inner one to run though the second row (and so on). The data comes from 'supergerador', a matrix. "rodadas" is the row size and "n" is the column size. "vec" is the vector of interest. Thank you in advance!
Edit: i, j were initially assigned i = 1, j = 2
for(e in 1:rodadas) {
for(f in 1:(n-1)) {
if(j >= 10) {
vec[f] = min(supergerador[i, j] - supergerador[i, j - 1], 1 - supergerador[i, j])
}
else {
vec[f] = func(i, j)
}
j = j + 1
}
i = i + 1
}
func is defined as
func = function(i, j) {
minf = min(supergerador[i, j] - supergerador[i, j - 1], supergerador[i, j + 1] - supergerador[i, j])
return(minf)
}
For reference, this is what the nested loop returns. You can tell that it only went through a single row.
> vec
[1] 0.127387378 0.068119707 0.043472981 0.043472981 0.027431603 0.027431603
[7] 0.015739046 0.008010766 0.008010766

I'm not quite sure what you are intending to do here, but here is a few suggestions and code edits:
Suggestions:
If you have a for loop, use the loop-index for your subsetting (as much as plausible) and avoid additional indexes where plausible.
This avoids code clutter and unforseen errors when indices should be reset but aren't.
Avoid double subsetting variables whenever possible. Eg if you have multiple calls to x[i, j], store this in a variable and then use this variable in your result.
Single line functions are fine, but should add readability to your code. Otherwise inlining your code is optimal from an efficiency perspective.
Incorporating these into your code I beliieve you are looking for
for(i in 1:rodadas) {
for(j in 2:n) {
x1 = supergerador[i, j]
x2 = supergerador[i, j - 1]
if(j >= 10) {
vec[f] = min(x1 - x2, 1 - x1)
}
else {
vec[f] = min(x1 - x2, supergerador[i, j + 1] - x1)
}
}
}
Here i am making the assumption that you wish to loop over columns for every row up to rodadas.
Once you get a bit more familiarized with R you should look into vectorization. With a bit more knowledge of your problem, we should be very easily able to vectorize your second for loop, removing your if statement and performing the calculation in 1 fast sweep. But until then this is a good place to start your programming experience and having a strong understanding of for-loops is vital in any language.

Related

R dataframe uses values in current row from previous row

I have a data frame in R as defined below:
df <- data.frame('ID'=c(1,1,1,1),
'Month' =c('M1','M2','M3','M4'),
"Initial.Balance" =c(100,100,100,0),
"Value" = c(0.1,0.2,0.2,0.2),
"Threshold"=c(0.05,0.18,0.25,0.25),
"Intermediate.Balance"=c(0,0,100,0),
"Final.Balance"=c(100,100,0,0))
This task uses Initial.Balance (in current row) from the Final.Balance of the previous row.
When Value >= Threshold, Intermediate.Balance=0 and Final.Balance = Initial.Balance-Intermediate.Balance
When Value < Threshold, Intermediate.Balance = Initial.Balance and Final.Balance = Initial.Balance-Intermediate.Balance
I have tried to accomplish this task using for loop but it takes lot of time on large dataset (for many IDs)
Here is my solution:
for (i in 1:nrow(df)){
df$Intermediate.Balance[i] <- ifelse(df$Value[i]>df$Threshold[i],0,df$Initial.balance[i])
df$Final.Balance[i] <- df$Initial.balance[i]-df$Intermediate.Balance[i]
if(i+1<=nrow(df)){
df$Initial.balance[i+1] <- df$Final.Balance[i] }
}
Can we look for similar solution using Data Table? As data table operations are quicker than for loop on dataframe, I believe this will help me save computation time.
Thanks,
I think in this particular case, final balance goes to 0 once there is a row with Value less than Threshold and subsequent balances all go to 0. So you can use this:
ib <- 100
df[, InitBal := ib * 0^shift(cumsum(Value<=Threshold), fill=0L)]
df[, ItmdBal := replace(rep(0, .N), which(Value<=Threshold)[1L], ib)]
df[, FinlBal := InitBal - ItmdBal]
or in one []:
df[, c("InitBal", "ItmdBal", "FinlBal") := {
v <- Value<=Threshold
InitBal <- ib * 0^shift(cumsum(v), fill=0L)
ItmdBal <- replace(rep(0, .N), which(v)[1L], ib)
.(InitBal, ItmdBal, InitBal - ItmdBal)
}]
Or a more general approach using Rcpp when the intermediate balance is not simply equal to the initial balance:
library(Rcpp)
cppFunction('List calc(NumericVector Value, NumericVector Threshold, double init) {
int n = Value.size();
NumericVector InitialBalance(n), IntermediateBalance(n), FinalBalance(n);
InitialBalance[0] = init;
for (int i=0; i<n; i++) {
if (Value[i] <= Threshold[i]) {
IntermediateBalance[i] = InitialBalance[i];
}
FinalBalance[i] = InitialBalance[i] - IntermediateBalance[i];
if (i < n-1) {
InitialBalance[i+1] = FinalBalance[i];
}
}
return List::create(Named("InitialBalance") = InitialBalance,
Named("IntermediateBalance") = IntermediateBalance,
Named("FinalBalance") = FinalBalance);
}')
setDT(df)[, calc(Value, Threshold, Initial.Balance[1L])]
I can't see an obvious way of getting rid of the loop since each row is deterministic into the next. That being said, data.frames copy the whole frame or at least whole columns whenever you set some portion of them. As such you can do this:
dt<-as.data.table(df)
for(i in 1:nrow(dt)) {
dt[i,Intermediate.Balance:=ifelse(Value>Threshold,0,Initial.Balance)]
dt[i,Final.Balance:=Initial.Balance-Intermediate.Balance]
if(i+1<=nrow(dt)) dt[i+1,Initial.Balance:=dt[i,Final.Balance]]
}
You could also try the set function but I'm not sure if it'll be faster, or by how much, given that the data comes from the data.table anyway.
dt<-as.data.table(df)
for(i in 1:nrow(dt)) {
i<-as.integer(i)
set(dt,i,"Intermediate.Balance", ifelse(dt[i,Value]>dt[i,Threshold],0,dt[i,Initial.Balance]))
set(dt,i,"Final.Balance", dt[i,Initial.Balance-Intermediate.Balance])
if(i+1<=nrow(dt)) set(dt,i+1L,"Initial.Balance", dt[i,Final.Balance])
}

How to implement a function with a sum inside in R?

I am trying to define a function with a for loop and inside a conditional in R studio. Yesterday I was able with the help of another thread to devise this piece of code. The problem is that I want to sum the vector elements ma for any possible x, so that is inside the function l. This is a simpler case which I am trying to solve to adapt the original model. However, I do not know how to proceed.
ma<-rep(0,20)
l <- function(x, ma) {
for(i in seq_along(ma)) {
if(i %% 2 == 1) {
ma[i] <- i + x
} else {
ma[i] <- 0
}
}
return(ma)
}
My problem is that I would like to have the sum of i+x+0+i+x... for any possible x. I mean a function of the kind for any possible x.
Question:
Can someone explain to me how to implement such a function in R?
Thanks in advance!
I am going to update the original function:
Theta_alpha_s<-function(s,alpha,t,Basis){
for (i in seq_along(Basis)){
if(i%% 2==1) {Basis[i]=s*i^{-alpha-0.5}*sqrt(2)*cos(2*pi*i*t)}
else{Basis[i]=s*i^{-alpha-0.5}*sqrt(2)*sin(2*pi*i*t)}
}
return(Basis)
}
If you don't want to change the values in Basis, you can create a new vector in the function (here result) that you will return:
l = function(s,alpha,t,Basis){
is.odd = which(Basis %% 2 == 1)
not.odd = which(Basis %% 2 == 0)
result = rep(NA, length(Basis))
result[is.odd] = s*is.odd^{-alpha-0.5}*sqrt(2)*cos(2*pi*is.odd*t)
result[not.odd] = s*not.odd^{-alpha-0.5}*sqrt(2)*sin(2*pi*not.odd*t)
#return(result)
return(c(sum(result[is.odd]), sum(result[not.odd])))
}

confunsion in create if in R

I have a question how to make a IF
for (i in 1:12){
for (j in 1:12) {
if (i != j) {
var = x + b
}
else{ }
}}
"else" I need that when they are equal to continue with j + 1 example: if i = 4 and j = 4 then continue with j = 5 and continue counting until the end of j and continue the process of when i! = j
I think you don't understand what is going on in your code or you don't understand what for loops do. One "trick" you can do is to actually print what happens in your for loops so that you will have one idea of what is going on. You could also do this with a piece of paper.
As they already pointed you out, you don't need the else because the for already takes care of this.
for (i in 1:12){
print("-------------------------------")
valueI <- paste0("my i value is ",i)
print(valueI)
for (j in 1:12) {
valueJ <- paste0("my j value is ",j)
print(valueJ)
if (i != j) {
#var = x + b
diff <- paste0(i, " is different than ", j)
print(diff)
}
else{
}
}
}
This code is the same as yours and will generate a log that explains you what happens step from step, you could also use a debugger but seeing your struggles, better use this for now. What are you trying to calculate? I feel like you want to calculate the power of something...

Error message in Bubble sort code in R language

I did some programming work on R language to do the bubble sort. Sometimes it works perfectly without any error message, but sometimes, it shows "Error in if (x[i] > x[i + 1]) { : argument is of length zero". Can any one help me check whats wrong with it? I have attached my code below
example <- function(x) {
n <- length(x)
repeat {
hasChanged <- FALSE
n <- n - 1
for(i in 1:n) {
if ( x[i] > x[i+1] ) {
temp <- x[i]
x[i] <- x[i+1]
x[i+1] <- temp
hasChanged <- TRUE
cat("The current Vector is", x ,"\n")
}
}
if ( !hasChanged ) break;
}
}
x <-sample(1:10,5)
cat("The original Vector is", x ,"\n")
example(x)
The error occurs because you are iteratively decreasing n. Depending on the original vector's order (or lack thereof), n can reach the value of 1 after the last change. In that case, a further reduction of n in the next iteration step addresses the value x[0], which is undefined.
With a minimal correction your code will work properly, without giving error messages. Try to replace the line
if ( !hasChanged ) break;
with
if ( !hasChanged | n==1 ) break
Basically you have two termination criteria: Either nothing has been changed in the previous iteration or n is equal to one. In both cases, a further iteration won't change the vector since it is already ordered.
By the way, in R programming you don't need a semicolon at the end of a command. It is tolerated/ignored by the interpreter, but it clutters the code and is not considered good programming style.
Hope this helps.

How to get equivalent to R ifelse functionality, using logical operators

Please can anyone advise how I can turn the following statement into one that will do the same thing but NOT using ifelse please?
<-ifelse(y>=50, 0.2*x+0.8*y, ifelse(y<50 & x>70, y+10, ifelse(y<50 & x<70, y)))
x=80
y=60
So I the final code should give an answer of 64 - selecting the first condition. I will then test it to ensure the other 3 conditions give the correct result for varying values of x and y
Thanks a lot.
This should work:
finalmark <- (x * 0.2 + y * 0.8) * (y >= 50) + (y + 10 * (x > 70)) * (y < 50)
Something like this?
if(y>=50){
0.2*x+0.8*y
}else{
if(y<50 & x>70){
y+10
}else{
if(y<50 & x<70){
y
}else{
"OMG I did not expect this scenario"
}
}
}
try: y=45; x=70 to see why I have the last condition.
If y is a number then, once you've tested for y > = 50 then y must be less than 50 so don't keep testing for that. Similarly, once you've found x > 70 then you don't need the last ifelse. You don't have a return for x = 70. My guess is that you want to test for a <= or >= situation there.
ifelse(y>=50, 0.2*x+0.8*y, ifelse(x>70, y+10, y))
in scalar that's
if(y >= 50){
0.2*x+0.8*y
}else if(x > 70){
y+10
}else y
Given you seem to be having a hard time in general writing the logic I suggest you post a more complete question. It's possible (probable) that you're doing something here that you really don't want to do.
There are several approaches you can take. Below are a few examples of building a function 'f', so that 'f(x,y)' meets your criteria listed in the question using logic other than 'ifelse' statements.
Note: I'm also adding in one amendment to the original post, since 'x=70' would break the logic. I'm adding 'x>=70' to the second criterion.
Option 1: Use a standard 'if / else if / else' logic block. Personally, I like this option, because it's easily readable.
f <- function(x, y){
if (y>= 50){
return(0.2*x+0.8*y)
} else if (y < 50 & x >= 70){
return(y+10)
} else {
return(y)
}
}
Option 2: Combine your two logical tests (there are really only two) into a string, and use a switch. Note that the final and unnamed option is treated as an 'else'.
f <- function(x, y){
return(
switch(paste(x >= 70, y >= 50, sep=""),
TRUEFALSE = y + 10,
FALSEFALSE = y,
0.2*x+0.8*y
)
)
}
Option 3: Order your 'if' statements to reduce logical comparisons. This is the sort of thing to do if you have a large data set or very limited memory. This is slightly harder to troubleshoot, since you have to read the whole block to fully understand it. Option 1 is better if you don't have memory or cycle limitations.
f <- function(x, y){
if (y >= 50){
return(0.2*x+0.8*y)
} else {
if (x >=70){
return(y+10)
} else {
return(y)
}
}
}
There are other options, but these are the simplest that come readily to mind.

Resources