R импортирует полуструктурированные данные CSV - PullRequest
2 голосов
/ 25 октября 2019

Я привык загружать прямой CSV с заголовками столбцов и одной таблицей в R, у меня есть большой CSV-файл, имеющий следующую структуру:

+-----------+---------+--------+---------+--------+---------+
| file_name |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| table1    |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| Var1      | Var2    | Var3   | Var4    | Var5   | Var6    |
+-----------+---------+--------+---------+--------+---------+
| 198824    | 198824  | 198824 | 198824  | 198824 | 198824  |
+-----------+---------+--------+---------+--------+---------+
| 123       | 1234    | 1242   | 124     | 1241   | 1232    |
+-----------+---------+--------+---------+--------+---------+
|           |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
|           |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| file_name |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| table2    |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| Var1      | Var2    | Var3   | Var4    | Var5   | Var6    |
+-----------+---------+--------+---------+--------+---------+
| x         | x       | x      | x       | x      | x       |
+-----------+---------+--------+---------+--------+---------+
| y         | y       | y      | y       | y      | y       |
+-----------+---------+--------+---------+--------+---------+
| z         | z       | z      | z       | z      | z       |
+-----------+---------+--------+---------+--------+---------+
|           |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
|           |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| file_name |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| table3    |         |        |         |        |         |
+-----------+---------+--------+---------+--------+---------+
| Var1      | Var2    | Var3   | Var4    | Var5   | Var6    |
+-----------+---------+--------+---------+--------+---------+
| 532523    | 25235   | 532523 | 25235   | 532523 | 25235   |
+-----------+---------+--------+---------+--------+---------+
| 25332     | 5325235 | 25332  | 5325235 | 25332  | 5325235 |
+-----------+---------+--------+---------+--------+---------+

Данные не полностью неструктурированы вчто следует этому шаблону:
В первой строке есть только имя файла: file_name
Во 2-й строке есть таблица: table1, table2, table3 и т. д.
И сама таблица, то есть 6 столбцовот var1 до var6 с данными под ним.
Тогда есть 2 пустых строки, и следующий набор будет начинаться с повторяющегося имени_файла, а затем следующего номера таблицы и таблицы внутри него

Все таблицыв CSV следует этому шаблону, но у меня возникают проблемы даже при загрузке этого в R, я получаю следующее при прямой загрузке с использованием read.csv ():

Error in read.table(file = file, header = header, sep = sep, quote = quote,  : 
  more columns than column names

Возможно ли загрузить в один кадр данныхиспользуя R, а также номер таблицы становится столбцом, а var1-var6 + номер таблицы в качестве заголовков столбцов?

т.е.

+--------+---------+--------+---------+--------+---------+--------------+
|  Var1  |  Var2   |  Var3  |  Var4   |  Var5  |  Var6   | table_number |
+--------+---------+--------+---------+--------+---------+--------------+
| 198824 | 198824  | 198824 | 198824  | 198824 | 198824  | table1       |
| 123    | 1234    | 1242   | 124     | 1241   | 1232    | table1       |
| x      | x       | x      | x       | x      | x       | table2       |
| y      | y       | y      | y       | y      | y       | table2       |
| z      | z       | z      | z       | z      | z       | table2       |
| 532523 | 25235   | 532523 | 25235   | 532523 | 25235   | table3       |
| 25332  | 5325235 | 25332  | 5325235 | 25332  | 5325235 | table3       |
+--------+---------+--------+---------+--------+---------+--------------+

Обратите внимание, что tКоличество строк в каждой таблице (table1, table2 и т. д.) имеет разное количество строк.

В CSV-файле всего около 200 таблиц, и он превышает предел Excel (я думаю, около 9MM строк)

Используя код Брайана, вот первые несколько строк:

> lines_all
 [1] "name,,,,,"                      "table1,,,,,"                    "Var1,Var2,Var3,Var4,Var5,Var6"  "321,54312,321,54654,3564,54321"
 [5] "45,54,4564,54,87,456"           ",,,,,"                          ",,,,,"                          "name,,,,,"                     
 [9] "table2,,,,,"                    "Var1,Var2,Var3,Var4,Var5,Var6"  "ssvf,afs,fasf,afsaf,zxvz,zvx"   "saf,zvx,zz,z,zxvz,zxvzxv"      
[13] "zxvsaf,wr,wrw,afsaf,asf,af"     ",,,,,"                          ",,,,,"                          "name,,,,,"                     
[17] "table3,,,,,"                    "Var1,Var2,Var3,Var4,Var5,Var6"  "1,2,3,4,5,6"                    "7,8,9,10,11,12"                
[21] "13,14,15,16,17,18"              "19,20,21,22,23,24"    

1 Ответ

2 голосов
/ 25 октября 2019

Использование этого файла:

file_name
table1
Var1, Var2, Var3, Var4, Var5, Var6
198824, 198824, 198824, 198824, 198824, 198824
123, 1234, 1242, 124, 1241, 1232





file_name
table2
Var1, Var2, Var3, Var4, Var5, Var6
x, x, x, x, x, x
y, y, y, y, y, y
z, z, z, z, z, z





file_name
table3
Var1, Var2, Var3, Var4, Var5, Var6
532523, 25235, 532523, 25235, 532523, 25235
25332, 5325235, 25332, 5325235, 25332, 5325235

Сначала прочитайте все в виде символьных векторов.

library(readr)
library(stringr)
library(purrr)
library(dplyr)
# Could be done in base R, but {readr} will be faster on a large file

# read in all lines
lines_all <- read_lines("nested_tables.txt")
lines_all
#>  [1] "file_name"                                     
#>  [2] "table1"                                        
#>  [3] "Var1, Var2, Var3, Var4, Var5, Var6"            
#>  [4] "198824, 198824, 198824, 198824, 198824, 198824"
#>  [5] "123, 1234, 1242, 124, 1241, 1232"              
#>  [6] ""                                              
#>  [7] ""                                              
#>  [8] ""                                              
#>  [9] ""                                              
#> [10] ""                                              
#> [11] "file_name"                                     
#> [12] "table2"                                        
#> [13] "Var1, Var2, Var3, Var4, Var5, Var6"            
#> [14] "x, x, x, x, x, x"                              
#> [15] "y, y, y, y, y, y"                              
#> [16] "z, z, z, z, z, z"                              
#> [17] ""                                              
#> [18] ""                                              
#> [19] ""                                              
#> [20] ""                                              
#> [21] ""                                              
#> [22] "file_name"                                     
#> [23] "table3"                                        
#> [24] "Var1, Var2, Var3, Var4, Var5, Var6"            
#> [25] "532523, 25235, 532523, 25235, 532523, 25235"   
#> [26] "25332, 5325235, 25332, 5325235, 25332, 5325235"

Найдите в каждой строке совпадение с регулярным выражением для имени таблицы. Вам может потребоваться настроить соответствующий шаблон: "table[0-9]" для соответствия вашим реальным именам.

# find where there's a string like "table1"
table_id_indices <- str_detect(lines_all, "table[0-9]")
table_id_indices
#>  [1] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [12]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [23]  TRUE FALSE FALSE FALSE

# extract the table names in order
table_id_names <- lines_all[table_id_indices]
table_id_names
#> [1] "table1" "table2" "table3"

Теперь, когда у вас есть вектор строк и индексы, с которых начинается каждый идентификатор, вы можете разделитьvector up.

# split the vector of lines into a list of vectors
# `cumsum` is a handy trick to "fill" from one TRUE value to the next
lines_chunked <- split(lines_all, cumsum(table_id_indices))
lines_chunked
#> $`0`
#> [1] "file_name"
#> 
#> $`1`
#>  [1] "table1"                                        
#>  [2] "Var1, Var2, Var3, Var4, Var5, Var6"            
#>  [3] "198824, 198824, 198824, 198824, 198824, 198824"
#>  [4] "123, 1234, 1242, 124, 1241, 1232"              
#>  [5] ""                                              
#>  [6] ""                                              
#>  [7] ""                                              
#>  [8] ""                                              
#>  [9] ""                                              
#> [10] "file_name"                                     
#> 
#> $`2`
#>  [1] "table2"                            
#>  [2] "Var1, Var2, Var3, Var4, Var5, Var6"
#>  [3] "x, x, x, x, x, x"                  
#>  [4] "y, y, y, y, y, y"                  
#>  [5] "z, z, z, z, z, z"                  
#>  [6] ""                                  
#>  [7] ""                                  
#>  [8] ""                                  
#>  [9] ""                                  
#> [10] ""                                  
#> [11] "file_name"                         
#> 
#> $`3`
#> [1] "table3"                                        
#> [2] "Var1, Var2, Var3, Var4, Var5, Var6"            
#> [3] "532523, 25235, 532523, 25235, 532523, 25235"   
#> [4] "25332, 5325235, 25332, 5325235, 25332, 5325235"

Чтобы сделать строки читаемыми, удалите все строки, не относящиеся к таблице.

# remove lines that don't have commas, since they're not tables
lines_chunked_cleaned <- map(lines_chunked, ~str_subset(.x, ",")) %>% compact()
lines_chunked_cleaned
#> $`1`
#> [1] "Var1, Var2, Var3, Var4, Var5, Var6"            
#> [2] "198824, 198824, 198824, 198824, 198824, 198824"
#> [3] "123, 1234, 1242, 124, 1241, 1232"              
#> 
#> $`2`
#> [1] "Var1, Var2, Var3, Var4, Var5, Var6"
#> [2] "x, x, x, x, x, x"                  
#> [3] "y, y, y, y, y, y"                  
#> [4] "z, z, z, z, z, z"                  
#> 
#> $`3`
#> [1] "Var1, Var2, Var3, Var4, Var5, Var6"            
#> [2] "532523, 25235, 532523, 25235, 532523, 25235"   
#> [3] "25332, 5325235, 25332, 5325235, 25332, 5325235"

Теперь каждый элемент списка можно прочитать как CSV.

# read in each vector of lines as a CSV
# forcing a default col_type prevents binding errors later
lines_chunked_csvs <- map(lines_chunked_cleaned, ~read_csv(.x, col_types = cols(.default = "c")))
lines_chunked_csvs
#> $`1`
#> # A tibble: 2 x 6
#>   Var1   Var2   Var3   Var4   Var5   Var6  
#>   <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
#> 1 198824 198824 198824 198824 198824 198824
#> 2 123    1234   1242   124    1241   1232  
#> 
#> $`2`
#> # A tibble: 3 x 6
#>   Var1  Var2  Var3  Var4  Var5  Var6 
#>   <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 x     x     x     x     x     x    
#> 2 y     y     y     y     y     y    
#> 3 z     z     z     z     z     z    
#> 
#> $`3`
#> # A tibble: 2 x 6
#>   Var1   Var2    Var3   Var4    Var5   Var6   
#>   <chr>  <chr>   <chr>  <chr>   <chr>  <chr>  
#> 1 532523 25235   532523 25235   532523 25235  
#> 2 25332  5325235 25332  5325235 25332  5325235

Используйте имена из ранее, чтобы идентифицировать каждый фрейм данных и связать их.

# name the list of tables, bind everything together
bind_rows(set_names(lines_chunked_csvs, table_id_names), .id = "table")
#> # A tibble: 7 x 7
#>   table  Var1   Var2    Var3   Var4    Var5   Var6   
#>   <chr>  <chr>  <chr>   <chr>  <chr>   <chr>  <chr>  
#> 1 table1 198824 198824  198824 198824  198824 198824 
#> 2 table1 123    1234    1242   124     1241   1232   
#> 3 table2 x      x       x      x       x      x      
#> 4 table2 y      y       y      y       y      y      
#> 5 table2 z      z       z      z       z      z      
#> 6 table3 532523 25235   532523 25235   532523 25235  
#> 7 table3 25332  5325235 25332  5325235 25332  5325235
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...