У меня есть таблица из 60 столбцов со значениями в каждом столбце, например: ДА, НЕТ, NA, NP.

    A   B   C
1  YES NO  NO
2  NA  NA  NA
3 YES NO  YES
4  NP  NP  NP

Мне нужно вычислить несколько пропорций, каждая со своим знаменателем:

Пример:
Процент ДА против ДА и НЕТ (YES / (YES + NO))
Процент НП против всех, кроме НП (NP / (YES + NO + NP))
Процент NA против всех (NA / rows)

Желаемый результат из фрейма данных выше:

%YES.A  %NP.A  %NA.A  %YES.B
  100%    33%    25%    0%

Что я пробовал на данный момент:
Попытка использовать dplyr с mutate, но необходимо создать 7 дополнительных столбцов для каждого из 60 столбцов. Четыре для каждого значения и три для каждого процента.

Пробовал revalue, но та же проблема - слишком много столбцов

mydata$A.NO <- revalue(mydata$A, c("NO" = 1))  
mydata$A.YES <- revalue(mydata$A,c("YES" = 1)) 

Надеюсь, что кто-то может помочь мне найти лучшее решение или любую библиотеку, которую я должен прочитать.

1
ErickOGM 28 Фев 2016 в 23:55

3 ответа

Лучший ответ

Первый шаг, который я бы сделал, - преобразовать данные в длинный формат, а затем вычислить проценты по группам:

library(dplyr)
library(tidyr)

mydf %>% 
  gather(key, val) %>%
  group_by(key) %>% 
  summarise(pYes = 100*sum(val=="YES",na.rm=TRUE)/sum(val %in% c("YES","NO"),na.rm=TRUE),
            pNP = 100*sum(val=="NP",na.rm=TRUE)/sum(val %in% c("YES","NO","NP"),na.rm=TRUE),
            pNA = 100*sum(is.na(val))/n())

Который дает:

Source: local data frame [3 x 4]

    key  pYes      pNP   pNA
  (chr) (dbl)    (dbl) (dbl)
1     A   100 33.33333    25
2     B     0 33.33333    25
3     C    50 33.33333    25

Вы можете преобразовать этот результат в тот же формат, что и ниже, добавив gather(percentage, val, -key) в качестве последнего шага.


Вы можете сделать это, сначала суммируя, а затем преобразовав в длинный формат:

mydf %>% 
  summarise_each(funs(pYes = sum(.=="YES",na.rm=TRUE)/sum(.%in% c("YES","NO"),na.rm=TRUE),
                      pNP = 100*sum(.=="NP",na.rm=TRUE)/sum(. %in% c("YES","NO","NP"),na.rm=TRUE),
                      pNA = 100*sum(is.na(.))/n())) %>%
  gather(key, val) %>%
  separate(key, c("column","percentage"), sep="_")

Который дает:

  column percentage       val
1      A       pYes 100.00000
2      B       pYes   0.00000
3      C       pYes  50.00000
4      A        pNP  33.33333
5      B        pNP  33.33333
6      C        pNP  33.33333
7      A        pNA  25.00000
8      B        pNA  25.00000
9      C        pNA  25.00000
2
Jaap 29 Фев 2016 в 07:35

Преобразование фрейма данных в таблицу данных ускоряет работу примерно на 50%.

dt <- data.table(df)
dt[, sapply(.SD, myfun)]

Df - это исходный фрейм данных, а myfun - это следующая функция, предоставляемая Heroka:

myfun <- function(x){
  res <- c(YES=sum(x=="YES",na.rm=T)/sum(x %in% c("YES","NO"),na.rm=T),
                    NP=sum(x=="NP",na.rm=T)/length(na.omit(x)))
  res
}
1
Erol 28 Фев 2016 в 22:02

Вот решение для вас в base-R. Поскольку вам нужны только итоговые показатели, нет необходимости создавать новые столбцы. Мы просто создаем новый объект сводных данных.

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

myfun <- function(x){
  res <- c(YES=sum(x=="YES",na.rm=T)/sum(x %in% c("YES","NO"),na.rm=T),
                    NP=sum(x=="NP",na.rm=T)/length(na.omit(x)))
  res
}

Затем мы просто применяем эту функцию ко всем нашим столбцам, используя lapply:

res <- lapply(dat, myfun)

Это дает нам список векторов (вы можете легко изменить что-то в функции; вы хотите список, вектор, фрейм данных или data.table?)

Мы можем их комбинировать:

do.call(rbind,res)
  YES        NP
A 1.0 0.3333333
B 0.0 0.3333333
C 0.5 0.3333333
1
Heroka 28 Фев 2016 в 21:12