R: Изменить строки в кадре данных, если значение повторяется после n элементов - PullRequest
2 голосов
/ 11 февраля 2020

У меня очень большой фрейм данных Данные , где мне нужно проверить, повторяется ли Энергия в течение n шагов. Вы можете видеть, что Энергия снова равна нулю после n шагов, ведь это то, что мне нужно изменить. Я установил на 10 в примере. Мне нужно сделать это, потому что это ошибка в сообщении.

Ниже приведен код, который я придумал, но для завершения моих данных о дырах требуется слишком много времени.

Вот выдержка из моих данных, чтобы вы могли проверить это:

Date <- as.POSIXct(c("2017-06-03 01:00:00", "2017-06-03 01:15:00", "2017-06-03 01:30:00","2017-06-03 01:45:00","2017-06-03 02:00:00", "2017-06-03 02:15:00", "2017-06-03 02:30:00","2017-06-03 02:45:00","2017-06-03 03:00:00", "2017-06-03 03:15:00", "2017-06-03 03:30:00","2017-06-03 03:45:00","2017-06-03 04:00:00", "2017-06-03 04:15:00", "2017-06-03 04:30:00","2017-06-03 04:45:00","2017-06-03 05:00:00", "2017-06-03 05:15:00", "2017-06-03 05:30:00","2017-06-03 05:45:00","2017-06-03 06:00:00", "2017-06-03 06:15:00", "2017-06-03 06:30:00","2017-06-03 06:45:00","2017-06-03 07:00:00", "2017-06-03 07:15:00", "2017-06-03 07:30:00","2017-06-03 07:45:00","2017-06-03 08:00:00","2017-06-03 08:15:00"))
Energy <- c(0,0,0,0,150,149,149,146,147,146,142,5,0,0,0,0,5,14,37,55,54,94,82,127,197,NA,256,195,219,220)
Sun <-c(0,0,0,0,0,0,0,0,1,5,11,23,34,34,31,34,41,75,107,111,104,141,107,199,197,180,241,190,153,150)
Data <- data.frame(Date, Energy, Sun) 

Есть также значения NA в списке, и я должен рассмотреть их тоже. Для этого примера я поставил одно значение NA.

n <- 10
for (m in c(1:length(Data[[1]]))) {

    if (Data$Energy[m] == 0 && !is.na(Data$Energy[m])) {

      for (l in c(1:n)) {
        if (m+l > length(Data[[1]])) {
          break()
        }
        if (Data$Energy[m] == Data$Energy[m + l] && !is.na(Data$Energy[m + l])) {
          for (j in c(1:(l-1))) {
            Data$Energy[m + j] <- 0

          }
        }
      }
   }
}

Я уверен, что есть более простой способ решить эту проблему, но я не знаю как, поскольку я новичок в R. Я имею в виду, что я использую if и for так много, он не может бежать быстро. Очень важно, чтобы код работал быстрее, потому что в Dataframe у меня более 2 000 000 элементов.

Я получаю такой результат (который я хочу, но занимает много времени):

Data
                  Date Energy Sun
1  2017-06-03 01:00:00      0   0
2  2017-06-03 01:15:00      0   0
3  2017-06-03 01:30:00      0   0
4  2017-06-03 01:45:00      0   0
5  2017-06-03 02:00:00      0   0
6  2017-06-03 02:15:00      0   0
7  2017-06-03 02:30:00      0   0
8  2017-06-03 02:45:00      0   0
9  2017-06-03 03:00:00      0   1
10 2017-06-03 03:15:00      0   5
11 2017-06-03 03:30:00      0  11
12 2017-06-03 03:45:00      0  23
13 2017-06-03 04:00:00      0  34
14 2017-06-03 04:15:00      0  34
15 2017-06-03 04:30:00      0  31
16 2017-06-03 04:45:00      0  34
17 2017-06-03 05:00:00      5  41
18 2017-06-03 05:15:00     14  75
19 2017-06-03 05:30:00     37 107
20 2017-06-03 05:45:00     55 111
21 2017-06-03 06:00:00     54 104
22 2017-06-03 06:15:00     94 141
23 2017-06-03 06:30:00     82 107
24 2017-06-03 06:45:00    127 199
25 2017-06-03 07:00:00    197 197
26 2017-06-03 07:15:00     NA 180
27 2017-06-03 07:30:00    256 241
28 2017-06-03 07:45:00    195 190
29 2017-06-03 08:00:00    219 153
30 2017-06-03 08:15:00    220 150

Спасибо за ваше время и помощь заранее.

Ответы [ 2 ]

4 голосов
/ 11 февраля 2020

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

# Window size
n <- 10

# Find zeroes
zeros <- which(Data$Energy == 0)

# Find distance between zeroes
dist.zero <- diff(zeros)

# Generate index sequences of windows to change
idx <- unlist(lapply(which(dist.zero > 1 & dist.zero <= n), function(x) zeros[x]:zeros[x+1]))

# Replace values
Data$Energy[idx] <- 0
1 голос
/ 11 февраля 2020

Следующий код работает быстрее, чем решение вопроса.
Вместо вложенных циклов for он повторяется один раз только с sapply и определяет повторы с dplyr::lead. Затем быстрый rowSums получает элементы вектора-столбца Energy, которые необходимо изменить.

n <- 10

eq <- sapply(seq.int(n), function(l){
  z <- Data[["Energy"]] == dplyr::lead(Data[["Energy"]], n = l, default = 0)
  z | Data[["Energy"]] == 0
})

eq[is.na(eq)] <- FALSE
inx <- rowSums(eq) != 0
inx <- which(inx)
if(length(inx) > 0) {
  Data[["Energy"]][min(inx):max(inx)] <- 0
}
Data

После запуска этого кода два созданных вектора больше не нужны.

rm(eq, inx)    # tidy up
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...