Как найти время нарушения определенного значения в R? - PullRequest
0 голосов
/ 12 марта 2020

Я хотел бы найти следующее вхождение («Время»), где минимальное значение («MinValue») нарушено.

Например, для следующей выборки данных:

Time <- c(1:10)
Value <- c(9,7,10,6,7,7,10,9,6,10)
MinValue <- c(5,6,8,4,6,6,8,6,4,9)
SampleData <- data.frame(Time, Value, MinValue)

Я хотел бы добиться следующего:

enter image description here

Я хотел бы добавить столбец ('TimeMinValue'), который показывает, в какое время минимальное значение нарушена текущая строка.

Большое спасибо всем за помощь! Я попытался найти свой ответ в Интернете, но ничего не смог найти. Однако, если я случайно продублировал вопрос, прошу прощения.

Ответы [ 2 ]

1 голос
/ 13 марта 2020

В качестве альтернативы, это может быть решено путем самостоятельного соединения .

Вот две различные реализации, использующие

  1. data.table
  2. SQL / sqldf()

data.table

Версия data.table представляет собой «однострочник», который агрегирует в неэквивалентном самосоединении :

library(data.table)
setDT(SampleData)[
  , TimeMinValue := .SD[.SD, on = .(Time > Time, Value <= MinValue), .(min(x.Time)), by = .EACHI]$V1][]
    Time Value MinValue TimeMinValue
 1:    1     9        5           NA
 2:    2     7        6            4
 3:    3    10        8            4
 4:    4     6        4           NA
 5:    5     7        6            9
 6:    6     7        6            9
 7:    7    10        8            9
 8:    8     9        6            9
 9:    9     6        4           NA
10:   10    10        9           NA

SQL / sqldf()

Мне было любопытно, как это можно выразить в синтаксисе SQL. Код более многословен, потому что мы должны объединить дважды:

  1. само-соединение, которое сравнивает MinValue с Value в последующих строках
  2. левое соединение для завершения строк и найти TimeMinValue для каждого Time
library(sqldf)
sqldf(
  "SELECT sd1.*, min(t) TimeMinValue
   FROM SampleData sd1 
   LEFT JOIN ( SELECT sd1.Time, 
                      sd2.Time t 
          FROM SampleData sd1 
          JOIN SampleData sd2
          WHERE sd1.Time < sd2.Time AND
                sd1.MinValue >= sd2.Value
        )
   USING (Time)
   GROUP BY Time  
")
   Time Value MinValue TimeMinValue
1     1     9        5           NA
2     2     7        6            4
3     3    10        8            4
4     4     6        4           NA
5     5     7        6            9
6     6     7        6            9
7     7    10        8            9
8     8     9        6            9
9     9     6        4           NA
10   10    10        9           NA

РЕДАКТИРОВАТЬ: Улучшено SQL версия

G. Grothendiek предложил упрощенную версию SQL, которая намного ближе к версии data.table:

sqldf(
  "SELECT a.*, min(b.Time) TimeMinValue
   FROM SampleData a
   LEFT JOIN SampleData b
   ON a.Time < b.Time AND
      a.MinValue >= b.Value
   GROUP BY a.Time")
1 голос
/ 12 марта 2020

Конечно, есть менее запутанный подход, но один вариант будет sapply над строками с which:

transform(
  SampleData,
  TimeMinValue = sapply(
    seq_len(nrow(SampleData)),
    function(x)
      Time[
        which(Value <= MinValue[x])[which(Value <= MinValue[x]) > x][1]
        ]))

Вывод:

   Time Value MinValue TimeMinValue
1     1     9        5           NA
2     2     7        6            4
3     3    10        8            4
4     4     6        4           NA
5     5     7        6            9
6     6     7        6            9
7     7    10        8            9
8     8     9        6            9
9     9     6        4           NA
10   10    10        9           NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...