我有一个〜15000 * 1000数据帧,其中每一列代表一个个体,每一行代表一个特征(0或1)的发生率。
我想高效地比较所有的列对,并为所有可能的对生成所有相互特征(行名)的逗号分隔列表。
当前,我正在通过combn遍历所有列,并将相互的行名粘贴到字符串中。那就是说我有一个解决方案,但是,它非常非常慢(可能是列数的平方)。
有没有办法向量化这个问题/用tidyr / dplyr等方法解决?我似乎找不到办法。
例如:
------|individual1 | individual2 | individual3 | ...
trait1| 0 | 1 | 1 | ...
trait2| 0 | 0 | 0 | ...
trait3| 1 | 1 | 1 | ...
... | ... | ... | ... | ...
为trait1,trait3
和individual 2
对生成字符串individual 3
。
谢谢!
玩具数据(实际数据太稀疏,无法提取子集):
df <- data.frame(trait = c("a", "b", "c", "d", "e"), ind1 = c(0, 1, 1, 0, 1), ind2 = c(1, 0, 1, 0, 1), ind3 = c(1, 0, 1, 1, 1))
答案 0 :(得分:0)
尝试对每个列组合应用自定义功能。也许可以稍微提高效率。
yarn run compile
数据
t(combn(1:(ncol(df)-1), 2, function(x){
string <- paste(df$trait[df[[x[1]+1]] == 1 & df[[x[2]+1]] == 1], collapse = ",")
c(names(df)[x+1], string)
}))
# [,1] [,2] [,3]
# [1,] "Alice" "Bob" "c,e"
# [2,] "Alice" "Charlie" "c,e"
# [3,] "Bob" "Charlie" "a,c,e"
答案 1 :(得分:0)
尽管这个问题已经接受了answer,但我想提出一种使用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
匹配的所有名称。结果包括以不同顺序给出的名称对,例如(Alice,Bob)和(Bob,ALice),以及重复的名称,例如(Bob,Bob)。这些已删除。
最后,将数据分组并汇总。
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