Подсчитать количество каждого фактора, группирующегося по другому фактору - PullRequest
2 голосов
/ 16 апреля 2019

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

У меня есть столбец с именем Data_source, по которому я хочу сгруппировать переменные.

У меня есть ряд symptom* переменных, где я хочу подсчитать согласно Data_source.

Почему-то я не могу понять, как это сделать. Нормальные функции group_by не работают должным образом.

Вот этот фрейм данных

 df <- wrapr::build_frame(
   "Data_source"  , "Sex"   , "symptoms_decLOC", "symptoms_nausea_vomitting" |
     "1"          , "Female", NA_character_    , NA_character_               |
     "1"          , "Female", NA_character_    , NA_character_               |
     "1"          , "Female", "No"             , NA_character_               |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "1"          , "Male"  , "Yes"            , "No"                        |
     "1"          , "Female", "Yes"            , "No"                        |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", "Yes"            , "No"                        |
     "2"          , "Female", "Yes"            , "No"                        |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               |
     "2"          , "Male"  , NA_character_    , NA_character_               |
     "2"          , "Female", NA_character_    , NA_character_               )

Обратите внимание, что пол и переменные симптомов - это все факторы, которые включают НС. Я попытался следующее

df %>% na.omit() %>% group_by(Data_source) %>% count("symptoms_decLOC")

Что не работает и является менее чем оптимальным, потому что мне пришлось бы повторять это для каждого столбца. Идеально было бы использовать что-то похожее на lapply(df, count), но это не дает мне описания для каждой группы.

EDIT

В ответ на вопрос ниже я добавил ожидаемый результат. Я отредактировал это в Excel, цветовое кодирование group_by для ясности.

enter image description here

Обратите внимание, как я получаю перерыв для каждого возможного ответа. Когда я запускаю это, используя dplyr, вот вывод.

> df %>% na.omit() %>% group_by(Data_source) %>% count("symptoms_decLOC")
# A tibble: 2 x 3
# Groups:   Data_source [2]
  Data_source `"symptoms_decLOC"`     n
  <chr>       <chr>               <int>
1 1           symptoms_decLOC         5
2 2           symptoms_decLOC         2

Ответы [ 3 ]

1 голос
/ 24 апреля 2019

Это получается в большинстве случаев: еще не выяснили, как включить группы с нулевым счетом ... якобы добавление .drop = FALSE позаботится об этом , но это не работает для меня (используя dplyr v. 0.8.0.9001).

library(dplyr)
library(tidyr)
(df
    %>% tidyr::gather(var,val,-Data_source)
    %>% count(Data_source,var,val, .drop=FALSE)
    %>% na.omit()
)

Результаты:

  Data_source var                       val        n
  <chr>       <chr>                     <chr>  <int>
1 1           Sex                       Female     7
2 1           Sex                       Male       1
3 1           symptoms_decLOC           No         1
4 1           symptoms_decLOC           Yes        5
5 1           symptoms_nausea_vomitting No         5
6 2           Sex                       Female     6
7 2           Sex                       Male       6
8 2           symptoms_decLOC           Yes        2
9 2           symptoms_nausea_vomitting No         2
1 голос
/ 24 апреля 2019

Использование ответа @Ben Bolker для получения подсчета для каждой группы, использование spread и gather для включения групп с нулевым счетом.

dplyr

library(dplyr)
library(tidyr)

# Count number of occurences by Data_source 
df2 <- 
  df %>% 
  gather(variable, value, -Data_source) %>% 
  count(Data_source, variable, value, name = "counter") %>%
  na.omit() 

# For variable = "Sex", leave as is
# For everything else, in this case symptom* convert into factor to include zero count group
# Then spread with dataframe will NAs filled with 0, re-convert back to long to bind rows
bind_rows(df2 %>%
            filter(variable == "Sex"), 

          df2 %>%
            filter(variable != "Sex") %>%
            mutate(value = factor(value, levels = c("Yes", "No"))) %>%
            spread(key = value, value = counter, fill = 0) %>%
            gather(value, counter, -Data_source, -variable))  %>%

  arrange(Data_source, variable)

data.table

library(data.table)
dt <- data.table(df)

# Melt data by Data source
dt_melt <- melt(dt, id.vars = "Data_source", value.factor = FALSE, variable.factor = FALSE)

# Add counter, if NA then 0 else 1
dt_melt[, counter := 0]
dt_melt[!is.na(value), counter := 1]

# Sum number of occurrences
dt_count <- dt_melt[,list(counter = sum(counter)), by = c("Data_source", "variable", "value")]

# Split into two dt
dt2a <- dt_count[variable == "Sex", ]
dt2b <- dt_count[variable != "Sex" ,]

# only on symptoms variables
# Convert into factor variable
dt2b$value <- factor(dt2b$value, levels = c("Yes", "No"))
dt2b_dcast <- dcast(data = dt2b, formula = Data_source + variable ~ value, value.var = "counter", fill = 0, drop = FALSE)
dt2b_melt <- melt(dt2b_dcast, id.vars = c("Data_source", "variable"), variable.name = "value", value.name = "counter") 

# combine
combined_d <- rbind(dt2a, dt2b_melt)
combined_d[order(Data_source, variable), ]
0 голосов
/ 17 апреля 2019

Я не совсем понимаю, о чем вы спрашиваете, но я полагаю, что вы хотите подсчитать количество не-NA значений в каждом из ваших symptom_* столбцов.

Это data.table решение:

# load library

library(data.table)

# Suppose the table is called "dt". Convert it to a data.table:

setDT(dt)

# convert the wide table to a long one, filter the values that
# aren't NA and count both, by Data_source and by variable
# (variable is the created column with the symptom_* names)

melt(dt, id.vars = 1:2)[!is.na(value), 
                        .N, 
                         by = .(Data_source, variable)]

Что делает каждая часть кода:

melt(dt, id.vars = 1:2) преобразует dt из широкого в длинный и сохраняет столбцы 1 и 2 (Data_source и sex) фиксированными.

!is.na(value) фильтрует значения (которые ранее были под каждым заголовком symptom_*), которые не являются NA.

.N считает строки.

by = .(Data_source, variable) - это группа, которую мы используем для подсчета. variable - это имя столбца, в котором symptom_* приземлился во время изменения формы.

...