Как сгруппировать данные в предварительно не определенные интервалы, используя R и dplyr? - PullRequest
1 голос
/ 01 октября 2019

У меня есть данные такого рода (очевидно, упрощенно):

Var1 Var2 Var3
20   0.4  a
50   0.5  a
80   0.6  b
150  0.3  a
250  0.4  b

Я хочу сгруппировать их в соответствии с Var1, если они попадают в интервал 50, затем получить среднее значение Var1 и Var2, иоставьте Var3 как есть, если он однородный, или переименуйте его, если группа имеет смешанные метки. В этом случае я получу:

Var1 Var2 Var3
50   0.5  mixed
150  0.3  a
250  0.4  b

Я предполагаю, что мне следует использовать функцию group_by из пакета dplyr, но я не знаю, как именно. Спасибо за вашу помощь!

Ответы [ 2 ]

2 голосов
/ 01 октября 2019

Другая dplyr возможность может быть:

df %>%
 group_by(grp = cumsum(Var1 - lag(Var1, default = first(Var1)) > 50)) %>%
 summarise(Var1 = mean(Var1),
           Var2 = mean(Var2),
           Var3 = ifelse(n_distinct(Var3) > 1, "mixed", Var3)) %>%
 ungroup() %>%
 select(-grp)

   Var1  Var2 Var3 
  <dbl> <dbl> <chr>
1    50   0.5 mixed
2   150   0.3 a    
3   250   0.4 b  
1 голос
/ 01 октября 2019

вот кадр данных с dput

d <- structure(list(Var1 = c(20L, 50L, 80L, 150L, 250L), Var2 = c(0.4, 
0.5, 0.6, 0.3, 0.4), Var3 = structure(c(1L, 1L, 2L, 1L, 2L), .Label = c("a", 
"b"), class = "factor")), class = "data.frame", row.names = c(NA, 
-5L))

Я бы

  1. создал несколько временных столбцов, чтобы определить, когда новая группа начинает
  2. группуи вычислить среднее значение, но также отследить различные значения изменения Var3
  3. , чтобы смешать, если более чем одно значение Var3 в группе

в тидиверсе, это может выглядеть как

d %>% 
 # make sure we sort Var1
 arrange(Var1) %>% 
 # increment var1 by 50 and test that against the next row
 # if the next value exceeds current by 50, we mark it as a new group
 mutate(nextint=Var1+50, 
       newgroup=Var1>lag(nextint,default=-Inf), 
       grp=cumsum(newgroup)) %>%
 # for each group, get the mean and a comma separated list of distinct Var3 values
 group_by(grp) %>% 
 summarise(
           grplbl=floor(max(Var1)/50)*50,
           mu=mean(Var2), 
           mix=paste(collapse=",",unique(Var3))) %>%
 # if mix (distinct Var3) has a comma in it, change from e.g. 'a,b' to 'mix'
 mutate(mix=ifelse(grepl(',', mix), 'mixed', mix))
# A tibble: 3 x 4
    grp grplbl    mu mix  
  <int>  <dbl> <dbl> <chr>
1     1     50   0.5 mixed
2     2    150   0.3 a    
3     3    250   0.4 b  
...