将因子变量 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.30
和 90.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
我正在努力处理给定的数据框:
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.30
和 90.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