Как применять функции последовательно с мурлыканием и трубами - PullRequest
2 голосов
/ 12 июня 2019

Я борюсь с пакетом мурлыканья.

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

Я пробовал несколько вариантов modify_if и summarise_if. Я предполагаю, что неправильно использую точки (.) При вызове предыдущего объекта.

(Руководство по мурлыканью и точкам было бы очень полезно, если у вас есть ссылка).

Например,

df <- data.frame(f1 = c("men", "woman", "men", "men"), 
                 f2 = c("high", "low", "low", "low"), 
                 n1 = c(1, 3, 3, 6))

Тогда

map(df, is.factor)

Если я использую

map_if(df, is.factor, forcats::fct_count)

Я получил результаты для каждой переменной, а не только для факторов.

Я думаю, что это довольно простая проблема, и с небольшим пониманием точек (.) Ее можно решить.

Заранее спасибо :)

Ответы [ 2 ]

1 голос
/ 12 июня 2019

Проблема с map_if / modify_if заключается в том, что она применяет функцию только к тем столбцам, которые удовлетворяют функции предиката, а остальные из них возвращаются как есть.

Следовательно, при попытке

library(tidyverse)  
map_if(df, is.factor, forcats::fct_count)

#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

#$n1
#[1] 1 3 3 6

fct_count применяется к столбцам f1 и f2, которые являются факторами, и столбец n1 возвращается как есть.Если вы хотите получить только выходные столбцы фактора, одним из них будет сначала select их, а затем применить функцию

df %>%
  select_if(is.factor) %>%
  map(forcats::fct_count)

#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3
1 голос
/ 12 июня 2019

Проблема в том, что map_if также возвращает неизмененные столбцы.Следовательно, когда OP пытается код (повторяя тот же код, что и в OP, чтобы показать)

map_if(df, is.factor, forcats::fct_count)
#$f1
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

#$n1
#[1] 1 3 3 6  ### it is the same column value unchanged

Здесь мы можем указать .else и discard элементы NULL.Таким образом, если мы укажем другие столбцы для возврата NULL и затем используем discard NULL элементов, это будет list коэффициентов.

library(tidyverse)
map_if(df, is.factor, forcats::fct_count, .else = ~ NULL) %>%
       discard(is.null)
#$f1
## A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 men       3
#2 woman     1

#$f2
# A tibble: 2 x 2
#  f         n
#  <fct> <int>
#1 high      1
#2 low       3

Или другой вариант - summarise_if и поместите вывод в list

df %>% 
      summarise_if(is.factor, list(~ list(fct_count(.)))) %>%
      unclass

Или другой вариант - gather в«длинный» формат и затем count один раз

gather(df, key, val, f1:f2) %>% 
        dplyr::count(key, val)

Или это можно сделать с помощью lapply из base R

lapply(df[sapply(df, is.factor)], fct_count)

или с использованием только base R

lapply(df[sapply(df, is.factor)], table)

Или результаты могут быть представлены по-другому

table(names(df)[1:2][col(df[1:2])], unlist(df[1:2]))
...