Агрегировать кадр данных с вычислением по одному столбцу - PullRequest
1 голос
/ 22 марта 2019

Мой исходный фрейм данных выглядит так:

library(tidyverse)

df <- tibble::tribble(
        ~element,     ~label, ~value,
            "aa", "sessions",    196,
            "bb", "sessions",    865,
            "aa",    "begin",     59,
            "bb",    "begin",    123,
            "aa", "complete",      5,
            "bb", "complete",      5
        )

Я хочу агрегировать как, в новом фрейме данных:

  • для каждой строки будет содержать столбец, содержащий отношение

    1. начало / сеансы
    2. завершение / сеансы

для каждого элемента aa и bb.

выглядит как:

df_agg <- tibble::tribble(
                          ~label_2,         ~aa,         ~bb,
               "begin_to_sessions", 0.301020408, 0.142196532,
            "complete_to_sessions", 0.005780347, 0.005780347
            )

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Это можно сделать с помощью первого spread этого в «широкий» формат, получить отношения, gather в «длинный» формат и spread обратно в «широкий» формат

library(tidyverse)
df %>% 
    spread(label, value) %>%
    transmute(element,
              begin_to_sessions = begin/sessions, 
              complete_to_sessions = complete/sessions) %>% 
    gather(label_2, val, -element) %>% 
    spread(element, val)

Или используя mutate_at (в случае, если имеется много столбцов)

df %>% 
    spread(label, value) %>% 
    mutate_at(vars(begin, complete), list(~ ./sessions)) %>% 
    select(-sessions) %>% 
    rename_at(vars(begin, complete), ~ paste0(., "_to_sessions")) %>% 
    gather(label_2, val, -element) %>% 
    spread(element, val)
# A tibble: 2 x 3
#  label_2                  aa      bb
#  <chr>                 <dbl>   <dbl>
#1 begin_to_sessions    0.301  0.142  
#2 complete_to_sessions 0.0255 0.00578

Мы также можем избежать многократного gather/spread, выполнив деление group_by, извлекая соответствующее значениев строку 'session' в 'label', filter выводим строки, содержащие 'session' в 'label', а затем делаем один spread в конце

df %>%
  group_by(element) %>% 
  mutate(value = value/value[label ==  "sessions"]) %>% 
  ungroup %>%
  filter(label != "sessions") %>% 
  transmute(element, value, label2 = paste0(label, "_to_sessions")) %>% 
  spread(element, value)
0 голосов
/ 22 марта 2019

С tidyverse вы также можете сделать:

df %>%
 filter(label != "sessions") %>%
 full_join(df %>%
 filter(label == "sessions"), by = c("element" = "element")) %>%
 group_by(element, label.x) %>%
 transmute(label = paste(label.x, "to", label.y, sep = "_"),
           res = value.x/value.y) %>%
 ungroup() %>%
 select(-label.x) %>%
 spread(element, res)

  label                    aa      bb
  <chr>                 <dbl>   <dbl>
1 begin_to_sessions    0.301  0.142  
2 complete_to_sessions 0.0255 0.00578
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...