在循环中填充数据框

时间:2016-02-28 09:55:51

标签: r csv dataframe

我在目录中有超过300个csv文件。 csv文件具有以下结构

mystr = mystr.replace(/(\d[^\S\r\n]*-)|-(?![^\S\r\n]*\d)/g, function (_, g) {
    return g ? g : ' '; });

我想计算每个csv文件中除了该文件中的NA之外的行数,并将其存储在具有两列的数据帧中:(1)id& (2)nobs。

这是我的代码:

id              Date        Nitrate     Sulfate
id of csv file  Some date   Some Value  Some Value
id of csv file  Some date   Some Value  Some Value
id of csv file  Some date   Some Value  Some Value

当我尝试在循环中填充数据帧时出现问题,似乎它没有填充数据框并返回NULL。我知道我做的事情很蠢。

2 个答案:

答案 0 :(得分:3)

我通常更喜欢将行添加到预先分配的列表中,然后将它们绑定在一起。这是一个有效的例子:

##### fake read.csv function returning random data.frame 
# (just to reproduce your case, remove this from your code...)
read.csv <- function(fileName){
  stupidHash <- sum(as.integer(charToRaw(fileName)))
  if(stupidHash %% 2 == 0){
    return(data.frame(id=stupidHash,date='2016-02-28',
                      nitrate=c(NA,2,3,NA,5),sulfate=c(10,20,NA,NA,40)))
  }else{
    return(data.frame(id=stupidHash,date='2016-02-28',
                      nitrate=c(4,2,3,NA,5,9),sulfate=c(10,20,NA,NA,40,50)))
  }
}
#####

complete <-function(directory,id){
  filenames <-sprintf("%03d.csv", id)
  filenames <-paste(directory,filenames,sep = '/')
  # here we pre-allocate a list of lenght=length(filenames)
  # where we will put the rows of our future data.frame
  rowsList <- vector(mode='list',length=length(filenames)) 
  for(i in 1:length(filenames)){
    filename <- filenames[i]
    data <- read.csv(filename)
    rowsList[[i]] <- data.frame(id=data$id[1],
                                nobs=sum(!is.na(data$sulfate) & !is.na(data$nitrate)))
  }
  # here we bind all the previously created rows together into one data.frame
  DF <- do.call(rbind.data.frame, rowsList)
  return(DF)
}

用法示例:

res <- complete(directory='dir',id=1:3)

> res
   id nobs
1 889    4
2 890    2
3 891    4

答案 1 :(得分:2)

问题在于以下两行:

dataframe[i,dataframe$id]<-data[data$id]
dataframe[i,dataframe$nobs]<-nrow(data[!is.na(data$sulfate & data$nitrate),])

如果要扩展数据帧,请使用rbind功能。但请注意,这不是有效的方法,因为它分配新内存并复制所有数据并添加一个新行。有效的方法是在这一行中分配足够大的数据帧:

dataframe <-data.frame(id=numeric(0),nobs=numeric(0))

使用预期行数。而不是0

所以最简单的方法是

dataframe <- rbind(dataframe, data.frame(id=data$id[1], nobs=nrow(data[!is.na(data$sulfate) & !is.na(data$nitrate),]))

更有效的方式是这样的:

dataframe <-data.frame(id=numeric(numberOfRows),nobs=numeric(numberOfRows))

然后在循环中:

dataframe[i,]$id<-data$id[1]
dataframe[i,]$nobs<-nrow(data[!is.na(data$sulfate) & !is.na(data$nitrate),])

更新:我将用于填充数据框的值更改为data$id[1]nrow(data[!is.na(data$sulfate) & !is.na(data$nitrate),])