从多个csv到数据帧的平均值

时间:2016-04-24 19:26:58

标签: r csv

在这个主题的不同主题中寻找帮助后,我仍然没有变得更聪明。因此:这是关于循环遍历多个数据文件的另一个问题......

行。我在一个包含5列数据的文件夹中有多个CSV文件。文件名如下:

Moist yyyymmdd hh_mm_ss.csv

我想创建一个脚本,逐个读取处理CSV文件,执行以下步骤:

1)加载文件 2)检查行数,如果少于3个注册,则排除文件 3)计算第2列的所有测量值(=行)的平均值 4)计算第4列的所有测量值(=行)的平均值 5)输出文件名时间戳,平均列2和平均列4到数据帧,

我写了以下函数

moist.each.mean <- function() {
  library("tcltk")
  directory <- tk_choose.dir("","Choose folder for Humidity data files")
  setwd(directory)
  filelist <- list.files(path = directory)
  filetitles <- regmatches(filelist, regexpr("[0-9].*[0-9]", filelist))
  mdf <- data.frame(timestamp=character(), humidity=numeric(), temp=numeric())

  for(i in 1:length(filelist)){
    file.in[[i]] <- read.csv(filelist[i], header=F)
    if (nrow(file.in[[i]]<3)){
      print("discard")
    } else {
      newrow <- c(filetitles[[i]], round(mean(file.in[[i]]$V2),1), round(mean(file.in[[i]]$V4),1))
      mdf <- rbind(mdf, newrow)
    }
  } 
  names(mdf) <- c("timestamp", "humidity", "temp")
}

但我一直收到错误:

Error in `[[<-.data.frame`(`*tmp*`, i, value = list(V1 = c(10519949L,  : 
  replacement has 18 rows, data has 17 

有什么想法吗?

Thx,kruemelprinz

3 个答案:

答案 0 :(得分:0)

这是一种略有不同的方法。使用lapply读取每个csv文件,必要时将其排除,否则创建摘要。这将为您提供一个列表,其中每个元素都是数据框摘要。然后使用rbind创建最终的摘要数据框。

如果没有您的数据样本,我无法确定下面的代码与您的问题完全匹配,但希望它足以让您到达目的地。

# Get vector of filenames to read
filelist=list.files(path=directory, pattern="csv")

# Read all the csv files into a list and create summaries
df.list = lapply(filelist, function(f) {

  file.in = read.csv(f, header=TRUE, stringsAsFactors=FALSE)

  # Set to empty data frame if file has less than 3 rows of data
  if (nrow(file.in) < 3) {

    print(paste("Discard", f))

  # Otherwise, capture file timestamp and summarise data frame  
  } else {

    data.frame(timestamp=substr(f, 7, 22), 
               humidity=round(mean(file.in$V2),1), 
               temp=round(mean(file.in$V4),1))
  }
})

# Bind list into final summary data frame (excluding the list elements
# that don't contain a data frame because they didn't have enough rows
# to be included in the summary)
result = do.call(rbind, df.list[sapply(df.list, is.data.frame)])

原始代码的一个问题是您创建了摘要结果的向量而不是结果的数据框:

c(filetitles[[i]], round(mean(file.in[[i]]$V2),1), round(mean(file.in[[i]]$V4),1))是一个包含三个元素的向量。你真正想要的是一个包含三列的数据框:

data.frame(timestamp=filetitles[[i]], 
           humidity=round(mean(file.in[[i]]$V2),1), 
           temp=round(mean(file.in[[i]]$V4),1))

答案 1 :(得分:0)

我还建议使用(l)申请......这是我的看法:

getMeans <- function(fpath,runfct,
                 target_cols = c(2),
                 sep=",",
                 dec=".",
                 header = T,
                 min_obs_threshold = 3){

f&lt; - list.files(fpath)     fcsv&lt; - f [grepl(&#34; \。csv&#34;,f)]

fcsv <- paste0(fpath,fcsv)

csv_list <- lapply(fcsv,read.table,sep = sep,
                 dec = dec, header = header)

csv_rows <- sapply(csv_list,nrow)

rel_csv_list <- csv_list[!(csv_rows < min_obs_threshold)]

lapply(rel_csv_list,function(x) colMeans(x[,target_cols]))


 }

还有这种错误消息,调试器可能非常有用。 只需运行debug(moist.each.mean)并逐步执行该功能。

答案 2 :(得分:0)

感谢使用lapply的建议。这绝对是有价值的,因为它也节省了大量的代码!与此同时,我设法修复了原始代码:

library("tcltk")
# directory: path to csv files
directory <-
  tk_choose.dir("","Choose folder for Humidity data files")
setwd(directory)
filelist <- list.files(path = directory)
filetitles <-
  regmatches(filelist, regexpr("[0-9].*[0-9]", filelist))
mdf <- data.frame()

for (i in 1:length(filelist)) {
  file.in <- read.csv(filelist[i], header = F, skipNul = T)
  if (nrow(file.in) < 3) {
    print("discard")
  } else {
    newrow <-
      matrix(
        c(filetitles[[i]], round(mean(file.in$V2, na.rm=T),1), round(mean(file.in$V4, na.rm=T),1)), nrow = 1, ncol =
          3, byrow = T
      )
    mdf <-  rbind(mdf, newrow)
  }
}

names(mdf) <- c("timestamp", "humidity", "temp")

只有我没有让它作为一个函数工作,因为那时我只会在mdf中有一行包含最后一个文件数据。不知怎的,它没有添加行,但每次迭代都会覆盖第1行。但是在没有函数包装的情况下使用它工作得很好......