2016-02-28 131 views
0

我在一个目录中有超过300个csv文件。 将CSV文件具有以下结构在循环中填充数据帧

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 

我希望计算在该文件中不包括NA每个csv文件的行数并将其存储在数据帧,其具有两列:(1)ID &(2) NOBS。

这里是我的代码:

complete <-function(directory,id){ 
    filenames <-sprintf("%03d.csv", id) 
    filenames <-paste(directory,filenames,sep = '/') 
    dataframe <-data.frame(id=numeric(0),nobs=numeric(0)) 
    for(i in filenames){ 
    data <- read.csv(i) 
    dataframe[i,dataframe$id]<-data[data$id] 
    dataframe[i,dataframe$nobs]<-nrow(data[!is.na(data$sulfate & data$nitrate),]) 
    } 

    dataframe 

} 

的问题,当我尝试填充在循环中出现数据帧,好像它不填充数据帧,返回NULL我。我知道我在做一些愚蠢的事情。

+0

你检查这个职位? http://stackoverflow.com/questions/14358629/counting-the-number-of-rows-of-a-series-of-csv-files – 2016-02-28 10:01:53

回答

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),])

+0

@bartoszukum我试过你的方法,但它以这个错误结束。错误在'$ < - 。data.frame'('* tmp *',“id”,value = list()): 替换有1461行,数据有1 –

+0

@Farrukh Ahmed对不起,我认为您使用的值填充数据帧是有效的。请考虑它。我假设数据$ id在每个位置都有相同的值,所以我首先使用。要使用is.na,必须分别检查每列,并在此之后进行逻辑“和”。 – bartoszukm

+0

非常感谢@bartoszukum。它的工作原理是 。 –

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