通过type_convert或spec函数获取环境数据集列类型规范的方法
问题场景
现有全列均为字符串类型的.RDS格式数据文件,需要将各列转换为适配的数据类型,同时留存列类型规范,方便后续调整部分列的类型配置。
读取CSV文件时,通过readr::spec()函数可以直接获取每一列的完整类型规范,参考效果如下:
library(tidyverse) library(lubridate) df <- midwest %>% slice(1:10) %>% mutate(date1 = seq(ymd('2021-06-07'), ymd('2021-06-16'), by = '1 day'), date2 = seq(as.Date('2021/6/7'), by = 'month', length.out = 10), empty1 = NA, empty2 = NA, empty3 = NA, empty4 = NA, empty11 = NA, empty21 = NA, empty31 = NA, empty41 = NA, empty12 = NA, empty22 = NA, empty32 = NA, empty42 = NA, empty13 = NA, empty23 = NA, empty33 = NA, empty43 = NA, dt = date1 + seconds(row_number()-1), time = format(dt, format = "%H:%M:%S")) %>% mutate(across(everything(), as.character)) # 临时存储CSV文件 f <- file.path(tempdir(), "midwest10.csv") write.csv(df, f, row.names = FALSE) df3 <- read_csv(f, show_col_types = FALSE) spec(df3) # 可以正常返回完整列规范 #> cols( #> PID = col_double(), #> county = col_character(), #> state = col_character(), #> area = col_double(), #> poptotal = col_double(), #> popdensity = col_double(), #> popwhite = col_double(), #> popblack = col_double(), #> popamerindian = col_double(), #> popasian = col_double(), #> popother = col_double(), #> percwhite = col_double(), #> percblack = col_double(), #> percamerindan = col_double(), #> percasian = col_double(), #> percother = col_double(), #> popadults = col_double(), #> perchsd = col_double(), #> percollege = col_double(), #> percprof = col_double(), #> poppovertyknown = col_double(), #> percpovertyknown = col_double(), #> percbelowpoverty = col_double(), #> percchildbelowpovert = col_double(), #> percadultpoverty = col_double(), #> percelderlypoverty = col_double(), #> inmetro = col_double(), #> category = col_character(), #> date1 = col_date(format = ""), #> date2 = col_date(format = ""), #> empty1 = col_logical(), #> empty2 = col_logical(), #> empty3 = col_logical(), #> empty4 = col_logical(), #> empty11 = col_logical(), #> empty21 = col_logical(), #> empty31 = col_logical(), #> empty41 = col_logical(), #> empty12 = col_logical(), #> empty22 = col_logical(), #> empty32 = col_logical(), #> empty42 = col_logical(), #> empty13 = col_logical(), #> empty23 = col_logical(), #> empty33 = col_logical(), #> empty43 = col_logical(), #> dt = col_datetime(format = ""), #> time = col_time(format = "") #> )
但如果数据是RDS格式(或已经加载到R环境中的数据集),直接调用spec()拿不到有效结果。不希望通过转存为CSV再用read_csv()读取的绕路方案,测试代码如下:
f <- file.path(tempdir(), "midwest10.RDS") saveRDS(df, f) df2 <- readRDS(f) df2 <- type_convert(df2) #> -- Column specification -------------------------------------------------------- #> cols( #> .default = col_double(), #> county = col_character(), #> state = col_character(), #> category = col_character(), #> # ... with 20 more columns #> ) #> i Use `spec()` for the full column specifications. spec(df2) # 期望返回完整列规范,实际返回NULL #> NULL
解决方法
type_convert()默认不会把猜测到的完整列规范附加到输出的数据框上,只会在控制台打印截断的摘要,所以后续调用spec()会返回NULL。只需要在调用type_convert()时加上spec = TRUE参数,函数就会把完整的列规范作为属性附加到转换后的数据框,之后直接调用spec()就能拿到完整结果,不需要转存CSV。
参考代码:
f <- file.path(tempdir(), "midwest10.RDS") saveRDS(df, f) df2 <- readRDS(f) # 关键参数:spec = TRUE df2 <- type_convert(df2, spec = TRUE) # 此时调用spec()即可返回完整列规范 spec(df2)
补充说明
- 拿到
cols格式的列规范对象后,可以直接修改对应列的类型定义,后续处理同结构数据时,直接把这个规范对象传给type_convert()的col_types参数即可,不需要重复做类型猜测。 - 全空值列默认会被识别为
col_logical()类型,如果需要调整为其他类型,直接在规范对象中修改对应列的配置即可。 - 如果已经完成
type_convert()转换、没加spec = TRUE参数,不需要重新跑转换流程,执行spec(df2) <- guess_spec(df2)即可补全列规范属性,只是效率比转换时直接携带参数稍低。
内容的提问来源于stack exchange,提问作者HBat
相关产品推荐
相关产品推荐

