Как запустить один и тот же код на нескольких фреймах данных? - PullRequest
0 голосов
/ 27 сентября 2019

У меня есть список фреймов данных, импортированных из папки, и я хочу написать функцию, которая будет изменять некоторые значения в зависимости от заголовка фрейма данных (который берется из имени файла).

library(dplyr)

time_geog <- function(index) {
  index = index %>%
    mutate(Quarter = quarter(as.Date(quarter_date, format = "%d/%m/%Y"),
                             with_year = TRUE),
           Quarter = paste0(substr(as.character(Quarter), 1, 4),"Q",
                            substr(as.character(Quarter), 6, 6)),
           QuarterQF = case_when(Quarter == "2018Q4" ~ "p",
                                 TRUE ~ ""))
  if(str_detect(index, "Title")) {
    index = index %>% 
      mutate(var1 = case_when(var1 == "abcd" ~ "code",
                                             TRUE ~ var1),
             var2 = case_when(var2 == "abcd" ~ "code",
                                           TRUE ~ var2),
             QF1 = case_when(var1 %in% c("value1", "value2") ~ "x",
                                   TRUE ~ ""),
             QF2 = case_when(var2 %in% c("value1", "value2") ~ "x",
                                   TRUE ~ ""))
  } else {
    index = index %>%
      mutate(var3 = case_when(var3 == "abcd" ~ "code",
                                 TRUE ~ var3),
             var4 = case_when(var4 == "abcd" ~ "code",
                                  TRUE ~ var4),
             QF1 = case_when(var3 == "value1" ~ "d", TRUE ~ "",
                                  var3 %in% c("value2", "value3") ~ "x",
                                  TRUE ~ ""))
  }
}

Я поместил эту функцию в цикл for, как показано ниже, который также считывает все нужные мне файлы и присваивает им имя на основе их исходного имени.

for (i in names) {
  filepath <- file.path(files, paste0(i, ".csv"))
  assign(substr(i, 10, nchar(i)), read_csv(filepath)) 
  time_geog(get(substr(i, 10, nchar(i))))
}

Это работает, когда я передаю ему определенный файл, но не когда я запускаю цикл.У меня также нет проблем с чтением нужных мне файлов с нужными заголовками.Я не хочу, чтобы все они потом находились в одном и том же фрейме данных, что происходит, если я использую:

for (i in names) {
  filepath <- file.path(files, paste0(i, ".csv"))
  assign(substr(i, 10, nchar(i)), read_csv(filepath)) 
  i <- time_geog(get(substr(i, 10, nchar(i))))
}

Любая помощь будет принята с благодарностью.Я чувствую, что я действительно близко, но мне просто не хватает жизненно важных знаний!

Ответы [ 2 ]

0 голосов
/ 27 сентября 2019

Вы упоминаете "список фреймов данных" , но ваш код показывает, что вы используете assign, что я обычно не рекомендую.Если ваши фреймы достаточно похожи, то вы можете получить свой список с

list_of_frames <- setNames(lapply(paste0(files, ".csv"), readr::read_csv),
                           files)

(или некоторыми substr именами файлов).

Ваша функция надеется получить имя объекта путем сопоставления с самим объектом.Хотя есть способы сделать это (что-то вроде deparse / substitute, а не способ, которым вы пытаетесь), это не сработает во всех случаях, и я полагаю, что на него не следует полагаться.

Вместо этого я предлагаю, чтобы вашей функции было присвоено имя с данными.Возможно, что-то вроде этого (не проверено):

time_geog <- function(index, name) {
  index = index %>%
    mutate(Quarter = quarter(as.Date(quarter_date, format = "%d/%m/%Y"),
                             with_year = TRUE),
           Quarter = paste0(substr(as.character(Quarter), 1, 4),"Q",
                            substr(as.character(Quarter), 6, 6)),
           QuarterQF = case_when(Quarter == "2018Q4" ~ "p",
                                 TRUE ~ ""))
  if(str_detect(name, "Title")) {
    index = index %>% 
      mutate(var1 = case_when(var1 == "abcd" ~ "code",
                                             TRUE ~ var1),
             var2 = case_when(var2 == "abcd" ~ "code",
                                           TRUE ~ var2),
             QF1 = case_when(var1 %in% c("value1", "value2") ~ "x",
                                   TRUE ~ ""),
             QF2 = case_when(var2 %in% c("value1", "value2") ~ "x",
                                   TRUE ~ ""))
  } else {
    index = index %>%
      mutate(var3 = case_when(var3 == "abcd" ~ "code",
                                 TRUE ~ var3),
             var4 = case_when(var4 == "abcd" ~ "code",
                                  TRUE ~ var4),
             QF1 = case_when(var3 == "value1" ~ "d", TRUE ~ "",
                                  var3 %in% c("value2", "value3") ~ "x",
                                  TRUE ~ ""))
  }
  return(index)
}
out <- Map(time_geog, list_of_frames, files)
0 голосов
/ 27 сентября 2019

Всегда помните, что правильный способ манипулирования множеством фреймов данных - это сохранять их в списке, а затем применять вашу функцию к списку одновременно, используя lapply или другие функции отображения.

У меня нет ваших данных, но на основании предоставленного вами кода вы можете попробовать:

# create an empty list (you may want to specify the length of the list if you know the total number of your files)   
df_list <- list()

# store all dataframe into the list
for (i in names) {
  filepath <- file.path(files, paste0(i, ".csv"))
  df_list[[length(df_list)+1]] <- read_csv(filepath) 
}

# apply your function to the list
df_list_new <- lapply(df_list,time_geog)

# merge the list into one master dataframe (`bind_rows()` comes from `dplyr` package)
df_master <- bind_rows(df_list_new)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...