如何在 R 中自动导入数据、添加时间戳和标准化数据文件中的行数



我有一个包含 1900 个数据集 (.dat) 的文件夹,它是 2012-2017 年的 1 天食物消费数据。 它们根据日期命名,如下所示:

FC-20120204.dat 
FC-20120205.dat 
FC-20120206.dat

每个数据集包含 1500列(1500 个变量),1440 行(1 分钟数据)。

我的问题是这些:

  1. 很多数据集不完整,即只有 899 行,1101 行
  2. 没有日期/时间戳,因此可能会令人困惑
  3. 我只需要时间戳和第 25 列中的数据。
  4. 这些数据应该是连续的,所以我最终必须将它们绑定在一起。

但首先我认为我需要做:

  1. 找到一种方法来标准化所有数据集以准确包含 1440 行。

到目前为止,我已经在stackoverflow中尝试了我之前的问题:

files<-list.files(pattern="FC")
result <- sapply(files, function(file) {
temp <- read.csv(file) # adjustments may be needed for headers, etc.
temp[,25]
})

它运行良好,直到 R Studio 突然崩溃。我想这是因为我有 1900 个数据集(整个数据集约为 9 GB。我的电脑内存只有 8 GB)。所以列表文件功能不适用,我想sapply和lapply也不适用。

我想必须一个接一个地自动化它,即一次导入一个文件,添加时间戳,标准化每个文件以包含 1440 行,选择所需的列,将其另存为新的.dat文件,重复另一个文件。

之后,我可以导入所有 1900 个新文件(这次要小得多,只有两列)并将它们重新绑定在一起。

或者有更简单的方法可以解决这个问题吗?

更新:其中三个数据集可以在这里下载:https://drive.google.com/drive/folders/17Rq1Vx21VqZhwYKWl9HLWZzxoZh2mxIh?usp=sharing。最重要的数据是 C 列。

或保管箱在这里 https://www.dropbox.com/sh/q6c9w8kryn2by5z/AAD3rPnBgP5CyRy7E5eautJGa?dl=0

处理大型数据^1可以通过几种方式处理。

  1. 如果我不建议一个("适当的")SQL数据库,那将是我的失职。
  2. 一次只加载/处理一小块,只在最后聚合。也就是说,做一些我在下面提到的尝试将你的"当前使用的数据"减少到一天或几天。
  3. 如果可以一次加载所有数据,但无法加载增量部分并在不超出内存的情况下处理它们,请尝试以下技术。

示例数据

(这将在工作目录中创建文件。

x1 <- read.csv(header=TRUE, stringsAsFactors=FALSE, text='
X1,X2,X3
10,07:00,30
11,07:01,31
12,07:02,32
13,07:03,33
15,07:05,35
16,07:06,36
18,07:08,38
19,07:09,39')
write.csv(x1, file="20120204.dat", row.names=FALSE)
x2 <- read.csv(header=TRUE, stringsAsFactors=FALSE, text='
X1,X2,X3
20,07:00,40
22,07:02,42
23,07:03,43
24,07:04,44
25,07:05,45
26,07:06,46')
write.csv(x1, file="20120205.dat", row.names=FALSE)

如果你可以用两个文件来做,你可以用两千个文件来做。在这种情况下,第二列是"time",从您的问题推断推断日期/时间的唯一方法是从文件名和此字段。(注意,在下面的过程中,merge会把连接键放在第一列,所以顺序改变。你当然可以强硬地武装这个。


作品

fnames <- list.files(pattern=".*\.dat", full.names=TRUE)
first <- TRUE
times <- c("00:00", "23:59")
for (fn in fnames) {
thisdate <- gsub(".*(20[0-9]{6}).dat", "\1", fn)
twotimes <- as.POSIXct(paste(thisdate, c("00:00", "23:59")), format = "%Y%m%d %H:%M")
allminutes <- data.frame(X2 = seq(twotimes[1], twotimes[2], by="min"))
dat <- read.csv(fn, stringsAsFactors=FALSE)
dat$X2 <- as.POSIXct(paste(thisdate, dat$X2), format = "%Y%m%d %H:%M")
dat <- merge(dat, allminutes, by="X2", all=TRUE)
write.table(dat, "alldata.csv", append=!first,
col.names=first, row.names=FALSE, sep=",", na="")
first <- FALSE
rm(dat)
gc() # optional, if you really want/need to control memory management *now*
}

逐步完成:

  1. timestwotimesallminutes都用于填写 data.frame,以便始终至少有 1,440 行。我说"至少"是因为这可以确保您在每分钟的"00"秒处出现一次。如果您有其他内容,则需要在每帧中临时创建一个"0 秒"时间列或其他一些技术来启用合并。如果你看allminutes,你会看到它是 1440 行,1 列,仅此而已,但必须每天创建它。
  2. thisdate:我正在从文件名中提取日期组件;模式可能因您而异,但应该有足够的资源根据您的文件名形成它。
  3. as.POSIXct(...):结合thisdate和时间字段(X2),创建一个真实的日期/时间对象(替换时间字符串)。
  4. merge()将有效地为缺失时间添加一行,并为所有其他列添加NA值。
  5. write.table(..., append=!first, col.names=first, ...)将数据追加到 CSV,仅包括第一次通过循环时的标题行。
  6. rm(dat)gc()强制垃圾回收,这通常会从内存中删除dat。这通常是低效的,不是必需的,有时是不需要的,但在您的情况下,这是一种强制保障。如果没有这个,它可能会工作(自动垃圾收集未使用的数据),请随时进行测试和报告。

假设

  1. 您可以一次处理内存中的所有数据(也许使用data.table),只是不能多次加载和修改所有数据。
  2. 顺便说一句:如果你有9GB的数据而不填写缺失的行,那么你只会增加文件大小,因此你可能永远无法将这一个文件加载到你的8GB计算机实例的R。这个答案并非毫无用处:您现在有一个格式更好的数据单文件,然后可以将其导入数据库或类似文件。

数据库?

正如我之前提到的,本地使用的大量数据确实需要增加您的 RAM(很多),或者更优雅地使用数据库。将SQLite(通过RSQLite)用于仅本地,无服务器数据库是可行的,因为它们可以处理如此大的数据。但是,根据您的能力,使用postgresmariadb甚至mssql-server-linux启动单个docker容器并不难。


^1:">大数据"可以根据您在计算机上可以执行多少操作进行分类;如果给定RAM和语言/工具无法加载它,那么它对您来说是"大"的。

最新更新