【问题标题】:Mean values from multiple csv to data frame从多个 csv 到数据框的平均值
【发布时间】:2016-04-24 19:26:57
【问题描述】:

在这个主题的不同线程中搜索了帮助之后,我仍然没有变得更聪明。因此:关于循环多个数据文件的问题又来了……

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

潮湿 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 

有什么想法吗?

谢谢,kruemelprinz

【问题讨论】:

  • file.in 定义在哪里?
  • 不幸的是,我不知道如何定义它。到目前为止,我已经付出了很多努力...... file.in 是用于加载某个 csv 的临时对象,直到它被下一个处理的文件覆盖。

标签: r csv


【解决方案1】:

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

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

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】:

    这里有一个稍微不同的方法。使用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))
    

    【讨论】:

      【解决方案3】:

      感谢使用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 行。但是在没有函数包装的情况下使用它效果很好......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-20
        • 1970-01-01
        • 2020-06-04
        • 2019-05-12
        • 1970-01-01
        • 2021-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多