J.Con
J.Con

Reputation: 4309

Change specific columns in list of data frames - R

In a list of data frames: (mylist<-list(iris, mtcars, ToothGrowth)), how can I make a change only to specific columns within the list?

For example, I have a character vector (test) that gives the column names"Petal.Width" and "drat". How can I match these names to column names in my list of data frames and apply something like log(x + 1)?

So far I am able to get the required columns out on their own, but I'm not sure how to keep the whole list of data frames together and just alter a couple of columns. Thank you

Upvotes: 4

Views: 746

Answers (3)

akrun
akrun

Reputation: 887028

Another option is to use intersect with the names of the columns to avoid getting the warnings

library(tidyverse)
out <- mylist %>%
           map(~ .x %>%
                  mutate_at(vars(intersect(names(.), test)), myfun))

data

mylist<-list(iris, mtcars, ToothGrowth)
myfun <- function(x) {
 log(x + 1)
}

test <- c("Petal.Width", "drat") 

Upvotes: 1

neilfws
neilfws

Reputation: 33782

I'd first define the function you want to apply, in your example log(x + 1):

myfun <- function(x) {
  log(x + 1)
}

Then use purrr::map to go through the list and dplyr::mutate_at to match the column names:

library(tidyverse)
mylist %>% 
  map(~mutate_at(.x, vars(one_of(c("Petal.Width", "drat"))), myfun))

Note this will give warnings because not all data frames contain the columns. You could use matches() instead if the warnings bother you:

mylist %>% 
  map(~mutate_at(.x, vars(matches("^Petal\\.Width|drat$")), myfun))

Upvotes: 2

Ronak Shah
Ronak Shah

Reputation: 388862

We can do this in couple of steps

test <- c("Petal.Width", "drat")

#Calculate the new value only for those specific columns which we need
value_cols <- lapply(mylist, function(x) log(x[names(x) %in% test]))

value_cols contains values for columns which we need to change.

We then use mapply and select specific columns from each list and update their values.

mapply(function(x, y) {
  x[names(x) %in% test] <- y
  x }, mylist, value_cols)

where value_cols is

value_cols
#[[1]]
#     Petal.Width
#1   -1.60943791
#2   -1.60943791
#3   -1.60943791
#4   -1.60943791
#5   -1.60943791
#...
#...
#[[2]]
#                    drat
#Mazda RX4           1.360977
#Mazda RX4 Wag       1.360977
#Datsun 710          1.348073
#Hornet 4 Drive      1.124930
#Hornet Sportabout   1.147402
#...
#...
#[[3]]
#data frame with 0 columns and 60 rows

Upvotes: 1

Related Questions