提问人:Sam 提问时间:11/16/2023 更新时间:11/16/2023 访问量:34
在 dplyr::mutate 中执行函数并忽略缺失值
Perform function within dplyr::mutate and ignore missing values
问:
我正在努力寻找解决应该(并且可能是)简单问题的解决方案。
给定以下数据(代码如下):
# A tibble: 10 × 2
id datetime
<dbl> <dttm>
1 1 NA
2 2 2023-01-16 10:00:00
3 3 NA
4 4 2023-01-18 20:00:00
5 5 2023-01-28 21:00:00
6 6 2023-01-17 19:00:00
7 7 NA
8 8 2023-01-16 04:00:00
9 9 2023-01-15 06:00:00
10 10 2023-01-13 21:00:00
我想将小时从 POSIXct 向量提取到一个新变量,但缺少值给我带来了问题。
预期输出:
# A tibble: 10 × 3
id datetime hour
<dbl> <dttm> <dbl>
1 1 NA NA
2 2 2023-01-16 10:00:00 10
3 3 NA NA
4 4 2023-01-18 20:00:00 20
5 5 2023-01-28 21:00:00 21
6 6 2023-01-17 19:00:00 19
7 7 NA NA
8 8 2023-01-16 04:00:00 4
9 9 2023-01-15 06:00:00 6
10 10 2023-01-13 21:00:00 21
我尝试了各种版本的 if_else 或 case_when 来管理缺失值,但不断出现错误。我的当前版本抛出错误:
Error in `mutate()`:
ℹ In argument: `hour = if_else(...)`.
Caused by error in `map_chr()`:
ℹ In index: 1.
Caused by error:
! Result must be length 1, not 0.
Run `rlang::last_trace()` to see where the error occurred.
建议它仍然在if_else的 FALSE 部分包含缺失值。
回复:
library(tidyverse)
dat <- tibble(
id = seq(1, 10, 1),
datetime = sample(seq(as.POSIXct("2023/1/1"), as.POSIXct("2023/1/31"), by = "hour"), 10)
)
dat[c(1, 3, 7), 2] <- NA
dat
dat <- dat %>%
mutate(
hour = if_else(
is.na(datetime),
NA,
datetime %>% str_split(" ") %>% map_chr(2) %>% hms() %>% hour()
)
)
答:
1赞
Peter
11/16/2023
#1
lubridate::hour()
是你的朋友...
library(tibble)
library(dplyr)
library(lubridate)
dat <- tibble(
id = seq(1, 10, 1),
datetime = sample(seq(as.POSIXct("2023/1/1"), as.POSIXct("2023/1/31"), by = "hour"), 10)
)
dat[c(1, 3, 7), 2] <- NA
mutate(dat, hour = lubridate::hour(datetime) )
#> # A tibble: 10 × 3
#> id datetime hour
#> <dbl> <dttm> <int>
#> 1 1 NA NA
#> 2 2 2023-01-11 05:00:00 5
#> 3 3 NA NA
#> 4 4 2023-01-05 15:00:00 15
#> 5 5 2023-01-04 00:00:00 0
#> 6 6 2023-01-26 06:00:00 6
#> 7 7 NA NA
#> 8 8 2023-01-12 21:00:00 21
#> 9 9 2023-01-20 12:00:00 12
#> 10 10 2023-01-05 04:00:00 4
创建于 2023-11-16 with reprex v2.0.2
评论
0赞
Sam
11/16/2023
确实是一个简单的解决方案!
1赞
jeffreyohene
11/16/2023
#2
我认为该错误可能是由使用 hms() 引起的。hms() 更适合使用持续时间,而不是使用您拥有的时间戳或日期时间对象。解决此问题的最佳函数是使用 lubridate 包中的 hour() 函数从 datetime 列的 datetime 值中提取小时,如下所示:
library(tidyverse)
dat <- tibble(
id = seq(1, 10, 1),
datetime = sample(seq(as.POSIXct("2023/1/1"), as.POSIXct("2023/1/31"), by = "hour"), 10)
)
dat[c(1, 3, 7), 2] <- NA
dat <- dat %>%
mutate(
hour = if_else(
is.na(datetime),
NA,
lubridate::hour(datetime)
)
)
dat
#> # A tibble: 10 × 3
#> id datetime hour
#> <dbl> <dttm> <int>
#> 1 1 NA NA
#> 2 2 2023-01-15 22:00:00 22
#> 3 3 NA NA
#> 4 4 2023-01-02 19:00:00 19
#> 5 5 2023-01-13 06:00:00 6
#> 6 6 2023-01-18 00:00:00 0
#> 7 7 NA NA
#> 8 8 2023-01-21 00:00:00 0
#> 9 9 2023-01-14 10:00:00 10
#> 10 10 2023-01-13 17:00:00 17
或者,您可以在 mutate 中使用 case_when 函数而不是 ifelse 来修改它,同时在新列中保持所有 NA 值不变
dat <- tibble(
id = seq(1, 10, 1),
datetime = sample(seq(as.POSIXct("2023/1/1"), as.POSIXct("2023/1/31"), by = "hour"), 10)
)
dat[c(1, 3, 7), 2] <- NA
dat <- dat %>%
mutate(
hour = case_when(
is.na(datetime) ~ NA_real_,
TRUE ~ datetime %>% lubridate::hour()
)
)
评论
mutate(dat, hour = lubridate::hour(datetime) )