Вычисление частоты значений по столбцам в R

#r #dplyr #frequency

Вопрос:

Кто-нибудь знает, как заменить значение ячейки частотой, с которой это значение встречается в столбце? Я пытаюсь превратить фрейм данных, полный меток пород и факторов для генов, в диаграмму частот (с целью позже выяснить, имеют ли животные, у которых общие аллели для одного гена, как правило, общие аллели и для других генов). В качестве примера мой начальный фрейм данных выглядит следующим образом:

 Breed Gene A Gene B Gene C Collie 3 5 8 Collie 5 7 2 Lab 3 3 1 Pug 3 7 8 Pug 3 7 9 Pug 4 4 9  

И я бы хотел, чтобы результат выглядел так:

 Breed Gene A Gene B Gene C 2 4 1 2 2 1 3 1 1 4 1 1 3 4 3 1 3 4 3 2 3 1 1 2  

Я вижу, как это сделать, используя цикл for (создайте новый фрейм данных, зацикливайтесь на каждом столбце, зацикливайтесь на каждой строке, меняйте каждое значение на счетчик, который увеличивается на единицу, когда он встречает равное значение), но есть ли более простой и эффективный подход apply или dplyr? Набор данных большой, и мне придется часто повторять это, и я обеспокоен тем, что вложенные циклы будут слишком медленными.

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

1. Чтобы визуально проверить данные, возможно, попробуйте построить их на графике: image(sapply(df, function(i) as.integer(as.factor(i))))

Ответ №1:

Вот базовый вариант R —

 replace_value_by_count lt;- function(x) ave(x, x, FUN = length) df[] lt;- lapply(df, replace_value_by_count) df  # Breed GeneA GeneB GeneC #1 2 4 1 2 #2 2 1 3 1 #3 1 4 1 1 #4 3 4 3 2 #5 3 4 3 2 #6 3 1 1 2  

Поскольку вы пометили dplyr , ту же функцию также можно использовать с помощью dplyr .

 library(dplyr) df lt;- df %gt;% mutate(across(.fns = replace_value_by_count))  

данные

 df lt;- structure(list(Breed = c("Collie", "Collie", "Lab", "Pug", "Pug",  "Pug"), GeneA = c(3L, 5L, 3L, 3L, 3L, 4L), GeneB = c(5L, 7L,  3L, 7L, 7L, 4L), GeneC = c(8L, 2L, 1L, 8L, 9L, 9L)),  class = "data.frame", row.names = c(NA, -6L))  

Ответ №2:

Мы можем использовать base R

 df[] lt;- lapply(df, function(x) table(x)[as.character(x)])  

-выход

 gt; df  Breed GeneA GeneB GeneC 1 2 4 1 2 2 2 1 3 1 3 1 4 1 1 4 3 4 3 2 5 3 4 3 2 6 3 1 1 2  

Или с помощью tidyverse

 library(dplyr) df %gt;%  mutate(across(everything(), ~ tibble(col1 = .x) %gt;%   add_count(col1) %gt;%   pull(n)))  Breed GeneA GeneB GeneC 1 2 4 1 2 2 2 1 3 1 3 1 4 1 1 4 3 4 3 2 5 3 4 3 2 6 3 1 1 2  

данные

 df lt;- structure(list(Breed = c("Collie", "Collie", "Lab", "Pug", "Pug",  "Pug"), GeneA = c(3L, 5L, 3L, 3L, 3L, 4L), GeneB = c(5L, 7L,  3L, 7L, 7L, 4L), GeneC = c(8L, 2L, 1L, 8L, 9L, 9L)),  class = "data.frame", row.names = c(NA,  -6L))