Função semelhante a group_by quando os grupos não são mutuamente excludentes
Eu gostaria de criar uma função em R, semelhante adplyr
égroup_by
função, que quando combinada comsummarise
pode fornecer estatísticas resumidas para um conjunto de dados em quea associação ao grupo não é mutuamente exclusiva. Ou seja, as observações podem pertencer a vários grupos. Uma maneira de pensar sobre isso pode ser considerar as tags; as observações podem pertencer a uma ou mais tags que podem se sobrepor.
Por exemplo, pegue R'sesoph
conjunto de dados (https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/esoph.html) documentando um estudo caso-controle de câncer de esôfago. Suponha que eu esteja interessado no número e na proporção de casos de câncer em geral e por 'etiqueta', onde as etiquetas têm: 65 anos ou mais; 80+ g / dia de álcool; 20+ gm / dia de tabaco; e um grupo de 'alto risco' em que os três critérios anteriores foram atendidos. Vamos transformar o conjunto de dados em formato longo (um participante por linha) e depois adicionar essas tags (colunas lógicas) ao conjunto de dados:
library('dplyr')
data(esoph)
esophlong = bind_rows(esoph %>% .[rep(seq_len(nrow(.)), .$ncases), 1:3] %>% mutate(case=1),
esoph %>% .[rep(seq_len(nrow(.)), .$ncontrols), 1:3] %>% mutate(case=0)
) %>%
mutate(highage=(agegp %in% c('65-74','75+')),
highalc=(alcgp %in% c('80-119','120+')),
hightob=(tobgp %in% c('20-29','30+')),
highrisk=(highage & highalc & hightob)
)
Minha abordagem usual é criar um conjunto de dados em que cada observação seja duplicada para cada tag a que pertence e, em seguida,summarise
este conjunto de dados:
esophdup = bind_rows(esophlong %>% filter(highage) %>% mutate(tag='age>=65'),
esophlong %>% filter(highalc) %>% mutate(tag='alc>=80'),
esophlong %>% filter(hightob) %>% mutate(tag='tob>=20'),
esophlong %>% filter(highrisk) %>% mutate(tag='high risk'),
esophlong %>% filter() %>% mutate(tag='all')
) %>%
mutate(tag=factor(tag, levels = unique(.$tag)))
summary = esophdup %>%
group_by(tag) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case))
Essa abordagem é ineficiente para grandes conjuntos de dados ou para um grande número de tags, e geralmente ficarei sem memória para armazená-lo.
Uma alternativa ésummarise
cada tag separadamente e vincule esses conjuntos de dados de resumo posteriormente, da seguinte maneira:
summary.age = esophlong %>%
filter(highage) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
mutate(tag='age>=65')
summary.alc = esophlong %>%
filter(highalc) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
mutate(tag='alc>=80')
summary.tob = esophlong %>%
filter(hightob) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
mutate(tag='tob>=20')
summary.highrisk = esophlong %>%
filter(highrisk) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
mutate(tag='high risk')
summary.all = esophlong %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
mutate(tag='all')
summary=bind_rows(summary.age,summary.alc,summary.tob,summary.highrisk,summary.all)
Essa abordagem é demorada e tediosa quando tenho um grande número de tags ou desejo reutilizá-las frequentemente para diferentes medidas de resumo em um projeto.
A função que tenho em mente, digamosgroup_by_tags(data, key, ...)
, que inclui um argumento para especificar o nome da coluna de agrupamento, deve funcionar da seguinte maneira:
summary = esophlong %>%
group_by_tags(key='tags',
'age>=65'=highage,
'alc>=80'=highalc,
'tob>=20'=hightob,
'high risk'=highrisk,
'all ages'=1
) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case))
com o conjunto de dados de resumo parecido com este:
> summary
tags n ncases case.rate
1 age>=65 273 68 0.2490842
2 alc>=80 301 96 0.3189369
3 tob>=20 278 64 0.2302158
4 high risk 11 5 0.4545455
5 all 1175 200 0.1702128
Melhor ainda, poderia levar variáveis do tipo "fator" e também "lógicas" para resumir, por exemplo, cada faixa etária individualmente, as pessoas com mais de 65 anos e todos:
summaryage = esophlong %>%
group_by_tags(key='Age.group',
agegp,
'65+'=(agegp %in% c('65-74','75+')),
'all'=1
) %>%
summarise(n=n(), ncases=sum(case), case.rate=mean(case))
>summaryage
Age.group n ncases case.rate
1 25-34 117 1 0.0085470
2 35-44 208 9 0.0432692
3 45-54 259 46 0.1776062
4 55-64 318 76 0.2389937
5 65-74 216 55 0.2546296
6 75+ 57 13 0.2280702
7 65+ 273 68 0.2490842
8 all 1175 200 0.1702128
Talvez não seja possível com...
e, em vez disso, pode ser necessário passar um vetor / lista de nomes de colunas para as tags.
Alguma ideia?
EDIT: para ficar claro, a solução deve usar as definições de tags / grupos e as estatísticas de resumo necessárias como argumentos, em vez de serem incorporadas à própria função. Ou em duas etapasdata %>% group_by_tags(tags) %>% summarise_tags(stats)
ou uma etapadata %>% summary_tags(tags,stats)
processo.