将因子变量 minute:second 转换为 R 中的数值变量 minute.seconds

Convert factor variable minute:second to numerical variable minute.seconds in R

我正在努力处理给定的数据框:

 game.time.total game.time.first.half game.time.second.half
1           95:09                46:04                 49:05
2           95:09                46:04                 49:05
3           95:31                46:07                 49:23
4           95:31                46:07                 49:23
5           95:39                46:08                 49:31

目前,这些列当前是因子变量(参见 str 输出)

'data.frame':   5 obs. of  3 variables:
 $ game.time.total      : Factor w/ 29 levels "100:22","100:53",..: 7 7 10 10 12
 $ game.time.first.half : Factor w/ 27 levels "45:18","46:00",..: 3 3 5 5 6
 $ game.time.second.half: Factor w/ 29 levels "48:01","48:03",..: 12 12 15 15 17

但是我希望能够使用 colmeans() 对每一列进行平均。根据我的理解,我需要将列转换为数字并表示为 minutes.seconds,如下所示:

game.time.total game.time.first.half game.time.second.half
1           95.09                46.04                 49.05
2           95.09                46.04                 49.05
3           95.31                46.07                 49.23
4           95.31                46.07                 49.23
5           95.39                46.08                 49.31

我知道我可以直接输入它们,但是还有更多类似格式的列和行...有没有一种简单的方法可以做到这一点?还是需要重新调整原文件(.csv)的格式?

编辑:感谢您的回答。我在最初的问题中的错误是我没有提供我的实际 DF。我现在添加了这个和 str() 结果。

@hello_friend 这是我应用你的第二个解决方案时返回的内容

 game.time.total game.time.first.half game.time.second.half
1               7                    3                    12
2               7                    3                    12
3              10                    5                    15
4              10                    5                    15
5              12                    6                    17

提前致谢。

基础 R 解决方案:

numeric_df <- setNames(data.frame(lapply(data.frame(
  Vectorize(gsub)(":", ".", DF), stringsAsFactors = FALSE
),
function(x) {
  as.double(x)
})), names(DF))

数据:

 DF <- structure(list(game.time.total = c("95:09", "95:09", "95:31", 
"95:31", "95:39"), game.time.first.half = c("46:04", "46:04", 
"46:07", "46:07", "46:08"), game.time.second.half = c("49:05", 
"49:05", "49:23", "49:23", "49:31")), class = "data.frame", row.names = c(NA, -5L))

您可以使用 lubridate 包中的 ms 函数将列转换为分钟和秒。

library(lubridate)
library(dplyr)

DF %>% 
  mutate_all(ms) %>% 
  mutate_all(period_to_seconds) %>% 
  summarise_all(mean) %>% 
  mutate_all(seconds_to_period)

           game.time.total game.time.first.half game.time.second.half
1 1H 35M 23.8000000000002S               46M 6S 49M 17.4000000000001S

如果您想要以秒为单位的平均值,则没有最后一个 mutate_all 调用。

DF %>% 
  mutate_all(ms) %>% 
  mutate_all(period_to_seconds) %>% 
  summarise_all(mean)

  game.time.total game.time.first.half game.time.second.half
1          5723.8                 2766                2957.4

注:假设95.09表示95分9秒而不是95分0.09分钟

这里你要小心了。想想 "89:30""90:30" 的平均值。它们加起来是 180 分钟,所以平均值应该是 90:00。但是,如果您将它们转换为 89.3090.30,那么它们将添加到 179.60 并且平均值变为 89.80,这甚至没有意义。

有可用的软件包可以更轻松地处理时间,例如 lubridate,如果您经常处理时间,则应该学会使用它们。但是,下面的解决方案不需要任何额外的包,而且非常简单。它定义了两个小函数,用于在 "mm:ss" 格式和秒数之间进行转换。您可以安全地在几秒钟内进行求和和求平均值,然后转换回您的原始格式:

as_seconds <- function(x) sapply(strsplit(x, ":"), function(y) sum(as.numeric(y) * c(60, 1)))

as_min_sec <- function(x) paste0(x %/% 60, sprintf(":%02d", 21))

apply(DF, 2, function(x) as_min_sec(mean(as_seconds(x))))
#>       game.time.total  game.time.first.half game.time.second.half 
#>               "95:21"               "46:21"               "49:21"

如果您只想将每列中的冒号替换为点,您可以这样做:

as.data.frame(lapply(DF, function(x) gsub(":", ".", x)))
#>   game.time.total game.time.first.half game.time.second.half
#> 1           95.09                46.04                 49.05
#> 2           95.09                46.04                 49.05
#> 3           95.31                46.07                 49.23
#> 4           95.31                46.07                 49.23
#> 5           95.39                46.08                 49.31