Хотя этот вопрос имеет принятый ответ , я хотел бы предложить другой подход, который использует dplyr
и tidyr
, а также вариант data.table
.
Всякий раз, когда бы Имена столбцов обрабатываются как элементы данных, это указывает на то, что набор данных хранится в неопрятном формате, IMHO. Преобразование данных в длинный формат позволит применять обычные манипуляции с данными, такие как объединение, группирование, агрегирование.
dplyr
и tidyr
library(dplyr)
library(tidyr)
df %>%
pivot_longer(!"trait") %>%
filter(value == 1L) %>%
select(-value) %>%
inner_join(., ., by = "trait") %>%
filter(name.x < name.y) %>%
group_by(name.x, name.y) %>%
summarise(traits = toString(trait)) %>%
ungroup()
# A tibble: 3 x 3
name.x name.y traits
<chr> <chr> <chr>
1 Alice Bob c, e
2 Alice Charlie c, e
3 Bob Charlie a, c, e
Пояснение
df %>%
pivot_longer(!"trait") %>%
filter(value == 1L)
преобразует данные в длинный формат, который является компактным представление исходной матрицы в широком формате:
# A tibble: 10 x 3
trait name value
<fct> <chr> <dbl>
1 a Bob 1
2 a Charlie 1
3 b Alice 1
4 c Alice 1
5 c Bob 1
6 c Charlie 1
7 d Charlie 1
8 e Alice 1
9 e Bob 1
10 e Charlie 1
Столбец value
удален, поскольку он больше не нужен. Затем длинные данные объединяются вместе, чтобы найти все имена, которые совпадают с trait
. Результат включает пары имен, которые даны в другом порядке, например, (Алиса, Боб) и (Боб, Алиса), а также дубликаты имен, например, (Боб, Боб). Они удаляются.
Наконец, данные группируются и суммируются.
data.table
Вариант data.table
реализует тот же подход, но имеет преимущество, позволяющее самоэквивалентное неравенство , которое уменьшает количество строк непосредственно в объединении вместо последующего этапа фильтрации.
library(data.table)
long <- melt(setDT(df), id.vars = "trait", variable.name = "name")[value == 1]
long[long, on = .(trait, name < name), .(name1 = x.name, name2 = i.name, trait), nomatch = NULL][
, .(traits = toString(trait)), keyby = .(name1, name2)]
name1 name2 traits
1: Alice Bob c, e
2: Alice Charlie c, e
3: Bob Charlie a, c, e