R: сгруппируйте каждый столбец отдельно, затем посчитайте по группам (повторите для всех столбцов в наборе данных)

#r

Вопрос:

Так что я возвращаюсь в R через некоторое время и обнаруживаю, что немного заржавел здесь. Я осмотрелся, но, похоже, не могу найти способ сделать это.

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

Приведенное ниже дает мне то, что я хочу для одной колонки (в данном случае a). Тем не менее, я не могу придумать лучший способ воспроизвести это в нескольких столбцах, где каждый столбец сгруппирован сам по себе, поэтому b по b, c по c, d по d и т. Д., Не делая все это вручную. Где конечным результатом будет one_col, но со многими строками.

 #data
a<- rep(1:5, 5) 
b <- rep(1:5, 5) 
c <- rep(1:5, 5) 
d <- rep(1:5, 5) 
df <- data.frame(a=a, b=b, c=c, d=d)

head(df)

#example analysis on one column
library(tidyverse)
one_col<-df%>%
  group_by(a)%>%
  summarise(count=n())%>%
  spread(a, count)%>%
  mutate(sum=rowSums(.[1:5]), neg=(`1` `2`)/sum, pos=(`4` `5`)/sum, neut=`3`/sum)%>%
  select(pos, neg, neut)

one_col
 

Я думал о том, чтобы сделать цикл for, но боролся с его форматированием. Есть какие-нибудь идеи?

 
for(i in 1:ncol(df)) {       
  group_by(!!df[i,])%>%
    summarise(count=n())
}
 

Спасибо!

Ответ №1:

Вот два подхода, использующих цикл и purrr::map_dfr() .

 library(tidyverse)
df1 <- df |> 
  mutate(across(a:d, ~ case_when(
    . %in% c(1, 2) ~ "neg",
    . %in% c(4, 5) ~ "pos",
    . == 3 ~ "neut"
  )))

# FOR LOOP
l <- vector("list", ncol(df1))
for (i in seq_along(df1)) {
  l[[i]] <- table(df1[[i]]) |> 
    prop.table() |> 
    as.data.frame()
}

l |> 
  setNames(names(df1)) |> 
  bind_rows(.id = "var") |> 
  pivot_wider(id_cols = var, names_from = Var1, values_from = Freq)

# map_dfr()
df1 |> 
  map_dfr(
    ~ table(.x) |> 
      prop.table() |> 
      as.data.frame(),
    .id = "var"
  ) |> 
  pivot_wider(id_cols = var, names_from = .x, values_from = Freq)

# var     neg  neut   pos
# <chr> <dbl> <dbl> <dbl>
# 1 a       0.4   0.2   0.4
# 2 b       0.4   0.2   0.4
# 3 c       0.4   0.2   0.4
# 4 d       0.4   0.2   0.4
 

Комментарии:

1. Блестяще, спасибо! решение map_dfr-это именно то, что я искал, но не смог найти.