Как создать переменную, идентифицирующую уникальные группы на основе ряда значений другой переменной? - PullRequest
0 голосов
/ 04 мая 2018

У меня есть набор данных df с двумя переменными: одна (в порядке возрастания) переменная posixct date.time и одно числовое значение переменной. Значение переменной состоит из серии нулей или серии различных положительных чисел, больших нуля. Длина каждой серии случайна, но больше единицы.

Редактировать: загрузка библиотеки lubridate

library(lubridate)

Набор данных df:

set.seed(10)
df <- data.frame(date.time=seq(ymd_hms("2016-01-01 00:00:00"),ymd_hms("2016-01-01 01:00:00"),length.out = 20),value=c(runif(3,1,3),rep.int(0,4),runif(5,1,3),rep.int(0,4),runif(4,1,3)))

Желаемый результат:

desired.outcome <- cbind(df,peak=c(1,1,1,0,0,0,0,2,2,2,2,2,0,0,0,0,3,3,3,3))

Я хотел бы создать третью переменную, называемую пиком, которая идентифицирует каждую серию положительных чисел, больших нуля, как отдельный «пик». Пик определяется как серия положительных чисел, больших нуля, которые находятся между двумя сериями нулей.

  • Какой эффективный способ получить желаемый результат для df> 5 миллионов строк, предпочтительно с использованием data.table или Dplyr?

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

Может не красавица:

(не может оценить ваши данные)

set.seed(10)
value=c(runif(3,1,3),rep.int(0,4),runif(5,1,3),rep.int(0,4),runif(4,1,3))

Код:

library(data.table)

result <- rleidv(value>0)
result[!(value>0)]<-0
result[value>0]<-rleidv(result[value>0])

результат:

#[1] 1 1 1 0 0 0 0 2 2 2 2 2 0 0 0 0 3 3 3 3
0 голосов
/ 04 мая 2018

Другой вариант (в mtd2) для вашего рассмотрения:

set.seed(10L)

#generate dataset of 5million rows as OP mentioned
N <- 5e6
df <- data.frame(value=10*runif(N))
#randomly set 25% of values to 0
df[sample(N, 0.25*N), "value"] <- 0

##original dataset of 20 rows
# df <- data.frame(date.time=seq(as.POSIXct("2016-01-01 00:00:00"),as.POSIXct("2016-01-01 01:00:00"),length.out = 20),
#     value=c(runif(3,1,3),rep.int(0,4),runif(5,1,3),rep.int(0,4),runif(4,1,3)))

mtd1 <- function() {
    inverse.rle(with(a<-rle(df$value>0), modifyList(a, list(values=cumsum(values)*values))))   
}

val <- df$value
mtd3 <- function() {
    result <- rleidv(val>0)
    result[!(val>0)]<-0
    result[val>0]<-rleidv(result[val>0])   
}

library(data.table)
mtd2 <- function() {
    setDT(df)[, peak := (value > 0) * ceiling(rleid(value > 0) / 2)]
}

library(microbenchmark)
microbenchmark(mtd1(), mtd3(), mtd2(), times=5L)

тайминги:

Unit: milliseconds
   expr        min         lq        mean     median         uq        max neval
 mtd1() 357.755701 375.957301 517.6211210 610.545700 611.407001 632.439902     5
 mtd3() 312.756201 329.190100 385.4440206 329.810201 352.368101 603.095500     5
 mtd2() 181.146901 187.001001 256.8531808 215.238501 221.030000 479.849501     5
0 голосов
/ 04 мая 2018
a=rle(df$value>0)
a$values=cumsum(a$values)*a$values
peak=inverse.rle(a)
peak
[1] 1 1 1 0 0 0 0 2 2 2 2 2 0 0 0 0 3 3 3 3


cbind(df,peak)
             date.time    value peak
1  2016-01-01 00:00:00 2.014956    1
2  2016-01-01 00:03:09 1.613537    1
3  2016-01-01 00:06:18 1.853815    1
4  2016-01-01 00:09:28 0.000000    0
5  2016-01-01 00:12:37 0.000000    0
6  2016-01-01 00:15:47 0.000000    0
7  2016-01-01 00:18:56 0.000000    0
8  2016-01-01 00:22:06 2.386204    2
9  2016-01-01 00:25:15 1.170272    2
10 2016-01-01 00:28:25 1.450873    2
11 2016-01-01 00:31:34 1.549061    2
12 2016-01-01 00:34:44 1.544610    2
13 2016-01-01 00:37:53 0.000000    0
14 2016-01-01 00:41:03 0.000000    0
15 2016-01-01 00:44:12 0.000000    0
16 2016-01-01 00:47:22 0.000000    0
17 2016-01-01 00:50:31 2.231659    3
18 2016-01-01 00:53:41 1.859343    3
19 2016-01-01 00:56:50 2.303311    3
20 2016-01-01 01:00:00 2.135476    3

Делаем это в одной строке:

inverse.rle(with(a<-rle(df$value>0),modifyList(a,list(values=cumsum(values)*values))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...