Есть ли лучший способ сделать group_by для каждого значения в списке? - PullRequest
0 голосов
/ 31 октября 2019

Я пытаюсь найти лучший способ перебрать каждый столбец фрейма данных, сгруппировать его по этому столбцу и получить сводку. Вот моя попытка:

library(tidyverse)
data = data.frame(
  a = sample(LETTERS[1:3], 100, replace=TRUE),
  b = sample(LETTERS[1:8], 100, replace=TRUE),
  c = sample(LETTERS[3:15], 100, replace=TRUE),
  d = sample(LETTERS[16:26], 100, replace=TRUE),
  value = rnorm(100)
)

myfunction <- function(x) {
  groupVars <- select_if(x, is.factor) %>% colnames()
  results <- list()
  for(i in 1:length(groupVars)) {
  results[[i]] <- x %>%
    group_by_at(.vars = vars(groupVars[i])) %>%
    summarise(
      n = n()
    ) 
  }
  return(results)
}

test <- myfunction(data)

Функция возвращает:

[[1]]
# A tibble: 3 x 2
  a         n
  <fct> <int>
1 A        37
2 B        34
3 C        29
...
...
...

Мой вопрос, это лучший способ сделать это? Есть ли способ избежать использования цикла for? Могу ли я использовать purrr и map как-то для этого?

Спасибо

Ответы [ 3 ]

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

Можно использовать map

library(tidyverse)
map(data[1:4], ~data.frame(x = {{.x}}) %>% count(x))
#$a
## A tibble: 3 x 2
#  x         n
#  <fct> <int>
#1 A        39
#2 B        32
#3 C        29
#
#$b
## A tibble: 8 x 2
#  x         n
#  <fct> <int>
#1 A        14
#2 B        11
#3 C        16
#4 D        10
#5 E        12
#6 F        10
#7 G        13
#8 H        14
#...

Выход - list. Обратите внимание, что я проигнорировал последний столбец data, так как он здесь не имеет значения.


Если вы хотите, чтобы столбцы в list data.frame s были названы в соответствии ск столбцам из вашего оригинала data мы можем использовать imap

imap(data[1:4], ~tibble(!!.y := {{.x}}) %>% count(!!sym(.y)))
#$a
## A tibble: 3 x 2
#  a         n
#  <fct> <int>
#1 A        23
#2 B        35
#3 C        42
#
#$b
## A tibble: 8 x 2
#  b         n
#  <fct> <int>
#1 A        15
#2 B        10
#3 C        13
#4 D         5
#5 E        19
#6 F         9
#7 G        13
#8 H        16
#...

или использовать tibble::enframe (спасибо @camille)

imap(data[1:4], ~enframe(.x, value = .y) %>% count(!!sym(.y)))
1 голос
/ 31 октября 2019

Вы можете изменить форму данных и группы по столбцу и букве. Это дает вам один фрейм данных вместо их списка, но вы можете получить список, если вы действительно хотите его использовать с split.

set.seed(123)
library(tidyverse)
data = data.frame(
  a = sample(LETTERS[1:3], 100, replace=TRUE),
  b = sample(LETTERS[1:8], 100, replace=TRUE),
  c = sample(LETTERS[3:15], 100, replace=TRUE),
  d = sample(LETTERS[16:26], 100, replace=TRUE),
  value = rnorm(100)
)

data %>%
  pivot_longer(cols = -value, names_to = "column", values_to = "letter") %>%
  group_by(column, letter) %>%
  summarise(n = n())
#> # A tibble: 35 x 3
#> # Groups:   column [4]
#>    column letter     n
#>    <chr>  <fct>  <int>
#>  1 a      A         33
#>  2 a      B         32
#>  3 a      C         35
#>  4 b      A          8
#>  5 b      B         11
#>  6 b      C         12
#>  7 b      D         14
#>  8 b      E          8
#>  9 b      F         17
#> 10 b      G         16
#> # … with 25 more rows

Создано в 2019-10-30 представительный пакет (v0.3.0)

0 голосов
/ 31 октября 2019

Вы можете просто позвонить:

apply(data, 2,table)

Вы можете удалить последний элемент списка, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...