假设我有一个字符串
age<-c("7y2m4d","5m4d","7y5m6d")
我想将其转换为像
这样的数字向量 c(7.34, 0.43, 7.43)
如何制作R代码?
我们可以假设一年有365天,一个月有365/12天。
答案 0 :(得分:3)
lubridate::duration
会将您的字符串转换为(近似)秒。
library(lubridate)
library(magrittr)
age <- c("7y2m4d", "5m4d", "7y5m6d")
age_sec <- age %>%
duration() %>%
as.numeric()
age_sec
[1] 226508400 13494600 234570600
然后您可以将年份近似为365 * 24 * 60 * 60
秒:
age_sec / (365 * 24 * 60 * 60)
[1] 7.182534 0.427911 7.438185
答案 1 :(得分:2)
基础R的另一种解决方案:
age<-c("7y2m4d","5m4d","7y5m6d")
age <- gsub('y', ' + ', age)
age <- gsub('m', ' / 12 + ', age)
age <- gsub('d', ' / 365', age)
sapply(age, function(x) eval(parse(text = x)))
#7 + 2 / 12 + 4 / 365 5 / 12 + 4 / 365 7 + 5 / 12 + 6 / 365
# 7.1776256 0.4276256 7.4331050
我们的想法是创建公式,然后为矢量的每个元素评估它。
答案 2 :(得分:2)
这些解决方案:
age
的第一个元素除外,问题似乎是错误地计算了答案)基于简单性(1a)比较下面的解决方案是最简单的并自动处理所有边缘情况,没有特定的代码,表明它是最自然的;但是,它确实使用了一个包。 (1)只是略微复杂,不使用包装,(2)非常短,也不使用任何包装,但不像(1)或(1a)那么简单。
1)此处getNum
提取并返回与代码相关联的x
的数字(代码为“y”,“m”或“d”)或如果x
中没有代码,则返回0.然后我们将年,月/ 12和日/ 365加起来。
getNum <- function(code, x) {
pat <- sprintf(".*?(\\d+)%s.*", code)
as.numeric(ifelse(grepl(code, x), sub(pat, "\\1", x), 0))
}
getNum("y", age) + getNum("m", age) / 12 + getNum("d", age) / 365
## [1] 7.1776256 0.4276256 7.4331050
1a)这类似于(1),除了我们在gsubfn中使用strapply来简化getNum
。实际上,getNum
缩减为单个strapply
调用,并且它使用的正则表达式也更简单。
library(gsubfn)
getNum <- function(code, x) {
strapply(x, paste0("(\\d+)", code), as.numeric, empty = 0, simplify = TRUE)
}
getNum("y", age) + getNum("m", age) / 12 + getNum("d", age) / 365
## [1] 7.1776256 0.4276256 7.4331050
2)此替代方法将每个字符串转换为dcf格式,并使用read.dcf创建y,m和d数字的矩阵。
详细地说,第一行代码是处理某些边缘情况,这些边缘情况实际上不存在于问题中的样本数据中。如果d缺失,我们首先将0d附加到age
(来自问题),以便我们可以处理y,m和d都缺失的情况。我们还预先添加一个虚拟条目,以确保y,m和d出现在至少一个条目中。如果我们知道y,m和d存在于至少一个组件中并且没有组件中y,m和d都同时缺失,则可以省略第一行代码。
第二行代码将每个输入字符串转换为dcf格式并将其读入矩阵,确保列按已知顺序删除上面添加的虚拟条目。
最后,我们将N替换为0并使用矩阵乘法来累计年,月/ 12和日/ 365.
a0 <- c("0y0m0d", paste0(age, ifelse(grepl("d", age), "", "0d")))
m <- read.dcf(textConnection(gsub("(\\d+)(\\D)", "\\2: \\1\n", a0)))[-1, c("y", "m", "d")]
m[is.na(m)] <- 0
c(array(as.numeric(m), dim(m)) %*% c(1, 1/12, 1/365))
## [1] 7.1776256 0.4276256 7.4331050
更新:重新排列并添加(1)和(1a)。