read_csv 对所有数字列使用 col_double()
read_csv use col_double() instead for all numeric columns
我想使用 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
50k 行数据框,后面的行有小数位值。
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 现在是 NA。
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
您可以做的一件事是读取 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
您可以尝试 hablar
中的 retype
进行数据类型解析,并尝试使用 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
我想使用 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
50k 行数据框,后面的行有小数位值。
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 现在是 NA。
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
您可以做的一件事是读取 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
您可以尝试 hablar
中的 retype
进行数据类型解析,并尝试使用 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