关于R中读取日期数据出错的解决办法
发布网友
发布时间:2022-11-25 09:49
我来回答
共1个回答
热心网友
时间:2023-10-09 07:44
R从excel文件中读取日期数据经常出现错误(如, 日期数据读入之后变成整数,或者整数与标准的日期格式共存等),这种情况大多是数据读入R之前数据类型保存有误(有些日期类型存储成了整数类型,或者整数与标准的日期类型数据共存) ,数据读入R之后,无法使用R中常用的日期处理函数(如lubridate的ymd()等函数)将数据转换为标准的日期函数(yyyy-mm-dd)。
遇到这种情况,我们可以通过colClasses或col_types来指定读入的数据列类型为日期类型('date'), 此时如果数据不是标准的日期类型(如yyyy-mm-dd)数据读入依然会出错。此时,可以指定数据列类型为文本类型('character'或'text'),此时数据读入不会出错,但是读入后需要对数据进行转换(整数形式的日期数据,如'41250', 需要转换为标准的日期类型数据:yyyy-mm-dd)。
日期与整数之间是可以转换的。 通常,日期与 1899年12月31日(或1970年1月1日-Unix时间)相差的天数即为相应日期对应的整数, 碰到日期中有'42110', '12334', '2018-12-12'形式存在的数据时, 需要判断日期数据是整数形式还是标准的日期格式。
下面写了一个简单的函数,来处理日期数据中既有整数形式的日期数据(如'41120'),又有标准日期类型的数据的情况:
str2num <- function(data){
return (as.numeric(as.character(data)))
}
change_date <- function(date_str){
##转为标准的年月日日期
date_str <- str_replace_all(date_str, "‘|’|“|”|“|”", '')
date_str <- str_replace_all(date_str, '年|月', '-')
date_str <- str_replace_all(date_str, '日', ' ')
date_str <- str_replace_all(date_str, '^\\s+|\\s+$', '')
##如果只有一个小数点,保留整数就行了
if (length(str_extract_all(date_str, '\\.')[[1]]) == 1 &&
!is.na(as.numeric(as.character(date_str)))){
date_str <- str_replace(date_str, '\\.\\d+$', '')
}
##空白字符后面的内容删除
date_str <- str_split(date_str, '\\s+', simplify = T)[, 1]
##标准的日期1
##yyyy-mm-dd, yyyy.mm.dd, yyyy/mm/dd, yyyy\mm\dd
tmp_bool1 <- str_detect(date_str, paste('\\d{4}[-./\\\\]\\d{1,2}[-./\\\\]\\d{1,2}',
'\\d{8}', sep = '|'))
##标准日期2
##mm-dd-yyy, mm.dd.yyyy, mm/dd/yyyy, mm\dd\yyyy
tmp_bool2 <- str_detect(date_str, '\\d{1,2}[-./\\\\]\\d{1,2}[-./\\\\]\\d{4}')
indexs <- 1:length(date_str)
##标准日期1,下标,年月日
norm_index1 <- which(tmp_bool1 == T)
##标准日期2下标, 月日年
norm_index2 <- which(tmp_bool2 == T)
##非标准日期,转换成了数字格式的日期
int_index <- indexs[!indexs %in% c(norm_index1, norm_index2)]
tmp_int <- date_str[int_index]
tmp_int <- round(str2num(tmp_int), 0)
date_int <- as.character(ymd('1900-1-1') + ddays(tmp_int - 2))
date_str[c(norm_index1, norm_index2)] <- str_replace_all(date_str[c(norm_index1, norm_index2)], '[/.\\\\]', '-')
##norm index1
date_str[norm_index1] <- as.character(ymd(date_str[norm_index1]))
##norm index2
date_str[norm_index2] <- as.character(mdy(date_str[norm_index2]))
##int index
date_str[int_index] <- date_int
return(date_str)
}
调用上面的函数后,数据都转化为了'yyyy-mm-dd'形式的字符串数据
需要调用lubridate包中的ymd()函数进一步将字符串数据转换为日期数据。
ps:不同来源的日期数据转换要注意开始计算天数的日期是1899-12-31还是1970-1-1。