0

I have multiple data.frames that all have different names but same column names, for example:

filenames <- c(1:10)
for (i in filenames){
  filenames[i] <- paste("df",filenames[i],sep="")  
  assign((filenames[i]), data.frame(matrix(rnorm(20), nrow=10)))
  }

How can one append the column names within each df with the name of that df?

The output would be:

> head(df1)
      df1_X1     df1_X2
1  0.2343486  0.2191546
2  0.5042413  2.0720167
3 -0.1082240  0.7376801
4  0.2346395  0.4677974
5  1.1559909 -1.1432890
6 -1.5554426 -0.2309197
> head(df2)
       df2_X1     df2_X2
1 -2.79824632 -0.1879618
2  1.93410571  0.3012066
3  0.72948663  0.2139871
4  0.59290004  1.1093813
5  0.04826737 -0.4062374
6 -0.78271090 -1.2870127

etc...

Here is my initial solution, which does not work:

for (i in length(filenames)){  
  colnames(filenames[i]) <- paste(filenames[i], colnames(filenames[i]), sep = "_") 
}

2 Answers 2

2

It is clearer and cleaner to do this with the data frames in a list. Then there's no need for awkward uses of assign, get, etc.

df1 <- data.frame(X1=1:5, X2=6:10)
df2 <- data.frame(X1=16:20, X2=21:25)

dfs <- list(df1 = df1,df2 = df2)

dfs_new <- lapply(names(dfs),
                  function(x) setNames(dfs[[x]],paste(x,colnames(dfs[[x]]),
                                                      sep = "_")))
Sign up to request clarification or add additional context in comments.

2 Comments

That's what I was shooting for...couldn't quite get there.
That's a nice solution, but I would like to keep individual data frames and not coerce to a list object. Of course one could then do: df <- do.call(rbind.data.frame, dfs_new) but that gives all in one df.
1

One way would be:

 df1 <- data.frame(X1=1:5, X2=6:10)
 df2 <- data.frame(X1=16:20, X2=21:25)
 name1 <- ls(pattern="^df\\d+$") 
 cNames <- colnames(df1) #assuming that column names are the same for all dataframes

 for(i in 1:2){
  assign(name1[i], `names<-` (get(name1[i]), paste(name1[i],cNames, sep="_"))) 
  }

 df1
 # df1_X1 df1_X2
 #1      1      6
 #2      2      7
 #3      3      8
 #4      4      9
 #5      5     10

 df2
 #  df2_X1 df2_X2
 #1     16     21
 #2     17     22
 #3     18     23
 #4     19     24
 #5     20     25

Or

  cNames1 <- c(t(outer(name1, cNames, FUN=paste, sep="_")))
  names2 <- split(cNames1,gsub("_.*", "", cNames1))
  list2env(
       Map(function(n1, data) {
       names(data) <- n1
       data
      }, names2, mget(name1)),
               envir = .GlobalEnv)
  df1
 #  df1_X1 df1_X2
 #1      1      6
 #2      2      7
 #3      3      8
 #4      4      9
 #5      5     10

2 Comments

Thanks. Works fine. Why use 'names<-'? It's the first time I see this kind of assignment operator in R.
@USER52306 It is almost similar to x <- get(name1[i]); names(x) <- paste(name1[i], cNames, sep="_"); assign(name1[i], x)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.