读取CSV文件时跳过可变行数,批量处理。

7

我想要创建一个循环,读取多个CSV文件,这些文件都有相同类型的空气温度数据。但是,我想要跳过数据上面的某些行。这些行在数据集中表示“警报”。每个文件可能有不同数量的警报,因此需要跳过不同数量的行。请参见以下内容:

-------------First CSV file---------------
Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2

-------------Second CSV file---------------
Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Alarm 5
Alarm 6
Alarm 7
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2

我该如何获取 DateTemp 的索引,以便告诉 read.csv 跳过这一行?

for (i in 1:length(csv.list))  {
  df = read.csv(csv.list[i], header = T, skip=????????)
}

为什么不先插入到临时表中,然后再从中筛选插入呢? - Anthony Horne
4个回答

6
在你的循环中,在read.table之前添加几行代码。
使用readLines读取数据。
r <- readLines(textConnection("Logger 001
               Alarm 1
               Alarm 2
               Alarm 3
               Alarm 4
               Date, Temp
               01/01/2011, -1.2
               01/02/2011, -1.3
               01/03/2011, -1.1
               01/04/2011, -1.2"))

[但是没有textConnection适用于您的ie r <- readLines("yourcsv")]

使用grep找到实际标题开始的行号。

dt <- grep("Date",r)

读取数据 - 跳过头部之前的行

read.table(text=r , header=TRUE, sep="," , skip = dt-1)


为了读取您的多个csv文件 - 这些文件将被存储在数据框列表中

 df.lst <- lapply(csv.list , function(i) {
                        r <- readLines(i)
                        dt <- grep("Date",r)
                        read.table(text=r , header=TRUE, sep="," , skip = dt-1)
                         })

3

data.table包中的fread函数可能对您有用,因为它在自动检测“垃圾”标题行方面非常出色。下面是一个示例:

首先,创建两个示例csv文件。

cat("Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2
", file = "socsv1.csv", sep = "\n")

cat("Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Alarm 5
Alarm 6
Alarm 7
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2", file = "socsv2.csv", sep = "\n")

## Check that they were created
list.files(pattern = "socsv")
# [1] "socsv1.csv" "socsv2.csv"

现在,只需使用 fread 并指定 sep,而不是让 fread 猜测。
library(data.table)
lapply(list.files(pattern = "socsv"), fread, sep = ",")
# [[1]]
#          Date  Temp
# 1: 01/01/2011  -1.2
# 2: 01/02/2011  -1.3
# 3: 01/03/2011  -1.1
# 4: 01/04/2011  -1.2
# 
# [[2]]
#          Date  Temp
# 1: 01/01/2011  -1.2
# 2: 01/02/2011  -1.3
# 3: 01/03/2011  -1.1
# 4: 01/04/2011  -1.2

1

count.fields 可以识别每个文件中第一行有两个逗号分隔字段的行。然后,您可以使用此来指定 skip。例如:

writeLines('Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2', f <- tempfile())

writeLines('Logger 001
Alarm 1
Alarm 2
Alarm 3
Alarm 4
Alarm 5
Alarm 6
Alarm 7
Date, Temp
01/01/2011, -1.2
01/02/2011, -1.3
01/03/2011, -1.1
01/04/2011, -1.2', f2 <- tempfile())

for (x in c(f, f2))  {
  ind <- match(2, count.fields(x, ','))
  df <- read.csv(x, header = T, skip=ind - 1)
  print(df)
}

#         Date Temp
# 1 01/01/2011 -1.2
# 2 01/02/2011 -1.3
# 3 01/03/2011 -1.1
# 4 01/04/2011 -1.2
# Date Temp
# 1 01/01/2011 -1.2
# 2 01/02/2011 -1.3
# 3 01/03/2011 -1.1
# 4 01/04/2011 -1.2

0

我认为有一个更简单的方法,就是按原样读取文件,并带有一些选项。

df = read.csv('weather-logger2.csv', colClasses = c('character', 'numeric'),
              col.names = c('Date', 'Temp'),
              na.strings = 'Temp', fill = TRUE, stringsAsFactors = FALSE)

前几行包含非日期字符串,将它们转换为日期时会得到NA(无法识别),但是您必须以这种方式进行转换以进行进一步处理,然后只需子集化并丢弃缺失值:

     Date Temp
1     Alarm 1   NA
2     Alarm 2   NA
3     Alarm 3   NA
4     Alarm 4   NA
5     Alarm 5   NA
6     Alarm 6   NA
7     Alarm 7   NA
8        Date   NA
9  01/01/2011 -1.2
10 01/02/2011 -1.3
11 01/03/2011 -1.1
12 01/04/2011 -1.2

df$Date = as.Date(df$Date, '%d/%m/%Y')
df = subset(df, !is.na(Date))

要获取:

         Date Temp
9  2011-01-01 -1.2
10 2011-02-01 -1.3
11 2011-03-01 -1.1
12 2011-04-01 -1.2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接