Убедитесь, что последовательность дат находится в правильном порядке

#r #date #sequence

#r #Дата #последовательность

Вопрос:

У меня есть фрейм данных, который содержит 4 столбца дат. Должно быть, что col1 встречается первым, col2 — вторым, col3 — третьим, а col4 — последним. Я хотел бы определить, в каких строках даты не расположены последовательно

Вот игрушечный фрейм данных

 col1 <- c(as.Date("2004-1-1"), as.Date("2005-1-1"), as.Date("2006-1-1"))
col2 <- c(as.Date("2004-1-2"), as.Date("2005-1-3"), as.Date("2006-1-2"))
col3 <- c(as.Date("2004-1-5"), as.Date("2005-1-9"), as.Date("2006-1-19"))
col4 <- c(as.Date("2004-1-9"), as.Date("2005-1-15"), as.Date("2006-1-10"))
dates <- data.frame(col1, col2, col3, col4)

dates

    col1       col2       col3       col4
1 2004-01-01 2004-01-02 2004-01-05 2004-01-09
2 2005-01-01 2005-01-03 2005-01-09 2005-01-15
3 2006-01-01 2006-01-02 2006-01-19 2006-01-10
  

Мой желаемый результат был бы,

     col1       col2       col3       col4       Seq?
1 2004-01-01 2004-01-02 2004-01-05 2004-01-09    T
2 2005-01-01 2005-01-03 2005-01-09 2005-01-15    T
3 2006-01-01 2006-01-02 2006-01-19 2006-01-10    F
  

Ответ №1:

Я могу придумать пару решений. Наивно я бы предложил использовать apply with ?is.unsorted , который:

Проверьте, не отсортирован ли объект (в порядке возрастания), без затрат на его сортировку.

 !apply(dates, 1, is.unsorted)
#[1]  TRUE  TRUE FALSE
  

В противном случае преобразуйте в длинный набор, а затем выполните групповую операцию, которая должна выполняться быстрее на больших наборах данных:

 tmp <- cbind(row=seq_len(nrow(dates)), stack(lapply(dates, as.vector)))
!tapply(tmp$values, tmp$row, FUN=is.unsorted)
  

И, наконец, метод грубой силы сравнения каждого столбца со следующим через Map , который снова должен быть еще быстрее:

 Reduce(`amp;`, Map(`<`, dates[-length(dates)], dates[-1]))
  

Комментарии:

1. Для последнего, возможно, do.call(pmin, Map(`<`, dates[-length(dates)], dates[-1])) было бы немного быстрее

2. @d.b — выглядит примерно так же по моим таймингам. Это также приводит результат к c(1,1,0) вместо логических значений.

Ответ №2:

Простая apply инструкция сделает свое дело:

 dates$Seq <- apply(dates, 1, function(x) all(x == sort(x)))
  

Ответ №3:

 rowSums(Reduce(pmax, dates, accumulate = TRUE) == dates) == NCOL(dates)
#[1]  TRUE  TRUE FALSE
  

Reduce с pmax определяет последовательную максимальную дату для каждой строки. С помощью accumulate = TRUE мы сохраняем выходные данные Reduce для каждой итерации и сравниваем с исходными данными в dates

Другой подход, который вводит NA , если даты не отсортированы.

 !is.na(Reduce(function(x, y) ifelse(x > y | is.na(x), NA, y), dates))
[1]  TRUE  TRUE FALSE