我正在尝试编写一个R脚本,根据332个监测站中的一个或多个的数据计算指定污染物(硝酸盐或硫酸盐)的平均值。来自每个站的数据保存在单独的文件中,编号为1:332。我是R的新手,为了对任何选择帮助我的人公平,我应该说这是一个家庭作业问题。我编写了下面的脚本,它只适用于一个文件:
pollutantmean <- function(directory, pollutant, id = 1:332) {
filepath <- "/Users/jim/Documents/Coursera/2_R_Prog/Data"
for(i in seq_along(id)) {
if(id < 10) {
name <- paste("00", id[i], sep = "")
}
if(id >= 10 && id < 100) {
name <- paste("0", id[i], sep = "")
}
if(id >= 100) {
name <- id[i]
}
}
file <- paste(name, "csv", sep = ".")
station <- paste(filepath, directory, file, sep = "/")
monitor <- read.csv(station)
if(pollutant == "nitrate") {
x <- mean(monitor$nitrate, na.rm = T)
}
if(pollutant == "sulfate") {
x <- mean(monitor$sulfate, na.rm = T)
}
x
}
但是,如果我输入多个文件(例如70:72),我只得到最后一个文件的平均值(72)。这告诉我,它正在计算每个文件的平均值,然后用下一个文件的平均值覆盖它,这样只输出最后一个文件。我可以使用rbind()来解决这个问题,但是我无法弄清楚如何为每个变量分配唯一的名称,这些名称将成为rbind()的参数。如果有任何帮助,我将不胜感激。 干杯, 吉姆
答案 0 :(得分:0)
你不要遍历文件。
你得到了最后一个文件的意思,因为当你循环id以创建名字时,你的循环会返回创建的姓氏。
你应该创建一个名称向量然后驻留并循环它!
提示:您不需要循环和条件语句来创建您的名称,您可以使用sprintf
来精确预期字符串的大小(3)以及您希望“扩展”的内容string(0)
> id <- c(1, 10, 100)
> names <- sprintf("%03d", id)
> names
[1] "001" "010" "100"
这应该有效:
pollutantmean <- function(directory, pollutant, id = 1:332) {
filepath <- "/Users/jim/Documents/Coursera/2_R_Prog/Data"
names <- sprintf("%03d", id)
files <- paste0(names, ".csv") # Or directly : files <- sprintf("%03d.csv", id)
station <- file.path(filepath, directory, files)
means <- numeric(length(station))
for (i in seq_along(station)) {
monitor <- read.csv(station[i])
if(pollutant == "nitrate") {
means[i] <- mean(monitor$nitrate, na.rm = T)
} else if(pollutant == "sulfate") {
means[i] <- mean(monitor$sulfate, na.rm = T)
}
}
return(means)
}
编辑: 如果你想要一个单一的平均值,你可以使用上面的代码并通过nrow non NA来思考每个方法。将循环替换为:
means <- numeric(length(station))
counts <- numeric(length(station))
for (i in seq_along(station)) {
monitor <- read.csv(station[i])
if(pollutant == "nitrate") {
means[i] <- mean(monitor$nitrate, na.rm = TRUE)
counts[i] <- sum(!is.na(monitor$nitrate))
} else if(pollutant == "sulfate") {
means[i] <- mean(monitor$sulfate, na.rm = TRUE)
counts[i] <- sum(!is.na(monitor$sulfate))
}
}
myMean <- sum(means * counts) / sum(counts)
return(myMean)
由于您的第一个目的是将数据收集到一个向量中,这里有一个解决方案,创建一个列表,其中每个元素是每个数据帧的所需“污染物”变量,unlist将所有向量收集到1然后我们可以计算此向量的均值。
pollutantmean <- function(directory, pollutant, id = 1:332) {
filepath <- "/Users/jim/Documents/Coursera/2_R_Prog/Data"
names <- sprintf("%03d", id)
files <- paste0(names, ".csv") # Or directly : files <- sprintf("%03d.csv", id)
station <- file.path(filepath, directory, files)
li <- lapply(station, function(x) {
monitor <- read.csv(x)
if(pollutant == "nitrate") {
monitor$nitrate
} else if(pollutant == "sulfate") {
monitor$sulfate
}
})
myMean <- mean(unlist(li))
return(myMean)
}
答案 1 :(得分:0)
Julien Navarre的第二个污染物功能的小修正。在计算均值时,不会忽略NA值,这可能会影响整体结果。所以计算平均值的线应该是这样的。
myMean <- mean(unlist(l), na.rm=TRUE)