I need to assign variables some values in a loop
Eg:
abc_1<-
abc_2<-
abc_3<-
.....
something like:
for(i in 1:20)
{
paste("abc",i,sep="_")<-some calculated value
}
I have tried to use paste as above but it doesn't work.
How could this be done.Thanks
assign() and paste0() should help you.
for example:
object_names <- paste0("abc",1:20)
for (i in 1:20){
assign(object_names[i],runif(40))
}
assign() takes the string in object_names and assigns the function in the second argument to each name. When you place a numeric vector inside of paste0() it gives back a character vector of concatenated values for each value in the numeric vector.
edit:
As Gregor says below, this is much better to do in a list because:
It will be faster.
When making a large number of things you probably want to do the same thing to each of them. lapply() is very good at this.
For example:
N <- 20
# create random numbers in list
abcs <- lapply(1:N,function(i) runif(40))
# multiply each vector in list by 10
abc.mult <- lapply(1:length(abcs), function(i) abcs[[i]] * 10)
Related
df is a frequency table, where the values in a were reported as many times as recorded in column x,y,z. I'm trying to convert the frequency table to the original data, so I use the rep() function.
How do I loop the rep() function to give me the original data for x, y, z without having to repeat the function several times like I did below?
Also, can I input the result into a data frame, bearing in mind that the output will have different column lengths:
a <- (1:10)
x <- (6:15)
y <- (11:20)
z <- (16:25)
df <- data.frame(a,x,y,z)
df
rep(df[,1], df[,2])
rep(df[,1], df[,3])
rep(df[,1], df[,4])
If you don't want to repeat the for loop, you can always try using an apply function. Note that you cannot store it in a data.frame because the objects are of different lengths, but you could store it in a list and access the elements in a similar way to a data.frame. Something like this works:
df2<-sapply(df[,2:4],function(x) rep(df[,1],x))
What this sapply function is saying is for each column in df[,2:4], apply the rep(df[,1],x) function to it where x is one of your columns ( df[,2], df[,3], or df[,4]).
The below code just makes sure the apply function is giving the same result as your original way.
identical(df2$x,rep(df[,1], df[,2]))
[1] TRUE
identical(df2$y,rep(df[,1], df[,3]))
[1] TRUE
identical(df2$z,rep(df[,1], df[,4]))
[1] TRUE
EDIT:
If you want it as a data.frame object you can do this:
res<-as.data.frame(sapply(df2, '[', seq(max(sapply(df2, length)))))
Note this introduces NAs into your data.frame so be careful!
I want to apply some operations to the values in a number of columns, and then sum the results of each row across columns. I can do this using:
x <- data.frame(sample=1:3, a=4:6, b=7:9)
x$a2 <- x$a^2
x$b2 <- x$b^2
x$result <- x$a2 + x$b2
but this will become arduous with many columns, and I'm wondering if anyone can suggest a simpler way. Note that the dataframe contains other columns that I do not want to include in the calculation (in this example, column sample is not to be included).
Many thanks!
I would simply subset the columns of interest and apply everything directly on the matrix using the rowSums function.
x <- data.frame(sample=1:3, a=4:6, b=7:9)
# put column indices and apply your function
x$result <- rowSums(x[,c(2,3)]^2)
This of course assumes your function is vectorized. If not, you would need to use some apply variation (which you are seeing many of). That said, you can still use rowSums if you find it useful like so. Note, I use sapply which also returns a matrix.
# random custom function
myfun <- function(x){
return(x^2 + 3)
}
rowSums(sapply(x[,c(2,3)], myfun))
I would suggest to convert the data set into the 'long' format, group it by sample, and then calculate the result. Here is the solution using data.table:
library(data.table)
melt(setDT(x),id.vars = 'sample')[,sum(value^2),by=sample]
# sample V1
#1: 1 65
#2: 2 89
#3: 3 117
You can easily replace value^2 by any function you want.
You can use apply function. And get those columns that you need with c(i1,i2,..,etc).
apply(( x[ , c(2, 3) ])^2, 1 ,sum )
If you want to apply a function named somefunction to some of the columns, whose indices or colnames are in the vector col_indices, and then sum the results, you can do :
# if somefunction can be vectorized :
x$results<-apply(x[,col_indices],1,function(x) sum(somefunction(x)))
# if not :
x$results<-apply(x[,col_indices],1,function(x) sum(sapply(x,somefunction)))
I want to come at this one from a "no extensions" R POV.
It's important to remember what kind of data structure you are working with. Data frames are actually lists of vectors--each column is itself a vector. So you can you the handy-dandy lapply function to apply a function to the desired column in the list/data frame.
I'm going to define a function as the square as you have above, but of course this can be any function of any complexity (so long as it takes a vector as an input and returns a vector of the same length. If it doesn't, it won't fit into the original data.frame!
The steps below are extra pedantic to show each little bit, but obviously it can be compressed into one or two steps. Note that I only retain the sum of the squares of each column, given that you might want to save space in memory if you are working with lots and lots of data.
create data; define the function
grab the columns you want as a separate (temporary) data.frame
apply the function to the data.frame/list you just created.
lapply returns a list, so if you intend to retain it seperately make it a temporary data.frame. This is not necessary.
calculate the sums of the rows of the temporary data.frame and append it as a new column in x.
remove the temp data.table.
Code:
x <- data.frame(sample=1:3, a=4:6, b=7:9); square <- function(x) x^2 #step 1
x[2:3] #Step 2
temp <- data.frame(lapply(x[2:3], square)) #step 3 and step 4
x$squareRowSums <- rowSums(temp) #step 5
rm(temp) #step 6
Here is an other apply solution
cols <- c("a", "b")
x <- data.frame(sample=1:3, a=4:6, b=7:9)
x$result <- apply(x[, cols], 1, function(x) sum(x^2))
This is an edited version of
my initial question, which i obviously explained poorly, so ill try again.
I want to perform a function with every column of the dataframe, and name the resulting objects (here values of the class dist) according to the original dataframe and the colname:
library(vegan)
d1 <- as.data.frame(matrix(rnorm(12),4,3), ncol=3, dimnames=list(NULL, LETTERS[1:3])))
Fun <-function(x){
vegdist(decostand(x,"standardize",MARGIN=2), method="euclidean")
}
d1.A <- Fun(d1$A) # A being the colname of the first column of d1
d1.B <- Fun(d1$B)
d1.C <- Fun(d1$C)
This i want to do for more than 100 columns in my dataframe.
So, in short i want to apply my function to all columns of my dataframe and create result values with names that are made from the name of the original dataframe and a paste of the column name the function was working on.
Thank you very much!
If you want to clutter your global environment with lots of objects, one option is list2env or you can use assign (Though, I would not recommend it). Instead you can do all the operations/analysis by storing it in a list and later save/write to different files using write.table and lapply
lst <- setNames(lapply(d1, Fun),
paste("d1", colnames(d1), sep="."))
The above list could be used for most of the analysis. If you need as individual objects.
list2env(lst, envir=.GlobalEnv)
#<environment: R_GlobalEnv>
Now, you can get the individual objects by calling d1.A, d1.B etc.
d1.A
# 1 2 3
#2 1.9838499
#3 1.2754209 0.7084290
#4 2.2286961 0.2448462 0.9532752
I am assuming you need to create a number (equal to the number of columns of d1) of objects of class "dist".
If that is the case, you can do this:
for (i in 1:ncol(d1))
{
eval(parse(text=paste('d1.',colnames(d1)[i], "<-" ,"Fun(d1[,",i,"])", sep="")))
}
This evaluates in each iteration to:
d1.V1 <- Fun(d1$V1)
d1.V2 <- Fun(d1$V2)
d1.V3 <- Fun(d1$V3)
I am trying to write a loop using "for" where my index,i, should have values from a set of values c(2,4,6,8,10,12) . I am further using i for subsetting values from another vector.
I defined a vector X , where X <- c(2,4,,6,8,10,12) ,
and then using for(i in X[1]:tail(X,n=1)).
This results in i taking all values from 2 to 12!
Whereas I want it to take the values mentioned in X only, i.e 2,4,6,8,10,12.
I hope someone can give me a hint how to do this
Thank you in advanced
You are looping through a sequence. If you want to loop only through the values of a vector, use this:
X <- c(2,4,6,8,10,12)
for(i in X) {
# Your code
}
I have a list, listDFs, where each element is a data frame. Each data frame has a different number of rows and the same number of columns.
I should create a vector beginning from listDFs[[i]]$Name extracting all the i element from the list.
I thought to use a loop such:
vComposti <- c()
for(j in 1:10){vComposti <- c(listDFs[[j]]$Name)}
But the result is a vector containing only the first level (listDFs[[1]]$Name) of the list.
Where I wrong?? Do you have any suggestion??
The problem you have is in this line:
vComposti <- c(listDFs[[j]]$Name)
Each time through your loop, you are re-assigning a new value to vComposti and overwriting the previous value.
In general it is preferable to pre-allocate the vector and fill it element by element:
vComposti <- rep(NA, 10)
for(j in 1:10){
vComposti[j] <- c(listDFs[[j]]$Name)
}
But it's also not clear to me exactly what you're expecting the result to be. You create a vector, but it looks like you are trying to store an entire data frame column in each element of the vector. If that's the case you may actually be looking for a result that's a list:
vComposti <- vector("list",10)
for(j in 1:10){
vComposti[[j]] <- c(listDFs[[j]]$Name)
}
Another, somewhat more sophisticated, option may be to use lapply:
lapply(listDFs,FUN = "[","Name")