Как выбрать только одну строку данных для каждого идентификатора на основе минимальной разницы дат в R? - PullRequest
0 голосов
/ 16 марта 2020

У меня есть фрейм данных с некоторыми идентификаторами и переменным количеством строк для каждого идентификатора, например:

ID    Date_start    Date
1     2016-11-02    2020-2-22
1     2016-11-02    2015-1-18
2     2019-12-22    2017-3-2
2     2019-12-22    2019-2-9
2     2019-12-22    2017-12-1

И для каждого идентификатора я хотел бы сохранить только одну строку, одну с Дата, ближайшая к Date_start. Затем я хотел бы установить значение NA для всех строк, где разность дат между abs (Date и Date_start) меньше 100 дней.

Есть ли простой способ сделать это?

Большое спасибо заранее

Ответы [ 3 ]

0 голосов
/ 16 марта 2020

Используя dplyr, мы можем получить следующее. Я добавил новый идентификатор, чтобы показать, как сделать все значения NA. Используя лучшее представление Ронака о replace вместо ifelse, мы можем сохранить классы.

library(dplyr)

df %>%
  mutate(Date_diff = abs(difftime(Date, Date_start))) %>%
  group_by(ID) %>%
  filter(Date_diff == min(Date_diff)) %>%
  mutate_all(~replace(., Date_diff < 100, NA))
#> # A tibble: 3 x 4
#> # Groups:   ID [3]
#>      ID Date_start Date       Date_diff
#>   <dbl> <date>     <date>     <drtn>   
#> 1     1 2016-11-02 2015-01-18 654 days 
#> 2     2 2019-12-22 2019-02-09 316 days 
#> 3     3 NA         NA          NA days

Данные

df <- structure(list(ID = c(1, 1, 2, 2, 2, 3), Date_start = structure(c(17107, 
17107, 18252, 18252, 18252, 18250), class = "Date"), Date = structure(c(18314, 
16453, 17227, 17936, 17501, 18202), class = "Date")), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L))
0 голосов
/ 16 марта 2020

Решение Base R:

# Convert factors to dates: 

cleaned_df <- within(df, {
                    Date_start <- as.Date(sapply(Date_start, as.character), "%Y-%m-%d")
                    Date <- as.Date(sapply(Date, as.character), "%Y-%m-%d")
                    }
                  )
# Aggregate to find the min Date per id: 

data.frame(do.call("rbind", lapply(split(cleaned_df, cleaned_df$ID), 
       function(x){
         data.frame(ID = unique(x$ID), Date = x$Date[which.min(x$Date_start - x$Date)])
        }
       )
      ),
 row.names = NULL
)

Решение Tidyverse:

library(tidyverse)
df %>% 
  mutate_if(str_detect(tolower(names(.)), "date"), funs(as.Date(., "%Y-%m-%d"))) %>%
  group_by(ID) %>% 
  summarise(Date = Date[which.min(Date - Date_start)]) %>% 
  ungroup()

Данные спасибо @Ronak Shah:

df <-
  structure(
    list(
      ID = c(1L, 1L, 2L, 2L, 2L),
      Date_start = structure(
        c(1L,
          1L, 2L, 2L, 2L),
        .Label = c("2016-11-02", "2019-12-22"),
        class = "factor"
      ),
      Date = structure(
        c(5L, 1L, 3L, 4L, 2L),
        .Label = c("2015-1-18",
                   "2017-12-1", "2017-3-2", "2019-2-9", "2020-2-22"),
        class = "factor"
      )
    ),
    class = "data.frame",
    row.names = c(NA,-5L)
  )
0 голосов
/ 16 марта 2020

Один из способов использования dplyr может быть group_by ID и получить строку с минимальной разницей с Date.

library(dplyr)

df %>%
  mutate_at(-1, lubridate::ymd) %>%
  group_by(ID) %>%
  slice(which.min(abs(Date_start - Date)))

#    ID Date_start Date      
#  <int> <date>     <date>    
#1     1 2016-11-02 2015-01-18
#2     2 2019-12-22 2019-02-09

Если вы хотите установить даты на NA, вы можете это сделать.

df %>%
  mutate_at(-1, lubridate::ymd) %>%
  group_by(ID) %>%
  mutate(diff = as.numeric(abs(Date_start - Date))) %>%
  slice(which.min(abs(Date_start - Date))) %>%
  mutate(diff = replace(diff, diff < 100, NA))

данные

df <- structure(list(ID = c(1L, 1L, 2L, 2L, 2L), Date_start = structure(c(1L, 
1L, 2L, 2L, 2L), .Label = c("2016-11-02", "2019-12-22"), class = "factor"), 
Date = structure(c(5L, 1L, 3L, 4L, 2L), .Label = c("2015-1-18", 
"2017-12-1", "2017-3-2", "2019-2-9", "2020-2-22"), class = "factor")),
class = "data.frame", row.names = c(NA, -5L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...