我有一个资料集,我需要将任何值为 0 但在过去 48 小时内具有非零值的值更改为特定字符串。我猜我可能需要在执行此操作之前将除第一列之外的所有列从 dbl 转换为 chr?
Time colA colB colC colD
<dttm> <dbl> <dbl> <dbl> <dbl>
1 2021-11-21 10:00:00 8 0 9 176
2 2021-11-11 11:00:00 21 0 22 416
3 2021-11-21 11:00:00 19 0 20 373
4 2021-11-11 12:00:00 40 13 28 566
5 2021-11-21 12:00:00 26 0 27 527
6 2021-11-11 13:00:00 50 20 32 651
7 2021-11-11 10:00:00 11 0 12 216
8 2021-11-21 13:00:00 30 0 31 617
9 2021-11-11 14:00:00 51 0 32 675
10 2021-11-21 14:00:00 31 0 32 644
很抱歉资料尚未按时间排序,正在努力解决这个问题。例如,这里的输出,我会喜欢去:
Time colA colB colC colD
<dttm> <dbl> <dbl> <dbl> <dbl>
1 2021-11-21 10:00:00 8 0 9 176
2 2021-11-11 11:00:00 21 0 22 416
3 2021-11-21 11:00:00 19 0 20 373
4 2021-11-11 12:00:00 40 13 28 566
5 2021-11-21 12:00:00 26 0 27 527
6 2021-11-11 13:00:00 50 20 32 651
7 2021-11-11 10:00:00 11 0 12 216
8 2021-11-21 13:00:00 30 0 31 617
9 2021-11-11 14:00:00 51 STRING1 32 675
10 2021-11-21 14:00:00 31 0 32 644
由于 colB 在 2021-11-11 14:00:00 的值为 0,但在此之前的 48 小时内至少有 1 个先前值!= 0,因此它会更改为“STRING1”
抱歉,如果这令人困惑,我正在尝试自动化我通常在 Excel 中手动执行的操作。提前致谢
uj5u.com热心网友回复:
这是一个tidyverse解决方案。我将首先创建一些示例资料(请注意,我确实将其他列设定为字符):
data = tribble(
~ time, ~ colA, ~ colB,
"2021-11-21 12:00:00", 1, 0,
"2021-11-22 00:00:00", 0, 1,
"2021-11-24 12:00:00", 0, 0,
"2021-11-25 12:00:00", 1, 1,
"2021-11-26 12:00:00", 0, 0,
) %>%
mutate(
time = ymd_hms(time),
across(-time, as.character)
)
# A tibble: 5 x 3
time colA colB
<dttm> <chr> <chr>
1 2021-11-21 12:00:00 1 0
2 2021-11-22 00:00:00 0 1
3 2021-11-24 12:00:00 0 0
4 2021-11-25 12:00:00 1 1
5 2021-11-26 12:00:00 0 0
这个问题的挑战在于,每次我们都需要知道要查找哪些其他行来确定每列的新值。要做到这一点,我将使用purrr:pmap()
和.data
可用的物件dplyr
。我将首先演示如何“回顾”过去 48 小时内的行:
data %>%
mutate(
across(
.cols = -time,
function(col) {
pmap_chr(list(time), function(t) {
eligible = .data$time >= t - hours(48) & .data$time < t
paste(col[eligible], collapse = ",")
})
},
.names = "{.col}_previous"
)
)
输出:
# A tibble: 5 x 5
time colA colB colA_previous colB_previous
<dttm> <chr> <chr> <chr> <chr>
1 2021-11-21 12:00:00 1 0 "" ""
2 2021-11-22 00:00:00 0 1 "1" "0"
3 2021-11-24 12:00:00 0 0 "" ""
4 2021-11-25 12:00:00 1 1 "0" "0"
5 2021-11-26 12:00:00 0 0 "0,1" "0,1"
如您所见,这看起来很有希望。我们已准备好以此为核心思想来开发解决方案。
data %>%
mutate(
across(
.cols = -time,
function(col) {
modify_ind = pmap_lgl(list(time), function(t) {
eligible = .data$time >= t - hours(48) & .data$time < t
any(col[eligible] != "0")
})
ifelse(modify_ind & col == "0", "STRING1", col)
}
)
)
输出:
# A tibble: 5 x 3
time colA colB
<dttm> <chr> <chr>
1 2021-11-21 12:00:00 1 0
2 2021-11-22 00:00:00 STRING1 1
3 2021-11-24 12:00:00 0 0
4 2021-11-25 12:00:00 1 1
5 2021-11-26 12:00:00 STRING1 STRING1
一些注意事项:
- 在我的解决方案中,我创建了一个
modify_ind
建立在前面所示想法的基础上:访问在过去 48 小时内按时间过滤的列,然后检查是否有任何非零值。然后我修改列,只要它modify_ind
是TRUE
与列的值"0"
。 - 如果您想创建新列而不是完全替换原始列,请添加一个
.names
自变量 toacross()
如前所示。 - 如果您只想修改资料集中的几列,而不是使用
across(.cols = -time)
,请使用类似across(.cols = c("colA", "colB"))
.
0 评论