如何将带有 "too many columns" 的大型 .csv 文件转换为 SQL 数据库

How to convert large .csv file with "too many columns" into SQL database

我得到了一个包含 25k 行和 20k 列的大型 .csv 文件(大约 6.5 Gb)。让我们调用第一列 ID1,然后每个附加列都是这些 ID1 在不同条件下的每个值。我们称这些为 ID2。

这是我第一次处理这么大的文件。我想在 R 中处理 .csv 文件并总结每个 ID1 的值、平均值、标准差和变异系数。

我的想法是直接读取文件(使用datatable fread),将其转换为“长”数据(使用dplyr)所以我有三列:ID1, ID2 和值。然后按ID1,ID2分组汇总。但是,我似乎没有足够的内存来读取文件(我假设 R 使用比文件大小更多的内存来存储它)。

我认为先将文件转换成 SQL 数据库然后从那里处理它会更有效。我尝试使用 sqlite3 转换它,但它给我一条错误消息,指出要读取的最大列数是 4096。

我没有使用 SQL 的经验,所以我想知道将 .csv 文件转换为数据库的最佳方法是什么。我想阅读每一列并将它们存储为 table 或类似的东西会起作用。

我搜索过类似的问题,但大多数人只是说拥有这么多列是糟糕的数据库设计。我无法生成结构正确的 .csv 文件。

对处理 .csv 文件的有效方法有什么建议吗?

最佳,

编辑:我能够在 R 中读取初始文件,但我仍然发现一些问题:

1- 由于“太多列”限制,我无法写入 sqlite 数据库。 2-我无法在 R 中旋转它,因为我收到错误消息: Error: cannot allocate vector of size 7.8 Gb 尽管我的内存限制足够高。我有 8.5 Gb 的可用内存并且:

> memory.limit()
[1] 16222

我使用了@danlooo 的代码,但数据不是我想要的格式。可能是我解释的不够清楚它的结构。

这是我希望数据看起来像的示例(ID1 = Sample,ID2 = name,value = value)

> test = input[1:5,1:5]
> 
> test
      Sample DRX007662 DRX007663 DRX007664 DRX014481
1: AT1G01010 12.141565 16.281420 14.482322  35.19884
2: AT1G01020 12.166693 18.054251 12.075236  37.14983
3: AT1G01030  9.396695  9.704697  8.211935   4.36051
4: AT1G01040 25.278412 24.429031 22.484845  17.51553
5: AT1G01050 64.082870 66.022141 62.268711  58.06854
> test2 = pivot_longer(test, -Sample)
> test2
# A tibble: 20 x 3
   Sample    name      value
   <chr>     <chr>     <dbl>
 1 AT1G01010 DRX007662 12.1 
 2 AT1G01010 DRX007663 16.3 
 3 AT1G01010 DRX007664 14.5 
 4 AT1G01010 DRX014481 35.2 
 5 AT1G01020 DRX007662 12.2 
 6 AT1G01020 DRX007663 18.1 
 7 AT1G01020 DRX007664 12.1 
 8 AT1G01020 DRX014481 37.1 
 9 AT1G01030 DRX007662  9.40
10 AT1G01030 DRX007663  9.70
11 AT1G01030 DRX007664  8.21
12 AT1G01030 DRX014481  4.36
13 AT1G01040 DRX007662 25.3 
14 AT1G01040 DRX007663 24.4 
15 AT1G01040 DRX007664 22.5 
16 AT1G01040 DRX014481 17.5 
17 AT1G01050 DRX007662 64.1 
18 AT1G01050 DRX007663 66.0 
19 AT1G01050 DRX007664 62.3 
20 AT1G01050 DRX014481 58.1 

> test3 = test2 %>% group_by(Sample) %>% summarize(mean(value))
> test3
# A tibble: 5 x 2
  Sample `mean(value)`
  <chr>                  <dbl>
1 AT1G01010              19.5 
2 AT1G01020              19.9 
3 AT1G01030               7.92
4 AT1G01040              22.4 
5 AT1G01050              62.6 

我应该如何更改代码以使其看起来像那样?

非常感谢!

在 SQL 中进行透视非常繁琐,通常需要为每一列编写嵌套查询。 SQLite3 确实是如果数据不能存在于 RAM 中的方法。此代码将分块读取文本文件,以长格式转换数据并将其放入 SQL 数据库。然后您可以使用 dplyr 动词访问数据库进行汇总。这使用了另一个示例数据集,因为我不知道 ID1 和 ID2 具有哪些列类型。您可能希望 pivot_longer(-ID2) 有两个名称列。

library(tidyverse)
library(DBI)
library(vroom)

conn <- dbConnect(RSQLite::SQLite(), "my-db.sqlite")
dbCreateTable(conn, "data", tibble(name = character(), value = character()))

file <- "https://github.com/r-lib/vroom/raw/main/inst/extdata/mtcars.csv"
chunk_size <- 10 # read this many lines of the text file at once
n_chunks <- 5

# start with offset 1 to ignore header
for(chunk_offset in seq(1, chunk_size * n_chunks, by = chunk_size)) {
  # everything must be character to allow pivoting numeric and  text columns
  vroom(file, skip = chunk_offset, n_max = chunk_size,
    col_names = FALSE, col_types = cols(.default = col_character())
  ) %>%
    pivot_longer(everything()) %>%
    dbAppendTable(conn, "data", value = .)
}

data <- conn %>% tbl("data") 
data
#> # Source:   table<data> [?? x 2]
#> # Database: sqlite 3.37.0 [my-db.sqlite]
#>    name  value    
#>    <chr> <chr>    
#>  1 X1    Mazda RX4
#>  2 X2    21       
#>  3 X3    6        
#>  4 X4    160      
#>  5 X5    110      
#>  6 X6    3.9      
#>  7 X7    2.62     
#>  8 X8    16.46    
#>  9 X9    0        
#> 10 X10   1        
#> # … with more rows

data %>%
  # summarise only the 3rd column
  filter(name == "X3") %>%
  group_by(value) %>%
  count() %>%
  arrange(-n) %>%
  collect()
#> # A tibble: 3 × 2
#>   value     n
#>   <chr> <int>
#> 1 8        14
#> 2 4        11
#> 3 6         7

reprex package (v2.0.1)

于 2022-04-15 创建