Создание df уникальных комбинаций столбцов в R, где порядок не имеет значения - PullRequest
0 голосов
/ 27 января 2020

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

В моем примере «Нет мнения», «Умеренный», «Консервативный» - то же, что и « Консервативный "Нет мнения", "Умеренный", что совпадает с "Умеренным", "Нет мнения", "Консервативный" и т. Д. c. все эти комбинации должны быть представлены одной строкой.

Я видел похожие темы об использовании distinct для домашних и выездных спортивных команд, но я не думаю, что это работает для этой проблемы.

library(tidyverse)

political_spectrum_values = 
  factor(c("Far left",
           "Liberal",
           "Moderate", 
           "Conservative",
           "Far right",
           "No opinion"), 
           ordered = T)


political_groups_of_3 <- 
crossing(first_person = political_spectrum_values, 
         second_person = political_spectrum_values,
         third_person = political_spectrum_values)

Я рассмотрел создание какой-то комбинированной переменной, добавив в эту строку, но я не уверен, как ее взять отсюда

unite(col = "group_composition", c(first_person, second_person, third_person), sep = "_")

РЕДАКТИРОВАТЬ: После более длительной работы с этой проблемой я изменил данные таким образом, чтобы это могло быть проще

crossing(first_person = political_spectrum_values, 
         second_person = political_spectrum_values,
         third_person = political_spectrum_values) %>% 
  mutate(group_n = row_number()) %>% 
  pivot_longer(cols = c(first_person, second_person, third_person), 
               values_to = "ideology", 
               names_to = "group") %>% 
  select(-group)

Ответы [ 4 ]

3 голосов
/ 27 января 2020

Вот трюк, который вы можете использовать. Вместо того, чтобы начинать с имен политических пристрастий, начните с цифр 5 ^ (0: 5). Обратите внимание, что сумма любой комбинации длины-3 будет уникальной, поскольку 3 раза 5 ^ x меньше 5 ^ (x + 1). Таким образом, если вы запустите expand.grid (эквивалент crossing) для трех таких векторов и возьмете суммы строк, то позиции уникальных сумм будут такими же, как позиции уникальных комбинаций имен в вашем результате crossing .

Таким образом, вы можете просто сделать эту однострочную строку:

political_groups_of_3[!duplicated(rowSums(expand.grid(5^(0:5), 5^(0:5), 5^(0:5)))), ]

, которая дает:

#> # A tibble: 56 x 3
#>    first_person second_person third_person
#>    <ord>        <ord>         <ord>       
#>  1 Conservative Conservative  Conservative
#>  2 Conservative Conservative  Far left    
#>  3 Conservative Conservative  Far right   
#>  4 Conservative Conservative  Liberal     
#>  5 Conservative Conservative  Moderate    
#>  6 Conservative Conservative  No opinion  
#>  7 Conservative Far left      Far left    
#>  8 Conservative Far left      Far right   
#>  9 Conservative Far left      Liberal     
#> 10 Conservative Far left      Moderate    
#> # ... with 46 more rows

Является ли это "более элегантным" или просто непрозрачным хаком это дело вкуса, конечно ...

1 голос
/ 27 января 2020

Основной метод R состоит в том, чтобы создать все комбинации political_spectrum_values, принимая 3 за раз, используя expand.grid, sort их по строкам и выбирая уникальные строки.

df <- expand.grid(first_person = political_spectrum_values, 
                  second_person = political_spectrum_values, 
                  third_person = political_spectrum_values)

df[] <- t(apply(df, 1, sort))
unique(df)

При необходимости в виде одной строки

unique(apply(df, 1, function(x) paste0(sort(x), collapse = "_")))
1 голос
/ 27 января 2020

Вот двухэтапное решение с использованием gtools::combinations и paste.

library(gtools)
#Get all combinations with repeats for the political_spectrum_values in groups of 3
combs<-combinations(nlevels(political_spectrum_values),
                            3,
                            as.character(political_spectrum_values),
                            repeats = T)
#Collapse each row in a single entry and convert it into a data.frame
combs<-data.frame(group_composition = apply(combs, 
                                            1, 
                                            function(x) paste(x, collapse = "_")))
0 голосов
/ 27 января 2020

Вот ответ с использованием комбинации обновления и unite. Я оставлю это открытым немного дольше, только если у кого-то есть более элегантное решение

crossing(first_person = political_spectrum_values, 
         second_person = political_spectrum_values,
         third_person = political_spectrum_values) %>% 
  mutate(group_n = row_number()) %>% 
  pivot_longer(cols = c(first_person, second_person, third_person), 
               values_to = "ideology", 
               names_to = "group") %>% 
  select(-group) %>%
  group_by(group_n) %>% 
  arrange(ideology) %>% 
  mutate(person = row_number()) %>% 
  pivot_wider(id_cols = group_n, values_from = ideology, names_from = person) %>% 
  unite(col = "group_composition", c(`1`, `2`, `3`), sep = "_") %>% 
  ungroup() %>% 
  distinct(group_composition)
...