【问题标题】:Memory issue when importing large zip tsv file to R将大型 zip tsv 文件导入 R 时出现内存问题
【发布时间】:2020-10-18 07:14:54
【问题描述】:

我正在尝试下载此文件,但无法在任何应用程序中打开它。我正在尝试对其进行一些分析,但系统告诉我内存不足。我尝试增加最大限制,但它仍然说没有足够的内存。任何帮助都会很棒。

library(readr)
file_url <- "http://samhda.s3-us-gov-west-1.amazonaws.com/s3fs-public/field-uploads-protected/studies/NSDUH-2002-2018/NSDUH-2002-2018-datasets/NSDUH-2002-2018-DS0001/NSDUH-2002-2018-DS0001-bundles-with-study-info/NSDUH-2002-2018-DS0001-bndl-data-tsv.zip"
zip <- tempfile(fileext = ".zip")
tsv_file <- download.file(file_url, zip, mode = "wb")
unzip_f <- unzip(tsv_file)
rawdata <- read_tsv(unzip_f, col_names= FALSE)
view(rawdata)
unlink(temp)

错误发生在 rawdata 步骤。我尝试使用 col_names TRUE,但某些列名未标记,并且无法先查看数据,我无法自己命名。这是系统和内存信息。

> sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 
> memory.limit()
[1] 8113
> memory.size()
[1] 8093.52

我收到的错误:

Error: cannot allocate vector of size 7.8 Mb

【问题讨论】:

  • 文件有多大?
  • 刚刚看了看:631Mo
  • 您是否尝试过使用 readLines 逐行读取文件,而不是一步读取?
  • 大小 = 12.3 GB,压缩后为 645,989KB
  • 我没有使用readlines,是否可以分段阅读,使用该功能后合并?

标签: r csv memory


【解决方案1】:

readr::read_tsv() 中的 skip = n_max = 参数可用于控制从制表符分隔的文件中读取多少数据到数据框中。

要读取前 10 个观察结果以便查看列名,可以运行:

library(readr)
file_url <- "http://samhda.s3-us-gov-west-1.amazonaws.com/s3fs-public/field-uploads-protected/studies/NSDUH-2002-2018/NSDUH-2002-2018-datasets/NSDUH-2002-2018-DS0001/NSDUH-2002-2018-DS0001-bundles-with-study-info/NSDUH-2002-2018-DS0001-bndl-data-tsv.zip"
zip <- tempfile(fileext = ".zip")
tsv_file <- download.file(file_url, zip, mode = "wb")
unzip_f <- unzip(zip,exdir="./data")
df <- read_tsv(unzip_f, col_names= TRUE, n_max = 10)

此时我们可以使用colnames() 函数检索列名。

col_names <- colnames(df)

我们现在将验证 100,000 行数据消耗的 RAM 量,并计算 100,000 次观察的加载时间。

system.time(df_100000 <- read_tsv("./data/NSDUH_2002_2018_tab.tsv", 
                      col_names = TRUE, n_max = 100000))
format(object.size(df_100000),units = "auto")


   user  system elapsed 
 55.276   4.136  60.559

> format(object.size(df_100000),units = "auto")
[1] "2.7 Gb"

此时,我们可以在具有 8Gb RAM 的机器上一次安全地从原始数据文件中读取大约 200,000 个观察值。

接下来,我们将计算出原始数据文件中有多少行数据。我们可以使用read_tsv()col_types = 参数并将除第一列之外的所有列设置为-,这告诉read_tsv() 不要读取列。我们还用一列和所有观察值计算数据框的大小。

theTypes <- c("n",rep("_",3661))
system.time(df_obs <- read_tsv("./data/NSDUH_2002_2018_tab.tsv",col_types = theTypes, 
                                  col_names = TRUE))
nrow(df_obs)
format(object.size(df_obs),units = "auto")

   user  system elapsed 
175.208  27.694 210.948 
> nrow(df_obs)
[1] 949285
> format(object.size(df_obs),units = "auto")
[1] "39.8 Mb"

在配备英特尔 i7-4870HQ 处理器、频率为 2.5Ghz 的 MacBook Pro 15 上,从原始数据文件中读取单列数据的所有观察结果花了将近 4 分钟。

nrow() 的结果告诉我们原始数据文件中有 949,285 行。如果我们将文件分成 200,000 个观察块,我们可以读取它们并将它们保存为带有saveRDS() 的 RDS 文件以供后续处理。

迭代读取文件并写入RDS

for(i in 1:5){
     df <- read_tsv("./data/NSDUH_2002_2018_tab.tsv",
                                         skip = (i - 1) * 200000,
                                         n_max = 200000,
                                         col_names = c_names)
     saveRDS(df,paste0("./data/usnuh_",i,".RDS"))
} 

此时,usnuh_1.RDSusnuh_5.RDS 可以单独读入 R 并进行分析。

注意:for() 循环会覆盖上一次迭代中创建的数据帧,因此我们可以读取和写入所有文件而不会耗尽 RAM。重要的是要记住,一个人只能加载 1 个包含 200,000 个观察值的文件,并将其用于具有 8Gb RAM 的机器上的数据分析。为了使用数据的不同部分,需要使用rm() 函数删除当前数据,然后再将另外 200,000 个观测 RDS 文件加载到 RAM 中。

读取最后 200,000 行

根据 cmets,这是可用于读取文件最后 200K 行的代码。

# read last 200K rows. first read one row to obtain column names
library(readr) 
df <- read_tsv("./data/NSDUH_2002_2018_tab.tsv", 
               col_names = TRUE, n_max = 1)
c_names <- colnames(df)
# next, configure skip = relative to end of file and read 
df <- read_tsv("./data/NSDUH_2002_2018_tab.tsv",
               skip = (949258 - 200000),
               n_max = 200000,
               col_names = c_names)

当我们在环境查看器中查看数据框时,我们可以看到它包含 200,000 个观察值。

【讨论】:

  • 谢谢,这也给了我一些关于如何在未来解决类似问题的良好背景。我真的很感激。
  • @Tesla_Republic - 不客气。如果您觉得答案有帮助,请接受并点赞。
  • 这在很大程度上确实有帮助,但我仍然无法处理信息并创建 5 个单独的文件。我至少能够获得一个包含 200k 行的文件。我目前正在尝试弄清楚如何获取最后 200k 行而不是前 200k 行。老实说,我不确定问题是什么,如果我运行最后一点代码(编写 RDS),它会显示“错误:无法分配大小为 30kb 的向量”,然后如果我在控制台中输入任何内容,它会给出相同的错误甚至不会自动填充或处理任何东西。我必须重新启动 RStudio。我也尝试释放内存空间。
  • 这确实有很大帮助,我认为我不需要整个数据集来达到我的目的。我会投票,但我是新手,还不能投票。
  • @Tesla_Republic - 我更新了我的答案以提供一个只读取最后 200,000 行的解决方案。此外,重要的是要注意,在具有 8Gb RAM 的机器上,一次只能在内存中拥有一个 200,000 行和所有列的数据帧。您需要剩余的 RAM 才能在文件上运行其他 R 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-08
  • 2019-03-25
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多