根据多个文件中保存的数据计算平均值

时间:2015-06-13 21:14:46

标签: r

我正在尝试编写一个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()的参数。如果有任何帮助,我将不胜感激。 干杯, 吉姆

2 个答案:

答案 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)