If I want to have variables with numbers accessible for example in a for loop I can use get and assign:
for(i in 1:2){
assign(paste0('a',toString(i)),i*pi)
}
get('a2')
output
[1] 6.283185
But what if I want to do something similar for a dataframe?
I would like to do something like
df<-data.frame(matrix(ncol = 2,nrow = 3))
varnames <- c()
for(i in 1:2){
varnames <- c(varnames, paste0('a', toString(i)))
}
colnames(df) <- varnames
for(i in 1:2){
assign(paste0('df$a',toString(i)), rep(i*pi,3))
}
get(paste0('df$a',toString(2)))
But this actually just creates variables called df$a1
, df$a2
instead of assigning c(i*pi,i*pi,i*pi) to the columns of the dataframe df
And what I really want to do is to be able manipulate whole columns (individual entries) like this:
for(i in 1:2){
for(j in 1:3)
assign(paste0('df$a',toString(i),'[',toString(j),']'), i*pi)
}
get(paste0('df$a',toString(2),'[2]'))
where I would be able to get df$a2[2]
.
I think something like a python dictionary would work too.
CodePudding user response:
Instead of assign
, just directly do the [
for(i in 1:2) df[[paste0('a', i)]] <- rep(i * pi, 3)
and then can get the value with
df[[paste0('a', 2)]][2]
[1] 6.283185
assign
can be used, but it is not recommended when we have do this more directly
for(i in 1:2) assign("df",`[[<-`(df, paste0('a', i), value = i * pi))
df[[paste0('a', 2)]][1]
[1] 6.283185
The get
should be on the object i.e. 'df' instead of the columns i.e.
get('df')[[paste0('a', 2)]][1]
CodePudding user response:
First of all, it is not generally a great idea to use assign
to create objects in the global environment. In preference, you should be creating a named list instead for all sorts of good reasons, not least of which is the ability to iterate over the objects you create.
Secondly, note that the block of code:
varnames <- c()
for(i in 1:2){
varnames <- c(varnames, paste0('a', toString(i)))
}
colnames(df) <- varnames
Can be replaced with the one-liner:
colnames(df) <- paste0("a", 1:2)
Finally, you should take advantage of R's vectorization and the ability to subset with ["colname"]
notation. This removes the need for an explicit loop altogether here:
df[paste0("a", 1:2)] <- sapply(1:2, \(i) rep(i * pi, 3))
df
#> a1 a2
#> 1 3.141593 6.283185
#> 2 3.141593 6.283185
#> 3 3.141593 6.283185