Примените пользовательскую функцию к уровням фактора в кадре данных - PullRequest
1 голос
/ 20 января 2020

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

Рассмотрим следующий тестовый набор данных:

df <- tibble(LINE=rep(c(1,2),each=6), FOUND=c(1,1,1,0,1,1,0,0,1,0,0,1))

#    LINE FOUND
#   <dbl> <dbl>
# 1     1     1
# 2     1     1
# 3     1     1
# 4     1     0
# 5     1     1
# 6     1     1
# 7     2     0
# 8     2     0
# 9     2     1
#10     2     0
#11     2     0
#12     2     1

Я хочу знать, например, долю найденных результатов (например, FOUND == 1) по уровню фактора LINE. Прямо сейчас я работаю со следующим кодом, но я действительно пытаюсь найти что-то более чистое.

# This is the function to calculate the proportion "found"
get_prop <- function (data) {
  tot <- data %>% nrow()
  found <- data %>% dplyr::filter(FOUND==1) %>% nrow
  found / tot
}

# This is the code to generate the expected result
lines <- df$LINE %>% unique %>% sort
v_line <- vector()
v_prop <- vector()
for (i in 1:length(lines)) {
  tot <- df %>% dplyr::filter(LINE==lines[i])
  v_line[i] <- lines[i]
  v_prop[i] <- get_prop(tot)
}
df_line = data.frame(LINE = v_line, CALL = v_prop)

Я ожидал бы, что следующее будет работать, но это не так, так как он возвращает результат для каждого уровня, но численное решение - это решение для всего набора данных, а не для конкретных уровней c:

df %>% dplyr::group_by(LINE) %>% dplyr::summarise(get_prop(.))

РЕДАКТИРОВАТЬ : Обратите внимание, что я ищу является решением для применения пользовательской функции над уровнями фактора в кадре данных. Это не обязательно число или доля вхождений определенного значения, как показано в примере.

РЕДАКТИРОВАТЬ 2 : То есть я ищу решение, которое использует функции get_prop выше. Это не потому, что это лучший способ решения этой конкретной проблемы, а потому, что она более обобщаема

Ответы [ 2 ]

3 голосов
/ 20 января 2020

Если вы хотите применить пользовательскую функцию для группы, вы можете использовать команду group_split. Это разделит ваш фрейм данных на элементы списка. Каждый элемент списка является подмножеством df. Затем вы можете использовать map, чтобы применить свою функцию к каждому уровню (обратите внимание, что вы можете group_split и map за один шаг, используя group_map). Я добавил последнюю строку, чтобы перейти к форме исходного подхода.

df %>% 
  group_by(LINE) %>% 
  group_split() %>% 
  map_dbl(get_prop) %>% 
  tibble(LINE = seq_along(.), CALL = .) # optional to get back to a df
#> # A tibble: 2 x 2
#>    LINE  CALL
#>   <int> <dbl>
#> 1     1 0.833
#> 2     2 0.333

Создано в 2020-01-20 пакетом prex (v0.3.0)

Теперь меня беспокоит то, что group_split удаляет группирующую переменную (я бы предпочел, чтобы она оставалась в качестве имен списка или атрибута). Поэтому, если вы хотите получить в качестве результата тиббл, возможно, имеет смысл заранее сохранить группирующую переменную:

groups <- unique(df$LINE)

df %>% 
  group_by(LINE) %>% 
  group_split() %>% 
  map_dbl(get_prop) %>% 
  tibble(group = groups, result = .)

update

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

library(tidyverse)
df <- tibble(LINE=rep(c("a", "b"),each=6), FOUND=c(1,1,1,0,1,1,0,0,1,0,0,1))

lvls <- unique(df$LINE)

df %>% 
  group_by(LINE) %>% 
  group_map(~ get_prop(.x)) %>% 
  setNames(lvls) %>% 
  unlist() %>% 
  enframe()
#> # A tibble: 2 x 2
#>   name  value
#>   <chr> <dbl>
#> 1 a     0.833
#> 2 b     0.333

Создано в 2020-01-20 пакетом Представить (v0.3.0)

2 голосов
/ 20 января 2020

Другим вариантом может быть использование group_map, а затем tibble::enframe

library(dplyr)

df %>% 
group_by(LINE) %>% 
group_map(~get_prop(.)) %>% 
unlist() %>% 
tibble::enframe()

#  name value
#  <int> <dbl>
#1     1 0.833
#2     2 0.333

Вы также можете использовать group_modify, который будет хранить имена групп (используя данные @ JBGruber)

df %>%
    group_by(LINE) %>%
    group_modify(~ tibble::enframe(get_prop(.), name = NULL))

# LINE  value
#  <chr> <dbl>
#1 a     0.833
#2 b     0.333
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...