Encontre a data mais antiga e a última em cada linha em R [duplicado]
Eu tenho um grande conjunto de dados com mais de 400 colunas que representam certos elementos de entrada do usuário de uma plataforma online e a hora em que cada entrada ocorreu. Cada linha representa um ID de usuário.
200 dessas colunas são da classe "POSIXct" "POSIXt" (por exemplo, 2019-11-04 15:33:50), e podem ocorrer valores ausentes, pois nem todos os elementos são exibidos ou preenchidos por todos os usuários.
Meu objetivo é criar duas colunas adicionais que incluam a primeira e a última data por linha de cada uma das 200 colunas "POSIXct" "POSIXt".
Aqui está um exemplo simplificado do quadro e uma das colunas adicionais desejadas. (ID 4 seria alguém que nunca se preocupou em abrir a lateral, mas tem dados de outras fontes de dados disponíveis e deve permanecer no conjunto de dados por enquanto)
ID Other_columns date_column date_column2 date_column3 max_date (what I want)
1 "numeric" 2019-11-04 19:33:50 2019-11-05 15:33:50 2019-11-05 16:33:50 2019-11-05 16:33:50
2 "numeric" NA 2019-11-04 17:20:10 2019-11-09 19:12:50 2019-11-09 19:12:50
3 "numeric" 2019-11-07 20:33:50 NA 2019-11-04 18:31:50 2019-11-07 20:33:50
4 NA NA NA NA NA
Até agora eu realmente não fui além da filtragem das outras colunas sem data,
is.POSIXt <- function(x) inherits(x, "POSIXt")
df%>%select(where(is.POSIXt))
Em vez de selecionar, provavelmente devo usar um mutate_at ou algo como condição, mas qual é a melhor maneira de verificar todas as 200 colunas de data / hora restantes e, em seguida, atribuir a data mais antiga / mais recente às colunas recém-criadas (ignorando o NA valores).
Respostas
Podemos usar pmax
e pmin
nas colunas 'data' para retornar a data mais antiga e a mais recente para cada linha
library(dplyr)
df %>%
mutate(max_date = do.call(pmax, c(select(., starts_with('date')), na.rm = TRUE)),
min_date = do.call(pmin, c(select(., starts_with('date')),
na.rm = TRUE)))
# ID Other_columns date_column date_column2 date_column3 max_date min_date
#1 1 numeric 2019-11-04 19:33:50 2019-11-05 15:33:50 2019-11-05 16:33:50 2019-11-05 16:33:50 2019-11-04 19:33:50
#2 2 numeric <NA> 2019-11-04 17:20:10 2019-11-09 19:12:50 2019-11-09 19:12:50 2019-11-04 17:20:10
#3 3 numeric 2019-11-07 20:33:50 <NA> 2019-11-04 18:31:50 2019-11-07 20:33:50 2019-11-04 18:31:50
#4 4 <NA> <NA> <NA> <NA> <NA> <NA>
Ou outra opção com rowwise
comc_across
df %>%
rowwise() %>%
mutate(max_date = max(as.POSIXct(c_across(starts_with('date'))),
na.rm = TRUE),
min_date = min(as.POSIXct(c_across(starts_with('date'))),
na.rm = TRUE))
-resultado
# A tibble: 4 x 7
# Rowwise:
# ID Other_columns date_column date_column2 date_column3 max_date min_date
# <int> <chr> <chr> <chr> <chr> <dttm> <dttm>
#1 1 numeric 2019-11-04 19:33:50 2019-11-05 15:33:50 2019-11-05 16:33:50 2019-11-05 16:33:50 2019-11-04 19:33:50
#2 2 numeric <NA> 2019-11-04 17:20:10 2019-11-09 19:12:50 2019-11-09 19:12:50 2019-11-04 17:20:10
#3 3 numeric 2019-11-07 20:33:50 <NA> 2019-11-04 18:31:50 2019-11-07 20:33:50 2019-11-04 18:31:50
#4 4 <NA> <NA> <NA> <NA> NA NA NA NA
dados
df <- structure(list(ID = 1:4, Other_columns = c("numeric", "numeric",
"numeric", NA), date_column = c("2019-11-04 19:33:50", NA, "2019-11-07 20:33:50",
NA), date_column2 = c("2019-11-05 15:33:50", "2019-11-04 17:20:10",
NA, NA), date_column3 = c("2019-11-05 16:33:50", "2019-11-09 19:12:50",
"2019-11-04 18:31:50", NA)), class = "data.frame", row.names = c(NA,
-4L))
Aqui está outra abordagem que você pode usar sem usar nenhum pacote.
Primeiro, obtenha dados para as colunas de data e, a partir daí, você pode usar a apply
função em cada linha para obter os valores máximos e mínimos de acordo. Aqui está o exemplo:
df_date = df[, sapply(df, FUN = function(x) class(x)[1]) %in% c("POSIXct", "POSIXt")]
df$max = apply(df_date, 2, FUN = function(x) max(x, na.rm = TRUE) df$min = apply(df_date, 2, FUN = function(x) min(x, na.rm = TRUE)
Dados
structure(list(ID = 1:4, Other_columns = c("numeric", "numeric",
"numeric", NA), date_column = structure(c(1572876230, NA, 1573139030,
NA), class = c("POSIXct", "POSIXt"), tzone = ""), date_column2 = structure(c(1572948230,
1572868210, NA, NA), class = c("POSIXct", "POSIXt"), tzone = ""),
date_column3 = structure(c(1572951830, 1573306970, 1572872510,
NA), class = c("POSIXct", "POSIXt"), tzone = "")), class = "data.frame", row.names = c(NA,
-4L))