Расчет по каждой паре из сгруппированных data.frame - PullRequest
2 голосов
/ 15 марта 2019

Мой вопрос касается выполнения вычисления между каждой парой групп в data.frame, я бы хотел, чтобы оно было более векторизованным.

У меня есть data.frame, который состоит из следующих элементов:столбцы: Location, Sample, Var1 и Var2.Я хотел бы найти закрытое совпадение для каждой Sample для каждой пары Location с для Var1 и Var2.

Я могу сделать это для одной пары местоположений как таковой:

df0 <- data.frame(Location = rep(c("A", "B", "C"), each =30), 
                 Sample = rep(c(1:30), times =3),
                 Var1 = sample(1:25, 90, replace =T),
                 Var2 = sample(1:25, 90, replace=T))
df00 <- data.frame(Location = rep(c("A", "B", "C"), each =30), 
                 Sample = rep(c(31:60), times =3),
                 Var1 = sample(1:100, 90, replace =T),
                 Var2 = sample(1:100, 90, replace=T))
df000 <- rbind(df0, df00)
df <- sample_n(df000, 100) # data

dfl <- df %>% gather(VAR, value, 3:4)

df1 <- dfl %>% filter(Location == "A")
df2 <- dfl %>% filter(Location == "B")
df3 <- merge(df1, df2, by = c("VAR"), all.x = TRUE, allow.cartesian=TRUE)
df3 <- df3 %>% mutate(DIFF = abs(value.x-value.y))
result <- df3 %>% group_by(VAR, Sample.x) %>% top_n(-1, DIFF)

Я пробовал другие возможности, такие как использование dplyr::spread, но не смог избежать «Ошибка: дублирующиеся идентификаторы для строк» ​​или столбцы, наполовину заполненные NA.

Существует ли более чистый и автоматизированный способ сделать это для каждой возможной пары групп?Я хотел бы избежать ручного подмножества и процедуры слияния для каждой пары.

1 Ответ

1 голос
/ 15 марта 2019

Один из вариантов - создать попарную комбинацию 'Location' с combn, а затем выполнить другие шаги, как в коде OP

 library(tidyverse)
 df %>% 
    # get the unique elements of Location
    distinct(Location) %>% 
    # pull the column as a vector
    pull %>% 
    # it is factor, so convert it to character
    as.character %>% 
    # get the pairwise combinations in a list
    combn(m = 2, simplify = FALSE) %>%
    # loop through the list with map and do the full_join
    # with the long format data df1
    map(~ full_join(df1 %>% 
                      filter(Location == first(.x)), 
                    df1 %>% 
                      filter(Location == last(.x)), by = "VAR") %>% 
             # create a column of absolute difference
             mutate(DIFF = abs(value.x - value.y)) %>%
             # grouped by VAR, Sample.x
             group_by(VAR, Sample.x) %>%
             # apply the top_n with wt as DIFF
             top_n(-1, DIFF))

Кроме того, как упоминалось в OP об автоматическом подборе вместо двойного filter (хотя и не ясно, ожидаемый результат)

df %>% 
   distinct(Location) %>%
   pull %>%
   as.character %>% 
   combn(m = 2, simplify = FALSE) %>% 
   map(~ df1 %>% 
             # change here i.e. filter both the Locations
             filter(Location %in% .x) %>% 
             # spread it to wide format
             spread(Location, value, fill = 0) %>% 
             # create the DIFF column by taking the differene
             mutate(DIFF = abs(!! rlang::sym(first(.x)) - 
                              !! rlang::sym(last(.x)))) %>% 
             group_by(VAR, Sample) %>% 
             top_n(-1, DIFF))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...