32

Objective: Change the Column Names of all the Data Frames in the Global Environment from the following list

colnames of the ones in global environment

So.

0) The Column names are:

 colnames = c("USAF","WBAN","YR--MODAHRMN") 

1) I have the following data.frames: df1, df2.

2) I put them in a list:

  dfList <- list(df1,df2)

3) Loop through the list:

 for (df in dfList){
   colnames(df)=colnames
 }

But this creates a new df with the column names that I need, it doesn't change the original column names in df1, df2. Why? Could lapply be a solution? Thanks

Can something like:

 lapply(dfList, function(x) {colnames(dfList)=colnames})

work?

Oniropolo
  • 879
  • 2
  • 12
  • 18

6 Answers6

50

With lapply you can do it as follows.

Create sample data:

df1 <- data.frame(A = 1, B = 2, C = 3)
df2 <- data.frame(X = 1, Y = 2, Z = 3)
dfList <- list(df1,df2)
colnames <- c("USAF","WBAN","YR--MODAHRMN") 

Then, lapply over the list using setNames and supply the vector of new column names as second argument to setNames:

lapply(dfList, setNames, colnames)
#[[1]]
#  USAF WBAN YR--MODAHRMN
#1    1    2            3
#
#[[2]]
#  USAF WBAN YR--MODAHRMN
#1    1    2            3

Edit

If you want to assign the data.frames back to the global environment, you can modify the code like this:

dfList <- list(df1 = df1, df2 = df2)
list2env(lapply(dfList, setNames, colnames), .GlobalEnv)
talat
  • 68,970
  • 21
  • 126
  • 157
  • @Oniropolo, see my edit. This will change your original data.frames in the global environment – talat Feb 21 '15 at 17:34
  • This is way to advanced for my R knowledge, but I was reading on environments. Can I ask you why 1) you didn't create a new environment instead of a list? 2) Suppose then you need to do some data cleaning, like strptime(df1$YR--MODAHRMN,format ='%Y%m%d%H%M'). Would it be possible to create an environment and then modify all the elements in this new environment? Sorry for the lack of knowledge! – Oniropolo Feb 21 '15 at 18:04
  • 1
    @Oniropolo, your question was based on having a list of data.frames where you want to change the names - that's why I used the list structure.. Normally, if you have many data.frames that are somehow related it's better to keep them in a list (i.e. not assign them back to the global environment). Generally, I hardly ever create extra environments but that depends on personal programming preference, I guess. – talat Feb 21 '15 at 18:08
  • Thank you very much! I didn't know what an environment was before your answer ! – Oniropolo Feb 21 '15 at 18:11
13

Just change your for-loop into an index for-loop like this:

Data

df1 <- data.frame(a=runif(5), b=runif(5), c=runif(5))
df2 <- data.frame(a=runif(5), b=runif(5), c=runif(5))

dflist <- list(df1,df2)

colnames = c("USAF","WBAN","YR--MODAHRMN") 

Solution

for (i in seq_along(dflist)){
  colnames(dflist[[i]]) <- colnames
}

Output

> dflist
[[1]]
       USAF      WBAN YR--MODAHRMN
1 0.8794153 0.7025747    0.2136040
2 0.8805788 0.8253530    0.5467952
3 0.1719539 0.5303908    0.5965716
4 0.9682567 0.5137464    0.4038919
5 0.3172674 0.1403439    0.1539121

[[2]]
        USAF       WBAN YR--MODAHRMN
1 0.20558383 0.62651334    0.4365940
2 0.43330717 0.85807280    0.2509677
3 0.32614750 0.70782919    0.6319263
4 0.02957656 0.46523151    0.2087086
5 0.58757198 0.09633181    0.6941896

By using for (df in dfList) you are essentially creating a new df each time and change the column names to that leaving the original list (dfList) untouched.

LyzandeR
  • 37,047
  • 12
  • 77
  • 87
  • Why does then...> colnames(df2) return the original [1] "a" "b" "c" ? – Oniropolo Feb 21 '15 at 17:29
  • Because the data.frames that change are the ones in the list not the ones outside the list. If you do `colnames(df2)` you will get the original names because nothing happened to df2. Do `colnames(dflist[[2]])` instead to see the result. `df2` is the second element in the list and this is what changed. You can do `df2 <- dflist[[2]]` if you want afterwards. – LyzandeR Feb 21 '15 at 17:32
  • The question then is how to change the original df2 ? The columns that matter are the original df1, df2; the list is just a way of changing both in one loop. – Oniropolo Feb 21 '15 at 17:33
  • I provided a solution above :): `df2 <- dflist[[2]]` – LyzandeR Feb 21 '15 at 17:33
  • 1
    Ohhh, the simplest line possible. How it didnt occur to me. Thanks! – Oniropolo Feb 21 '15 at 17:35
  • No worries. Have a look at @docendodiscimus solution above. It is a bit more advanced, but it might be worth learning. – LyzandeR Feb 21 '15 at 17:36
  • @Oniropolo please edit the first line of your question to reflect that it's not the `data.frames` in the list that you want to change the colnames of, but the colnames of the ones in global environment. – StrikeR Feb 21 '15 at 17:45
1

If you want the for loop to work, you should not pass the whole data.frame as the argument.

for (df in 1:length(dfList))
  colnames(dfList[[df]]) <- colnames
StrikeR
  • 1,598
  • 5
  • 18
  • 35
  • I really don't get it... So for example using the example the first person gave, with your code, I still get colnames(df2) ...[1] "X" "Y" "Z" – Oniropolo Feb 21 '15 at 17:31
  • In that answer you are talking about, df2 is a `data.frame` which does not have anything to do with dfList, which is combination of df1 and df2. So, the names are changed in the df2 that is present inside the dfList. Look at `colnames(dfList$df2)` for changed column names. – StrikeR Feb 21 '15 at 17:38
1

A tidyverse solution with rename_with:

library(dplyr)
library(purrr)

map(dflist, ~ rename_with(., ~ colnames))

Or, if it's only for one column:

map(dflist, ~ rename(., new_col = old_col))

This also works with lapply:

lapply(dflist, rename_with, ~ colnames)
lapply(dflist, rename, new_col = old_col)
Maël
  • 45,206
  • 3
  • 29
  • 67
0
dfList <- lapply(dfList, `names<-`, colnames)
Dan Lewer
  • 871
  • 5
  • 12
  • While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Gerhard Jul 05 '21 at 11:08
  • Maybe ... it's still better than the accepted solution :) – Dan Lewer Jul 05 '21 at 11:14
0

Create the sample data:

df1 <- data.frame(A = 1, B = 2, C = 3)
df2 <- data.frame(X = 1, Y = 2, Z = 3)
dfList <- list(df1,df2)
name <- c("USAF","WBAN","YR--MODAHRMN")

Then create a function to set the colnames:

res=lapply(dfList, function(x){colnames(x)=c(name);x})

[[1]]
USAF WBAN YR--MODAHRMN
1    1    2            3

[[2]]
USAF WBAN YR--MODAHRMN
1    1    2            3
  • 1
    Sure—but your answer puts the new data frames in res, when it seems the question asks for changing the names in the environment. Your answer isn't substantially different, and no better, than the accepted answer. – Prayag Gordy Dec 07 '22 at 05:14