我写了下面的函数,该函数采用非标准的时间格式,例如'730'(7:30)并将其转换为十进制小时数,例如'7.5'。
decimal_time <- function(x) {
x <- as.character(x)
tmp <- nchar(x)
if (tmp < 4 & !is.na(tmp)){
x <- paste0(strrep('0',4-tmp),as.character(x))
}
x <- sub("([[:digit:]]{2,2})$", ":\\1", x)
x <- strsplit(x,':')[[1]]
x <- as.numeric(x)
x[1]+x[2]/60
}
要将其应用于一列,请执行以下操作...
dt_times[, New_Time := lapply(Time, decimal_time)]
但是,我不知道如何将相同的功能应用于共享相同格式的许多列。当然,如果它是矢量化函数(例如“均值”),那么我可以编写...
dt_times[, lapply(.SD, mean), .SDcols = c('col1', 'col2')]
...但是如果我的函数首先使用lapply怎么办?请帮忙!
答案 0 :(得分:2)
如果您的问题是您没有向量化函数,则可以在函数内部使用sapply
decimal_time <- function(y) {
sapply(y,function(x) {
x <- as.character(x)
tmp <- nchar(x)
if (tmp < 4 & !is.na(tmp)){
x <- paste0(strrep('0',4-tmp),as.character(x))
}
x <- sub("([[:digit:]]{2,2})$", ":\\1", x)
x <- strsplit(x,':')[[1]]
x <- as.numeric(x)
x[1]+x[2]/60
})
}
答案 1 :(得分:2)
您不需要任何循环(在函数的外部或内部)。您可以完全向量化您的功能:
decimal_time <- function(x) {
x <- as.character(x)
tmp <- nchar(x)
ii <- tmp < 4 & !is.na(tmp)
x[ii] <- paste0(strrep('0',4-tmp[ii]), x[ii])
x <- sub("([[:digit:]]{2,2})$", ":\\1", x)
x <- strsplit(x,':')
x <- do.call(rbind, x)
mode(x) <- "numeric"
x[,1]+x[,2]/60
}
x <- c("1", "730")
decimal_time(x)
#[1] 0.01666667 7.50000000
使用整数除法比使用文本处理更容易:
decimal_time <- function(x) {
x <- as.integer(x)
if (any(x >= 2400)) warning("input >= 24 h")
x %/% 100 + (x %% 100) / 60
}
x <- c("1", "730")
decimal_time(x)
#[1] 0.01666667 7.50000000
答案 2 :(得分:0)
这是我过去遇到的问题。我的解决方案通常是只运行for
循环:
for(col in c('col1', 'col2'){
dt_times[, (col):= vapply(col, function(x) decimal_time(get(x)), FUN.VALUE = numeric(1))]
}
也许不是最优雅的解决方案,但应该可以完成工作。
答案 3 :(得分:-1)
我建议您使用map_dfr
包中的purrr
函数在data.frame上应用函数,并同时返回data.frame。在幕后,map_ *系列函数的迭代方式与for循环相同,但是以一种更具可读性和整洁的方式进行。
此外,如果您希望将此函数映射到特定的列名,则也可以使用dplyr
和filter
函数的结合使用contains
包,您可以修改这些特定变量。结合这些功能:
library(dplyr)
library(purrr)
df %>%
filter(contains("some_string")) %>%
map_dfr(decimal_time)