User defined function within for-loops - r

I am working on a project in which I am simulating 8 classroom social networks over 6 weeks, so 30 iterations. Students will nominate each other based on a number of factors, and I plan to simulate a number of conditions in which I remove or add some of these factors to the simulation. In other words, I'm going to be repeating a lot of code, so I'd rather use functions rather than cutting and pasting where ever possible.
Right now, I'm trying to create a function that adjusts the probability of one student selecting another based on the similarity of their emotions. When I include it in a set of nested for for loops, this works just fine:
num_students <- 5
names_students <- letters[1:num_students]
student_emotion <- sample(round(runif(5, min = -5, max = 5), digits = 1))
student_emotion_df <- cbind.data.frame(names_students, student_emotion)
probs <- rep(1/num_students, 5)
row_prob <- vector(length = 5)
for(i in 1:num_students){
for(q in 1:num_students){
if(abs(student_emotion[i]-student_emotion[q]) >= 0 &
abs(student_emotion[i]-student_emotion[q]) <= .5){
row_prob[q] <- 1*probs[q]
} else if(abs(student_emotion[i]-student_emotion[q]) > .5 &
abs(student_emotion[i]-student_emotion[q]) <= 1) {
row_prob[q] <- .75 * probs[q]
}
else {
row_prob[q] <- .5 * probs[q]
}
}
}
The row_prob object is a vector of probabilities a student i, in the column, will select student q, in the rows.
I've created a user-defined function based on the same code, and that works:
emotion_difference_fun <- function(probs){
for(q in 1:num_students){
if(abs(student_emotion[i]-student_emotion[q]) >= 0 &
abs(student_emotion[i]-student_emotion[q]) <= .5){
row_prob[q] <- 1*probs[q]
} else if(abs(student_emotion[i]-student_emotion[q]) > .5 &
abs(student_emotion[i]-student_emotion[q]) <= 1) {
row_prob[q] <- .75 * probs[q]
}
else {
row_prob[q] <- .5 * probs[q]
}
}
return(row_prob)
}
emotion_difference_fun(probs)
But when I try to embed that function within the for loop iterating through the columns, row_prob returns as an empty vector:
for(i in 1:num_students){
emotion_difference_fun(probs)
}
Any thoughts on how I can get this to work?
Thanks for any help you're able to offer.

If I understood your question properly, then you need to assign the results in your last 'for' loop:
for(i in 1:num_students){
if(i == 1) out <- NULL
out <- c(out, emotion_difference_fun(probs))
}
out
Is that what you are looking for?
What I am unclear about though, is why in your second code section you are not looking for a 5*5 matrix. Eventually, when running that code, it doesn't matter that you did it for i = 5 students, because it will only save in row_prob your last iteration (student = 5).

You can use replicate to repeat the function emotion_difference_fun for num_students.
result <- replicate(num_students, emotion_difference_fun(probs))
You can also set simplify = FALSE to get output as list.
result <- replicate(num_students, emotion_difference_fun(probs),simplify = FALSE)

Related

how to calculate h-point

I am trying to write a function to calculate h-point. the function is defined over a rank frequency data frame.
consider the following data.frame :
DATA <-data.frame(frequency=c(49,48,46,38,29,24,23,22,15,12,12,10,10,9,9), rank=c(seq(1, 15)))
and the formula for h-point is :
if {there is an r = f(r), h-point = r }
else { h-point = f(i)j-f(j)i / j-i+f(i)-f(j) }
where f(i) and f(j) are corresponding frequencies for ith and jth ranks and i and j are adjacent ranks that i<f(i) and j>f(j).
NOW, i have tried the following codes :
fr <-function(x){d <-DATA$frequency[x]
return(d)}
for (i in 1:length(DATA$rank)) {
j <- i+1
if (i==fr(i))
return(i)
else(i<fr(i) && j>fr(j)) {
s <-fr(i)*j-fr(j)*i/j-i+fr(i)-fr(j)
return(s)
}}
I also tried:
for (i in 1:length(DATA$rank)) {
j <- i+1
if (i==fr(i))
return(i)
if (i<fr(i) while(j>fr(j))) {
s <-fr(i)*j-fr(j)*i/j-i+fr(i)-fr(j)
return(s)
}}
and neither of them works. for the DATA ,the desired result would be i=11 and j=12, so:
h-point=12×12 - 10×11 / 12 - 11 + 12 - 10
can you please tell me what I`m doing wrong here?
You could do:
h_point <- function(data){
x <- seq(nrow(data))
f_x <- data[["frequency"]][x]
h <- which(x == f_x)
if(length(h)>1) h
else{
i <- which(x<f_x)
j <- which(x>f_x)
s <- which(outer(i,j,"-") == -1, TRUE)
i <- i[s[,1]]
j <- j[s[,2]]
cat("i: ",i, "j: ", j,"\n")
f_x[i]*j - f_x[j]*i / (i-j + f_x[i]-f_x[j])
}
}
h_point(DATA)
i: 11 j: 12
[1] 34
I think I have figured out what you are trying to achieve. My loop will go through DATA and break at any point if rank == frequency for a given row. If might be more prudent to explicitly test this with DATA$rank[i] == fr(i) rather than relying on i, in case tied ranks etc.
The second if statement calculates h-point (s) for rows i and j if row i has rank that is lower than freq and row j has a rank that is higher.
Is this what you wanted?
DATA <-data.frame(frequency=c(49,48,46,38,29,24,23,22,15,12,12,10,10,9,9), rank=c(seq(1, 15)))
fr <-function(x){d <-DATA$frequency[x]
return(d)}
for(i in 1:nrow(DATA)){
j <- i+1
if (i==fr(i)){
s <- list(ij=c(i=i,j=j), h=i)
break
}else if(i <fr(i) && j>fr(j)){
s <-list(ij=c(i=i,j=j),h=fr(i)*j-fr(j)*i/j-i+fr(i)-fr(j))
}}
I am not sure the formula is correct, in your loop you had j-i but in explanation it was i-j. Not sure if the entire i-j+fr(i)-fr(j) is the denominator and similarly for the numerator. Simple fixes.

How to break a repeat loop when its output falls within the 95% confidence interval of the previous 3 outputs?

I have been trying to write a repeat function that breaks whenever its output equilibrates, meaning that it stops after a specific number of iterations, after which the function returns values that fall within the 95% confidence interval of the last 3 values returned by that function. This is example data:
a <- c(1, 5)
a.2 <- c(9, 18)
rbind(a, a.2)
b <- c(1, 0.5)
c <- c(1, 0)
This is the function I am trying out. Every computation of the values is addded to a matrix with two columns. I am using the last three rows to work out a 95% confidence intrval for the two different values. If the values fall within this interval, the function is supposed to break.
repeat {
abc <- sum(a * b) + c
for(alpha in abc[alpha]) {
if (abc[alpha] > 0) {
new.abc[alpha] <- (1-b)a - 0.2(b)
} else {
new.abc[alpha] <- (b-1)a - 0.2(b)
}
}
all.abc <<- matrix(ncol = 2, dimnames = list(c(),c("abc.1", "abc.2")
all.abc <<- rbind(all.abc, new.abc)
s <- apply(all.abc[(length(abc[,1]) - 2):length(abc[,3]),], 2, sd)
n <- apply(all.abc[(length(abc[,1]) - 2):length(abc[,3]),], 2, length)
error <- qnorm(0.975)*s/sqrt(n)
for(j in length(all.abc[j,])) {
for(i in length(all.abc[,i])) {
if((all.abc[j,i] < all.abc[j,i] + error * all.abc[j,i]) &
(all.abc[j,i] > all.abc[j,i] - error * all.abc[j,i])) {
break
}
}
}
}
However, this does not seem to work. I suppose the values of the last rows are not readily available during the execution of the function. I hope I have been clear. Tell me if I need to clarify anything. Thanks!

How to implement mutation function of genetic algorithm in R?

I'm implementing GA algorithm. The chromosomes have a combination of -1,0,1 values. In the mutation part, I want to change -1 to 1 with prob(-1 to 1) and change 1 to -1 with prob(1 to -1).
I don't know if there is any function in R which would make it easy for me. Would any one tell me if there is a function which helps me replace the values according to their probability?
You could throw a dice and if 1 comes up, you change the original value to another value. You could add if statements for all of your transitions. If you mean to mutate the whole string in one step, this can be better optimized.
from <- c(1,-1,1,0,-1)
probToMutate <- function(x) {
if (x == 1) {
dice <- rbinom(1, size = 1, prob = 0.1)
if (dice == 1) {
x <- -1
} else {
x <- 1
}
} else {
x
}
}
sapply(from, FUN = probToMutate)

Perceptron (single layer 2D) - Result with samples on straight line

I tried to implement a simple 2D single layer perceptron and ended up with this solution:
perceptron <- function(featureVec, classVec, wStart=matrix(c(0,0,0)), eta=1, limit = 50) {
plot(x=featureVec[,1],y=featureVec[,2])
# Extending dimensions
dimension <- dim(featureVec)[1]
featureVec <- cbind(featureVec,rep(1,dimension))
# Inverting 2. class
index <- classVec == -1
featureVec[index,] <- apply(matrix(featureVec[index]),1,prod,-1)
wTemp <- wStart
y <- featureVec %*% wTemp
iteration = 0
while (T) {
y <- featureVec %*% wTemp
delta <- as.matrix(featureVec[y <= 0,])
for(i in 1:nrow(delta)) {
wTemp <- wTemp + eta*delta[i,]
}
result <- featureVec %*% wTemp
if (sum(result <= 0) == 0) {
break
}
if (iteration >= limit) {
stop("Maximum count of interations reached!")
}
iteration = iteration + 1
}
if(wTemp[2] != 0) {
abline(-wTemp[3]/wTemp[2],-wTemp[1]/wTemp[2])
} else if(wTemp[2] == 0) {
abline(v=wTemp[1])
} else if(wTemp[1] == 0) {
abline(h=wTemp[2])
}
return(wTemp)
}
The feature vector works row-wise, the class vector needs values of 1 and -1 col-wise.
For most of my tests it works correct, but when I have samples like (0,0) (0,1) with classes (1,-1) I get no result. That happens with some of my examples with two points lying on a straight line (horizontal to a coordinate axis). When I try to choose different start vectors it sometimes works correctly (I have no deterministic behaviour here right now I guess). Is that a correct behaviour or is my implementation wrong?
Thanks for your help, Meiner.
EDIT: Some changes of the inital post.
Bad Dataset:
featureTest <- matrix(c(0,0,0,1),byrow=T,nrow=2)
classTest <- matrix(c(1,-1),nrow=2)
perceptron(featureTest,classTest)
featureTest <- matrix(c(0,1,0,2),byrow=T,nrow=2)
classTest <- matrix(c(1,-1),nrow=2)
perceptron(featureTest,classTest)
Good Dataset:
featureTest <- matrix(c(0,0,0,2),byrow=T,nrow=2)
classTest <- matrix(c(1,-1),nrow=2)
perceptron(featureTest,classTest)

How to repeat a loop?

this is my first loop:
e13 = rnorm(122)
y = 0*e13
y[1]=2
y[2]=5
for(k in 3:length(e13)) {
y[k]= 0.6 * y[k-1] + e13[k]
}
Now I want to repeat it 10 times to find another 10 values for the same y[k], like, 10 different y[1], 10 different y[2] and so on.
And then I need ot use these numbers for another functions.
I tried it but didn't work
for (i in 1:20) {
for(k in 3:length(e13)) {
y[k,i] = 0.6 * y[k-1,i] + e13[k,i]
}
}
it says "wrong number of dimensions"
Now my code is like that:
e13 = rnorm(122)
y <- array(0, c(length(e13), 20))
y[1, ] <- 2
y[2, ] <- 5
i<-c(1:20)
y[1]=2
y[2]=5
for (i in 1:20) {
for(k in 3:length(e13)) {
y[k,i] = 0.6 * y[k-1,i] + e13[k,i]
}
}
but the problem now is the dimension of e13 (a normal distribution), im going to try to set the correct dimension
You should take a good look at some introductory R texts (e.g., this, this, this, and others). The comments on your question were guiding you to solve this yourself. You're almost there, but here is how I would do what you're attempting.
e13 <- matrix(rnorm(122*20), ncol=20)
y <- array(0, dim(e13))
y[1, ] <- 2
y[2, ] <- 5
for (i in 1:ncol(y)) {
for(k in 3:nrow(y)) {
y[k, i] <- 0.6 * y[k-1, i] + e13[k, i]
}
}
Here is a simple solution although cbind will slow you down with larger datasets. If need more speed you don't need to specify 2 dimensions you can specify datamatrix as a vector of length length(e13)*(how many times you want to repeat) In this case length(e13)*20. Then in your second loop you would have y placed further along the length of datamatrix each repetition of the loop. Its sometimes simpler to do this and you turn it into a matrix at the end if you want using matrix.
datamatrix=NULL
for(n in 1:20) {
e13 = rnorm(122)
y = 0*e13
y[1]=2
y[2]=5
for(k in 3:length(e13)) {
y[k]= 0.6 * y[k-1] + e13[k]
}
datamatrix=cbind(datamatrix,y)}

Resources