Написание функции для фильтрации и суммирования данных в таблицу пропорций

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

     ID   a   b   c   d   e   f   g
1     1   1   2   3   0   4   5   A 
2     2   0   0   1   0   2   0   A
3     3   1   5   2   1   0   0   B
4     4   5   1   2   0   1   1   B
5     5   2   0   1   0   0   0   C
...

Исходя из этого, я хочу получить пропорцию b=0 или b>0, если столбец a>0. Для справки, я могу получить эту информацию с помощью следующего кода:

prop.table(table(df$b[df$a>0]!=0))*100

Однако я хочу сделать то же самое со столбцами c и d, а также с e и f (такой же шаблон, так что вы отфильтровываете, когда c = 0 и когда e = 0, чтобы получить эти пропорции> 0 и = 0 для г и е соответственно). Кроме того, я хотел бы, чтобы весь этот вывод был в одной таблице. Может выглядеть примерно так:

      b.perc   d.perc   f.perc
TRUE   75.00    20.00    66.67
FALSE  25.00    80.00    33.33

Любая помощь приветствуется. Кроме того, я хотел бы рассчитать ИСТИННЫЕ проценты по группам, перечисленным в столбце G, и получить такой результат:

      b.perc   d.perc   f.perc
A     100.00    0.00     50.00
B     100.00   50.00    100.00
C     0.00      0.00      0.00

person Kfin    schedule 02.07.2019    source источник


Ответы (1)


Мы подмножаем альтернативные столбцы, используем каждый набор в качестве входных данных для mapply, получаем table и prop.table на основе условия, упомянутого в сообщении OP.

out <- round(mapply(function(x, y) prop.table(table(x[y > 0] != 0)) * 100,
          df[c(FALSE, TRUE)], df[c(TRUE, FALSE)]), 2)
colnames(out) <- paste0(colnames(out), ".perc")
out
#      b.perc d.perc f.perc
#FALSE     25     80  33.33
#TRUE      75     20  66.67

Если нас интересует только ИСТИННЫЙ процент, то мы можем сделать это и с colMeans

colMeans((df[c(FALSE, TRUE)] * NA^!(df[c(TRUE, FALSE)] > 0)) != 0, na.rm = TRUE)
#       b         d         f 
#0.7500000 0.2000000 0.6666667 

данные

df <- structure(list(a = c(1L, 0L, 1L, 5L, 2L), b = c(2L, 0L, 5L, 1L, 
0L), c = c(3L, 1L, 2L, 2L, 1L), d = c(0L, 0L, 1L, 0L, 0L), e = c(4L, 
2L, 0L, 1L, 0L), f = c(5L, 0L, 0L, 1L, 0L)), class = "data.frame",
row.names = c("1", 
"2", "3", "4", "5"))
person akrun    schedule 02.07.2019
comment
фрейм данных, который я вам дал, является лишь частью гораздо большего набора данных (около 50 переменных) - как я могу адаптировать этот скрипт для извлечения определенных столбцов из большего набора данных (помимо выбора и создания нового, меньшего фрейма данных)? - person Kfin; 02.07.2019
comment
@Kayla Предполагая, что у вас есть 50 столбцов, а интересующие столбцы — это первые 20 столбцов, затем используйте df1 <- df[, 1:25] и примените коды к набору данных подмножества. - person akrun; 02.07.2019
comment
хорошо - только пробую это с подмножеством (в основном то, что я представил ранее, поэтому всего 6 столбцов), и я сталкиваюсь с этой ошибкой: Ошибка: длина вектора логического индекса для [ должна равняться количеству столбцов (или 1): * .data имеет 6 столбцов * Индексный вектор имеет длину 2 - person Kfin; 02.07.2019
comment
@Кайла В чем ошибка? У вас есть matrix из data.frame ? Пожалуйста, проверьте str(df). каков результат df[c(FALSE, TRUE)] и df[, c(FALSE, TRUE)] - person akrun; 02.07.2019
comment
вывод df[c(FALSE, TRUE)] и df[, c(FALSE, TRUE)] является той же ошибкой, что и раньше (ошибка: длина вектора логического индекса для [ должна равняться количеству столбцов (или 1): * .data имеет 6 столбцов * Индексный вектор имеет длину 2) - person Kfin; 08.07.2019
comment
@Kayla Непонятна структура ваших данных. Если вы можете привести пример и показать ошибку, легче понять, где она не работает. - person akrun; 08.07.2019
comment
извините - я получил его на работу. Проблема была с функцией выбора (dplyr против plyr), когда я создавал новый фрейм данных меньшего размера. Это сработало, спасибо! - person Kfin; 08.07.2019
comment
интересно, не могли бы вы помочь мне использовать этот код, чтобы добавить функцию group_by, чтобы я мог получить таблицу с ИСТИННЫМИ процентами по категориальным переменным (т.е. A, B, B, A, C), расположенным в 7-м столбце. - person Kfin; 08.07.2019
comment
@Kayla Можете ли вы обновить свой пост с ожидаемым результатом. Это основано на столбце f - person akrun; 08.07.2019
comment
обновлено. Добавлен столбец g (но по-прежнему нужны только пропорции, основанные на столбцах a-f) - person Kfin; 08.07.2019
comment
@Кайла Тебе нужно lapply(split(df1[-c(1, 8)], df1$g), function(df) colMeans((df[c(FALSE, TRUE)] * NA^!(df[c(TRUE, FALSE)] > 0)) != 0, na.rm = TRUE)) - person akrun; 08.07.2019
comment
Я столкнулся с ошибкой (ошибка в FUN (слева, справа): нечисловой аргумент бинарного оператора), и я попытался добавить as.numeric() в функцию, чтобы попытаться решить эту проблему, но безуспешно. - person Kfin; 08.07.2019
comment
@kayla Можете ли вы проверить str(df1) Здесь я удалил 1-й и 8-й столбцы, так как это казалось либо символом, либо столбцом идентификатора. Если другие столбцы не являются числовыми, это будет проблемой. - person akrun; 08.07.2019
comment
извините, нашел проблему - немного другой порядок. Еще раз спасибо за вашу помощь - person Kfin; 08.07.2019