Вложенные тиблы и выполнение вычислений на каждом с group_by - PullRequest
0 голосов
/ 18 февраля 2020

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

Сценарий ниже делает то, что я хочу, но он выглядит довольно неуклюжим и слишком сложным. Я не очень много работал с вложенными данными, поэтому не уверен, что использовал самые лучшие методы. Кто-нибудь может придумать более удобный способ достижения того же результата в tidyverse или data.table?

Спасибо!

library(tidyverse)

# sample data
set.seed(123)
input <- tibble(id_a = c(letters[seq(1,10)]),
                size = runif(10, min = 10, max = 50),
                class = c("x","x","y","x","y",
                          "y","x","y","x","x"),
                id_b = c("A1","A1","B1","B1","B1",
                         "C1","C1","C1","D1","E1"))
print(input)

   id_a   size class id_b 
   <chr> <dbl> <chr> <chr>
 1 a      23.6 x     A1   
 2 b      43.6 x     A1   
 3 c      23.9 y     B1   
 4 d      23.4 x     B1   
 5 e      29.1 y     B1   
 6 f      45.7 y     C1   
 7 g      44.6 x     C1   
 8 h      25.6 y     C1   
 9 i      41.1 x     D1   
10 j      48.4 x     E1 
# nest input to create a nested tibble for each id_b
input_nest <- input %>% group_by(id_b) %>% nest()

# calculate dominant class
input_nest_dominant <- input_nest %>% mutate(DOMINANT_CLASS = lapply(data, function(x){
  # group each nested tibble by class, and calculate total size. Then find the biggest size and extract 
  # the class value
  output <- x %>% group_by(class) %>% 
            summarise(total_size = sum(size)) %>% 
            top_n(total_size, n = 1) %>% 
            pull(class)
  return(output)
} ))

# unnest to end up with a tibble
input_nest_dominant_clean <- input_nest_dominant %>% 
                             unnest(cols = c(DOMINANT_CLASS)) %>% 
                             select(-data) %>% 
                             ungroup()


print(input_nest_dominant_clean)
  id_b  DOMINANT_CLASS
  <chr> <chr>         
1 A1    x             
2 B1    y             
3 C1    y             
4 D1    x             
5 E1    x 

Ответы [ 3 ]

3 голосов
/ 18 февраля 2020

Из этого примера вам вообще не нужно nest, просто рассчитайте его, используя group_by и summarize.


input %>%
  group_by(id_b, class) %>%
  summarize(size = sum(size)) %>%
  group_by(id_b) %>%
  summarize(DOMINANT_CLASS = class[which.max(size)])
#> # A tibble: 5 x 2
#>   id_b  DOMINANT_CLASS
#>   <chr> <chr>         
#> 1 A1    x             
#> 2 B1    y             
#> 3 C1    y             
#> 4 D1    x             
#> 5 E1    x
0 голосов
/ 18 февраля 2020

Вы можете сделать только 1 сортировку и удалить все дубликаты. Что-то вроде:

input %>% arrange(desc(size)) %>% filter(!duplicated(id_b)) %>% arrange(id_b)

# A tibble: 5 x 4
  id_a   size class id_b 
  <chr> <dbl> <chr> <chr>
1 b      41.5 x     A1   
2 e      47.6 y     B1   
3 h      45.7 y     C1   
4 i      32.1 x     D1   
5 j      28.3 x     E1  

Если порядок id_b не важен, вы можете опустить последний arrange

Или в базе R:

input = input[order(-input$size),]
input[!duplicated(input$id_b),]
0 голосов
/ 18 февраля 2020

Вот базовое решение R, в котором дважды использовалось aggregate, т. Е.

agg <-aggregate(size ~ class + id_b, input, FUN = sum)
output <- aggregate(agg[-2],agg[2],FUN = max)[-3]

или более компактная версия

output <- aggregate(.~id_b,
                    aggregate(size ~ class + id_b, 
                              input, 
                              FUN = function(v) sum(v)),
                    FUN = function(v) tail(sort(v),1))[-3]

такая, что

> output
  id_b class
1   A1     x
2   B1     y
3   C1     y
4   D1     x
5   E1     x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...