R, создание переменных на лету в списке с помощью оператора assign
Я хочу создавать имена переменных на лету внутри списка и присваивать им значения в R, но я не могу получить желаемый результат. Вот логика моего кода:
После вызова функции: dat_in <- readf(1,2)
входной файл читается на основе продукта и сайта. После прочтения конкретный столбец (13-й здесь) назначается переменной aot500
, Я хочу, чтобы эта переменная возвращалась из функции для каждой комбинации продукта и сайта. Например, мне нужно имя переменной в списке оператора как aot500.AF
, aot500.CM
, aot500.RB
должен быть возвращен из этой функции. У меня проблемы с return
заявление. Там нет ошибки, но нет ничего в dat_in
, Я ожидаю, что это dat_in$aot500.AF
и т.д. Пожалуйста, сообщите, что не так в return
заявление. Кроме того, я хочу прочитать файлы для всех комбинаций за один вызов функции, скажем, с помощью цикла for, и мне интересно, как оператор return будет обрабатывать список других переменных.
prod <- c('inv','tot')
site <- c('AF','CM','RB')
readf <- function(pp, kk) {
fname.dsa <- paste("../data/site_data_",prod[pp],"/daily_",site[kk],".dat",sep="")
inp.aod <- read.csv(fname.dsa,skip=4,sep=",",stringsAsFactors=F,na.strings="N/A")
aot500 <- inp.aod[,13]
return(list(assign(paste("aot500",siteabbr[kk],sep="."),aot500)))
}
2 ответа
Почти всегда нет необходимости использовать assign()
, мы можем решить проблему в два этапа, прочитать файлы в список, а затем дать имена.
(Не проверено, так как у нас нет ваших файлов)
prod <- c('inv', 'tot')
site <- c('AF', 'CM', 'RB')
# get combo of site and prod
prod_site <- expand.grid(prod, site)
colnames(prod_site) <- c("prod", "site")
# Step 1: read the files into a list
res <- lapply(1:nrow(prod_site), function(i){
fname.dsa <- paste0("../data/site_data_",
prod_site[i, "prod"],
"/daily_",
prod_site[i, "site"],
".dat")
inp.aod <- read.csv(fname.dsa,
skip = 4,
stringsAsFactors = FALSE,
na.strings = "N/A")
inp.aod[, 13]
})
# Step 2: assign names to a list
names(res) <- paste("aot500", prod_site$prod, prod_site$site, sep = ".")
Я предлагаю два ответа, один на основе dplyr и один на основе R. Вам, вероятно, придется адаптировать filename
в readAOT_500
функция для вашего конкретного случая.
Base R ответ
#' Function that reads AOT_500 from the given product and site file
#' @param prodsite character vector containing 2 elements
#' name of a product and name of a site
readAOT_500 <- function(prodsite,
selectedcolumn = c("AOT_500"),
path = tempdir()){
cat(path, prodsite)
filename <- paste0(path, prodsite[1],
prodsite[2], ".csv")
dtf <- read.csv(filename, stringsAsFactors = FALSE)
dtf <- dtf[selectedcolumn]
dtf$prod <- prodsite[1]
dtf$site <- prodsite[2]
return(dtf)
}
# Load one file for example
readAOT_500(c("inv", "AF"))
listofsites <- list(c("inv","AF"),
c("tot","AF"),
c("inv", "CM"),
c( "tot", "CM"),
c("inv", "RB"),
c("tot", "RB"))
# Load all files in a list of data frames
prodsitedata <- lapply(listofsites, readAOT_500)
# Combine all data frames together
prodsitedata <- Reduce(rbind,prodsitedata)
ответ dplyr
Я использую пакеты Хэдли Уикхем для очистки данных.
library(dplyr)
library(tidyr)
daily_CM <- read.csv("~/downloads/daily_CM.dat",skip=4,sep=",",stringsAsFactors=F,na.strings="N/A")
# Generate all combinations of product and site.
prodsite <- expand.grid(prod = c('inv','tot'),
site = c('AF','CM','RB')) %>%
# Group variables to use do() later on
group_by(prod, site)
Создайте 6 поддельных файлов путем выборки из предоставленных вами данных
Вы можете пропустить этот раздел, когда у вас есть реальные данные. Я использовал различную длину выборки, чтобы количество наблюдений отличалось для каждого участка.
prodsite$samplelength <- sample(1:495,nrow(prodsite))
prodsite %>%
do(stuff = write.csv(sample_n(daily_CM,.$samplelength),
paste0(tempdir(),.$prod,.$site,".csv")))
Чтение многих файлов с помощью dplyr::do()
prodsitedata <- prodsite %>%
do(read.csv(paste0(tempdir(),.$prod,.$site,".csv"),
stringsAsFactors = FALSE))
# Select only the columns you are interested in
prodsitedata2 <- prodsitedata %>%
select(prod, site, AOT_500)