#r #if-statement #conditional-statements #difftime
Вопрос:
Я пытаюсь исправить некоторые ошибочные записи в наборе данных условным способом. Мне нужно сделать это по группам, и условие основано на разнице между 2 временными метками в 2 разных наборах данных.
Вот несколько примеров типов данных, с которыми я работаю:-
df1<-structure(list(UserID = c("AAA", "AAA", "AAA", "BBB", "BBB",
"BBB", "BBB", "CCC", "CCC", "CCC", "CCC", "CCC", "DDD", "DDD",
"DDD", "DDD", "DDD", "DDD"), Value = c("Group1", "Group1", "Group2",
"Group3", "Group3", "Group1", "Group2", "Group4", "Group5", "Group5",
"Group5", "Group5", "Group1", "Group2", "Group2", "Group2", "Group2",
"Group2"), Time = structure(c(1577840400, 1577844000, 1577847600,
1577966400, 1577970000, 1577973600, 1577977200, 1577977200, 1577980800,
1577984400, 1577988000, 1577991600, 1578193200, 1578196800, 1578200400,
1578204000, 1578207600, 1578211200), class = c("POSIXct", "POSIXt"
), tzone = "UTC")), row.names = c(NA, -18L), class = "data.frame")
df2<-structure(list(UserID = c("AAA", "AAA", "AAA", "BBB", "BBB",
"BBB", "BBB", "CCC", "CCC", "DDD", "DDD"), StartTime = structure(c(1577839980,
1577840460, 1577843820, 1577966580, 1577970180, 1577973360, 1577975160,
1577977920, 1577978940, 1578193200, 1578193920), class = c("POSIXct",
"POSIXt"), tzone = "UTC"), EndTime = structure(c(1577840460,
1577843820, 1577846640, 1577970180, 1577973360, 1577975160, 1577978580,
1577978940, 1577980680, 1578193920, 1578196620), class = c("POSIXct",
"POSIXt"), tzone = "UTC")), row.names = c(NA, -11L), class = "data.frame")
Оба набора данных выглядят следующим образом:-
print(df1)
UserID Value Time
1 AAA Group1 2020-01-01 01:00:00
2 AAA Group1 2020-01-01 02:00:00
3 AAA Group2 2020-01-01 03:00:00
4 BBB Group3 2020-01-02 12:00:00
5 BBB Group3 2020-01-02 13:00:00
6 BBB Group1 2020-01-02 14:00:00
7 BBB Group2 2020-01-02 15:00:00
8 CCC Group4 2020-01-02 15:00:00
9 CCC Group5 2020-01-02 16:00:00
10 CCC Group5 2020-01-02 17:00:00
11 CCC Group5 2020-01-02 18:00:00
12 CCC Group5 2020-01-02 19:00:00
13 DDD Group1 2020-01-05 03:00:00
14 DDD Group2 2020-01-05 04:00:00
15 DDD Group2 2020-01-05 05:00:00
16 DDD Group2 2020-01-05 06:00:00
17 DDD Group2 2020-01-05 07:00:00
18 DDD Group2 2020-01-05 08:00:00
print(df2)
UserID StartTime EndTime
1 AAA 2020-01-01 00:53:00 2020-01-01 01:01:00
2 AAA 2020-01-01 01:01:00 2020-01-01 01:57:00
3 AAA 2020-01-01 01:57:00 2020-01-01 02:44:00
4 BBB 2020-01-02 12:03:00 2020-01-02 13:03:00
5 BBB 2020-01-02 13:03:00 2020-01-02 13:56:00
6 BBB 2020-01-02 13:56:00 2020-01-02 14:26:00
7 BBB 2020-01-02 14:26:00 2020-01-02 15:23:00
8 CCC 2020-01-02 15:12:00 2020-01-02 15:29:00
9 CCC 2020-01-02 15:29:00 2020-01-02 15:58:00
10 DDD 2020-01-05 03:00:00 2020-01-05 03:12:00
11 DDD 2020-01-05 03:12:00 2020-01-05 03:57:00
Столбец метки времени в df1 округляется до каждого часа, в то время как в df2 есть начальная метка времени и конечная метка времени (обе детализированы и округлены до минуты). В df1 есть некоторые записи, которые неверны, поскольку они не отображаются в df2 в соответствующее время.
Например, UserID
последняя EndTime
метка времени CCC в df2-2020-01-02 15:58:00, но в df1 CCC отображается по адресу 2020-01-02 17:00:00, 2020-01-02 18:00:00 amp; 2020-01-02 19:00:00; аналогичный пример с UserID
DDD.
Что я хочу сделать
Если UserID
у a есть запись в df1 с df1$Time
отметкой времени >=60 минут, чем их последняя > df2$EndTime
отметка времени в df2, я хочу, чтобы запись в поле df1$Value
была изменена на «NoGroup».
Вот наглядный пример желаемого результата:-
UserID Value Time
1 AAA Group1 2020-01-01 01:00:00
2 AAA Group1 2020-01-01 02:00:00
3 AAA Group2 2020-01-01 03:00:00
4 BBB Group3 2020-01-02 12:00:00
5 BBB Group3 2020-01-02 13:00:00
6 BBB Group1 2020-01-02 14:00:00
7 BBB Group2 2020-01-02 15:00:00
8 CCC Group4 2020-01-02 15:00:00
9 CCC Group5 2020-01-02 16:00:00
10 CCC NoGroup 2020-01-02 17:00:00
11 CCC NoGroup 2020-01-02 18:00:00
12 CCC NoGroup 2020-01-02 19:00:00
13 DDD Group1 2020-01-05 03:00:00
14 DDD Group2 2020-01-05 04:00:00
15 DDD NoGroup 2020-01-05 05:00:00
16 DDD NoGroup 2020-01-05 06:00:00
17 DDD NoGroup 2020-01-05 07:00:00
18 DDD NoGroup 2020-01-05 08:00:00
Любые указатели ценятся, как всегда 🙂
Ответ №1:
с помощью dplyr
:
df1 %>%
left_join(df2 %>% group_by(UserID) %>% filter(EndTime == max(EndTime)), by = "UserID") %>%
mutate(Value = if_else(Time-EndTime >= 60, "NoGroup", Value)) %>%
select(-c(4,5))
Сначала вы join
последний EndTimes
из каждого UserID
из df2
них df1
, затем вы проверяете, не прошло ли Time
больше 60 минут после этого EndTime
, и Value
соответственно меняете. Наконец, вы удаляете столбцы, которые были добавлены во время join
Комментарии:
1. Это здорово, большое вам за это спасибо, работает блестяще!
Ответ №2:
df1<-structure(list(UserID = c("AAA", "AAA", "AAA", "BBB", "BBB",
"BBB", "BBB", "CCC", "CCC", "CCC", "CCC", "CCC", "DDD", "DDD",
"DDD", "DDD", "DDD", "DDD"), Value = c("Group1", "Group1", "Group2",
"Group3", "Group3", "Group1", "Group2", "Group4", "Group5", "Group5",
"Group5", "Group5", "Group1", "Group2", "Group2", "Group2", "Group2",
"Group2"), Time = structure(c(1577840400, 1577844000, 1577847600,
1577966400, 1577970000, 1577973600, 1577977200, 1577977200, 1577980800,
1577984400, 1577988000, 1577991600, 1578193200, 1578196800, 1578200400,
1578204000, 1578207600, 1578211200), class = c("POSIXct", "POSIXt"
), tzone = "UTC")), row.names = c(NA, -18L), class = "data.frame")
df2<-structure(list(UserID = c("AAA", "AAA", "AAA", "BBB", "BBB",
"BBB", "BBB", "CCC", "CCC", "DDD", "DDD"), StartTime = structure(c(1577839980,
1577840460, 1577843820, 1577966580, 1577970180, 1577973360, 1577975160,
1577977920, 1577978940, 1578193200, 1578193920), class = c("POSIXct",
"POSIXt"), tzone = "UTC"), EndTime = structure(c(1577840460,
1577843820, 1577846640, 1577970180, 1577973360, 1577975160, 1577978580,
1577978940, 1577980680, 1578193920, 1578196620), class = c("POSIXct",
"POSIXt"), tzone = "UTC")), row.names = c(NA, -11L), class = "data.frame")
library(tidyverse)
library(lubridate)
#>
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#>
#> date, intersect, setdiff, union
no_groups <-
df1 %>%
as_tibble() %>%
left_join(df2 %>% as_tibble()) %>%
group_by(UserID) %>%
mutate(
last_end = max(EndTime)
) %>%
mutate(
no_group = all((last_end - Time) <= minutes(60))
) %>%
distinct(UserID, no_group)
#> Joining, by = "UserID"
no_groups
#> # A tibble: 4 x 2
#> # Groups: UserID [4]
#> UserID no_group
#> <chr> <lgl>
#> 1 AAA FALSE
#> 2 BBB FALSE
#> 3 CCC TRUE
#> 4 DDD TRUE
df1 %>%
as_tibble() %>%
left_join(no_groups) %>%
mutate(Value = ifelse(no_group, "NoGroup", Value)) %>%
select(-no_group)
#> Joining, by = "UserID"
#> # A tibble: 18 x 3
#> UserID Value Time
#> <chr> <chr> <dttm>
#> 1 AAA Group1 2020-01-01 01:00:00
#> 2 AAA Group1 2020-01-01 02:00:00
#> 3 AAA Group2 2020-01-01 03:00:00
#> 4 BBB Group3 2020-01-02 12:00:00
#> 5 BBB Group3 2020-01-02 13:00:00
#> 6 BBB Group1 2020-01-02 14:00:00
#> 7 BBB Group2 2020-01-02 15:00:00
#> 8 CCC NoGroup 2020-01-02 15:00:00
#> 9 CCC NoGroup 2020-01-02 16:00:00
#> 10 CCC NoGroup 2020-01-02 17:00:00
#> 11 CCC NoGroup 2020-01-02 18:00:00
#> 12 CCC NoGroup 2020-01-02 19:00:00
#> 13 DDD NoGroup 2020-01-05 03:00:00
#> 14 DDD NoGroup 2020-01-05 04:00:00
#> 15 DDD NoGroup 2020-01-05 05:00:00
#> 16 DDD NoGroup 2020-01-05 06:00:00
#> 17 DDD NoGroup 2020-01-05 07:00:00
#> 18 DDD NoGroup 2020-01-05 08:00:00
Создано 2021-09-17 пакетом reprex (v2.0.0)