read_csv использует col_double () вместо всех числовых столбцов - PullRequest
0 голосов
/ 14 февраля 2019

Я бы хотел использовать readr::read_csv вместо read.csv из-за его скорости и автоматического преобразования дат.Однако есть одна проблема с тем, как он обрабатывает числа, которые в основном являются целыми числами, с добавлением нескольких чисел с плавающей точкой.

Есть ли способ заставить его использовать col_double для всех чисел, при этом все еще используя col_guessдля всех остальных столбцов?

Мне кажется, что угадывание col_integer - неоптимальный выбор разработчика пакета.Кажется, это часто случается с реальными данными для меня.Например, когда ненулевые значения редки.

Я открываю файлы, не зная заранее типов столбцов или имен.

Вот иллюстрация проблемы:

df<-data.frame(
    i=as.integer(c(1:5)),
    d=seq.Date(as.Date('2019-01-01'), length.out = 5, by=1),
    mix = c('1','2','3.1','4','5'),
    stringsAsFactors = F
)%>%as.tbl
write_csv(df, '~/temp.csv')

это хорошо! Значение 3.1 читается правильно.

read_csv('~/temp.csv')
# A tibble: 5 x 3
      i d            mix
  <int> <date>     <dbl>
1     1 2019-01-01   1  
2     2 2019-01-02   2  
3     3 2019-01-03   3.1
4     4 2019-01-04   4  
5     5 2019-01-05   5 

Фрейм данных из 50 тыс. Строк с десятичным значением в следующих строках.

df_large <-data.frame(
    i = as.integer(c(1:(1e4))),
    d=seq.Date(as.Date('2019-01-01'), length.out = 1e4, by=1),
    mix = as.character(c(1:(1e4))),
    stringsAsFactors = F
)%>%as.tbl
bind_rows(df_large, df)%>%tail(7)
# A tibble: 7 x 3
      i d          mix  
  <int> <date>     <chr>
1  9999 2046-05-17 9999 
2 10000 2046-05-18 10000
3     1 2019-01-01 1    
4     2 2019-01-02 2    
5     3 2019-01-03 3.1  
6     4 2019-01-04 4    
7     5 2019-01-05 5   

это ПЛОХО! 3.1 теперь НС.

bind_rows(df_large, df)%>%write_csv(., '~/temp.csv')
read_csv('~/temp.csv')%>%tail(7)
# A tibble: 7 x 3
      i d            mix
  <int> <date>     <int>
1  9999 2046-05-17  9999
2 10000 2046-05-18 10000
3     1 2019-01-01     1
4     2 2019-01-02     2
5     3 2019-01-03    NA
6     4 2019-01-04     4
7     5 2019-01-05     5

это работает, но как мне установить guess_max заранее.

read_csv('~/temp.csv', guess_max = 1e5)%>%as.tbl%>%tail(7)
# A tibble: 7 x 3
      i d              mix
  <int> <date>       <dbl>
1  9999 2046-05-17  9999  
2 10000 2046-05-18 10000  
3     1 2019-01-01     1  
4     2 2019-01-02     2  
5     3 2019-01-03     3.1
6     4 2019-01-04     4  
7     5 2019-01-05     5  

По мере роста guess_max увеличивается и время выполнения.Похоже, передискретизация.

system.time(read_csv('~/temp.csv', guess_max = 1e5)%>%as.tbl%>%tail(7))
   user  system elapsed 
  0.020   0.001   0.022 
system.time(read_csv('~/temp.csv', guess_max = 1e7)%>%as.tbl%>%tail(7))
   user  system elapsed 
  0.321   0.010   0.332 
system.time(read_csv('~/temp.csv', guess_max = 1e9)%>%as.tbl%>%tail(7))
   user  system elapsed 
 34.138   5.848  39.821 

Это работает, но может быть> 30 столбцов, и я не набираю заранее.

read_csv('~/temp.csv', col_types = 'dDd')%>%as.tbl%>%tail(7)

data.table::fread быстрый, хорошо обрабатывает числа, но не конвертирует даты.

data.table::fread('~/temp.csv')%>%as.tbl%>%tail(7)
# A tibble: 7 x 3
      i d              mix
  <int> <chr>        <dbl>
1  9999 2046-05-17  9999  
2 10000 2046-05-18 10000  
3     1 2019-01-01     1  
4     2 2019-01-02     2  
5     3 2019-01-03     3.1
6     4 2019-01-04     4  
7     5 2019-01-05     5 

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Вы можете попробовать retype из hablar для разбора типа данных и fread для быстрого чтения.

library(hablar)
data.table::fread('~/temp.csv') %>%
  retype() %>% 
  tail(7)

, что дает мне:

# A tibble: 7 x 3
      i d              mix
  <int> <date>       <dbl>
1  9999 2046-05-17  9999  
2 10000 2046-05-18 10000  
3     1 2019-01-01     1  
4     2 2019-01-02     2  
5     3 2019-01-03     3.1
6     4 2019-01-04     4  
7     5 2019-01-05     5  
0 голосов
/ 14 февраля 2019

Одна вещь, которую вы могли бы сделать, это прочитать в первой строке CSV (или в первом n числах строк), выяснить, какие столбцы анализируются как целые числа, и передать их в качестве аргументов cols:

library(readr)

read_csv_dbl <- function(file, ...){
  types <- sapply(suppressMessages(read_csv(file, n_max = 1)), class) 
  int_cols <- names(types[types == "integer"])
  args <- structure(replicate(length(int_cols), col_double()), names = int_cols)
  read_csv(file, col_types = do.call(cols, args), ...)
}

read_csv_dbl("~/temp.csv") %>% tail(7)
# A tibble: 7 x 3
#      i d              mix
#  <dbl> <date>       <dbl>
#1  9999 2046-05-17  9999  
#2 10000 2046-05-18 10000  
#3     1 2019-01-01     1  
#4     2 2019-01-02     2  
#5     3 2019-01-03     3.1
#6     4 2019-01-04     4  
#7     5 2019-01-05     5  

Этот метод также намного быстрее, чем изменение guess_max:

system.time(read_csv_dbl("~/temp.csv"))
#   user  system elapsed 
#   0.02    0.00    0.01 
...