读取具有不同行数的多个CSV以在文件开头跳过

时间:2013-03-11 06:07:05

标签: r csv read.table

我必须阅读大约300个单独的CSV。我已设法使用循环和结构化CSV名称自动化该过程。但是,每个CSV在开始时都有14-17行垃圾,并且随机变化,因此在read.table命令中编写'skip'参数的硬编码将无效。每个CSV的列名和列数相同。

以下是我反对的一个例子:

QUICK STATISTICS:

      Directory: Data,,,,
           File: Final_Comp_Zn_1
      Selection: SEL{Ox*1000+Doma=1201}
         Weight: None,,,
     ,,Variable: AG,,,

Total Number of Samples: 450212  Number of Selected Samples: 277


Statistics

VARIABLE,Min slice Y(m),Max slice Y(m),Count,Minimum,Maximum,Mean,Std.Dev.,Variance,Total Samples in Domain,Active Samples in Domain AG,  
6780.00,   6840.00,         7,    3.0000,   52.5000,   23.4143,   16.8507,  283.9469,        10,        10 AG,   
6840.00,   6900.00,         4,    4.0000,    5.5000,    4.9500,    0.5766,    0.3325,        13,        13 AG,   
6900.00,   6960.00,        16,    1.0000,   37.0000,    8.7625,    9.0047,   81.0848,        29,        29 AG,   
6960.00,   7020.00,        58,    3.0000,   73.5000,   10.6931,   11.9087,  141.8172,       132,       132 AG,   
7020.00,   7080.00,        23,    3.0000,  104.5000,   15.3435,   23.2233,  539.3207,        23,        23 AG,   
7080.00,   7140.00,        33,    1.0000,   15.4000,    3.8152,    2.8441,    8.0892,        35,        35 AG,

基本上我想阅读VARIABLE,Min slice Y(m),Max slice Y(m),...行。我可以想到一些解决方案,但我不知道如何编程。无论如何我可以:

  1. 首先读取CSV并以某种方式计算出有多少垃圾线然后重新读取并指定要跳过的正确行数?或
  2. 告诉read.table在找到列名时开始阅读(因为每个CSV的名称相同)并忽略之前的所有内容?
  3. 我认为解决方案(2)是最合适的,但我愿意接受任何建议!

2 个答案:

答案 0 :(得分:17)

这是一个可以采取的方法的最小例子。

首先,让我们编写一些类似于你描述的csv文件:

cat("blah\nblah\nblah\nVARIABLE,X1,X2\nA,1,2\n", file="myfile1.csv")
cat("blah\nVARIABLE,A1,A2\nA,1,2\n", file="myfile2.csv")
cat("blah\nblah\nVARIABLE,Z1,Z2\nA,1,2\n", file="myfile3.csv")

其次,确定数据的开始位置:

linesToSkip <- sapply(list.files(pattern = "myfile.*.csv"), 
                      function(x) grep("^VARIABLE", readLines(x))-1)

第三,使用该信息将您的文件读入单个列表。

lapply(names(linesToSkip), 
       function(x) read.csv(file=x, skip = linesToSkip[x]))
# [[1]]
#   VARIABLE X1 X2
# 1        A  1  2
# 
# [[2]]
#   VARIABLE A1 A2
# 1        A  1  2
# 
# [[3]]
#   VARIABLE Z1 Z2
# 1        A  1  2

编辑#1

两次读取数据的替代方法是将其读入列表一次,然后执行相同类型的处理:

myRawData <- lapply(list.files(pattern = "myfile.*.csv"), readLines)
lapply(myRawData, function(x) {
  linesToSkip <- grep("^VARIABLE", x)-1
  read.csv(text = x, skip = linesToSkip)
})

或者,就此而言:

lapply(list.files(pattern = "myfile.*.csv"), function(x) {
  temp <- readLines(x)
  linesToSkip <- grep("^VARIABLE", temp)-1
  read.csv(text = temp, skip = linesToSkip)
})

编辑#2

正如@PaulHiemstra所说,您可以使用参数n仅将每个文件的几行读入内存,而不是读取整个文件。因此,如果您确定每个文件中不超过20行“垃圾”,如果您使用的是第一种方法,则可以使用:

linesToSkip <- sapply(list.files(pattern = "myfile.*.csv"), 
                      function(x) grep("^VARIABLE", readLines(x, n = 20))-1)

答案 1 :(得分:9)

data.table中的函数fread会自动检测要跳过的行数。该功能目前处于开发阶段。

以下是一个示例代码:

require(data.table)

cat("blah\nblah\nblah\nVARIABLE,X1,X2\nA,1,2\n", file="myfile1.csv")
cat("blah\nVARIABLE,A1,A2\nA,1,2\n", file="myfile2.csv")
cat("blah\nblah\nVARIABLE,Z1,Z2\nA,1,2\n", file="myfile3.csv")

lapply(list.files(pattern = "myfile.*.csv"), fread)