Как создать вектор из общих элементов в векторах R
У меня есть несколько векторов символов генов, содержащих названия видов, в которых они обнаружены, и я сделал график UpSetR, чтобы показать количество видов, общих для разных генов. Теперь я хотел бы сделать обратное: нанести на график количество общих генов по видам, но я не знаю, как это сделать.
Пример того, что у меня есть:
gene1 <- c("Panda", "Dog", "Chicken")
gene2 <- c("Human", "Panda", "Dog")
gene3 <- c("Human", "Panda", "Chicken")
...#About 20+ genes with 100+ species each
Пример того, что я хотел бы получить в результате:
Panda <- c("gene1", "gene2", "gene3")
Dog <- c("gene1", "gene2")
Human <- c("gene2", "gene3")
Chicken <- c("gene1", "gene3")
...
Я знаю, что это концептуально просто, но логистически сложнее. Кто-нибудь может дать мне подсказку?
Спасибо!
5 ответов
Ты можешь использовать unstack
от базы R:
unstack(stack(mget(ls(pattern="gene"))),ind~values)
$Chicken
[1] "gene1" "gene3"
$Dog
[1] "gene1" "gene2"
$Human
[1] "gene2" "gene3"
$Panda
[1] "gene1" "gene2" "gene3"
Вы можете в конечном итоге перечислить это в окружающую среду, list2env
функция
Сломать:
l = mget(ls(pattern="gene"))#get all the genes in a list
m = unstack(stack(l),ind~values)# Stack them, then unstack with the required formula
m
$Chicken
[1] "gene1" "gene3"
$Dog
[1] "gene1" "gene2"
$Human
[1] "gene2" "gene3"
$Panda
[1] "gene1" "gene2" "gene3"
list2env(m,.GlobalEnv)
Dog
[1] "gene1" "gene2"
Прежде всего я думаю, что для большинства целей лучше хранить gene
векторы в списке, как в
genes <- list(gene1 = gene1, gene2 = gene2, gene3 = gene3)
Тогда один базовый подход R будет
genes.v <- unlist(genes)
names(genes.v) <- rep(names(genes), times = lengths(genes))
species <- lapply(unique(genes.v), function(g) names(genes.v)[g == genes.v])
names(species) <- unique(genes.v)
species
# $Panda
# [1] "gene1" "gene2" "gene3"
#
# $Dog
# [1] "gene1" "gene2"
#
# $Chicken
# [1] "gene1" "gene3"
#
# $Human
# [1] "gene2" "gene3"
genes.v
является названным вектором всех видов с генами, являющимися их названиями. Тем не менее, когда виды имеют то же самое, например, gene1
то эти имена gene11
а также gene12
, Это то, что я исправляю во второй строке. Затем в третьей строке я перехожу по всем видам и создаю результирующий список, за исключением того, что в четвертой строке я добавляю названия видов.
Поместите данные в список, для начала. Это облегчает работу.
genes <- list(
gene1 = c("Panda", "Dog", "Chicken"),
gene2 = c("Human", "Panda", "Dog"),
gene3 = c("Human", "Panda", "Chicken")
)
Тогда мы можем получить названия видов оттуда.
species <- unique(unlist(genes))
С этими данными
> species
[1] "Panda" "Dog" "Chicken" "Human"
Для каждого из них мы хотим проверить, содержится ли имя в гене. Это работа для Map
(или его двоюродный брат lapply
, но мне нравится Map
):
get_genes_for_species <- function(s) {
contained <- unlist(Map(function(gene) s %in% gene, genes))
names(genes)[contained]
}
genes_per_species <- Map(get_genes_for_species, species)
Теперь у вас есть список списков, один список для каждого вида, содержащий гены, найденные в этом виде.
> genes_per_species
$Panda
[1] "gene1" "gene2" "gene3"
$Dog
[1] "gene1" "gene2"
$Chicken
[1] "gene1" "gene3"
$Human
[1] "gene2" "gene3"
Вы можете попробовать это.
gene <-unique(c(gene1,gene2,gene3))
TF <-data.frame(Species = gene)
TF$gene1 <- gene%in%gene1
TF$gene2 <- gene%in%gene2
TF$gene3 <- gene%in%gene3
> TF
Species gene1 gene2 gene3
1 Panda TRUE TRUE TRUE
2 Dog TRUE TRUE FALSE
3 Chicken TRUE FALSE TRUE
4 Human FALSE TRUE TRUE
Вот вариант, который охватывает тиверсайд и помещает результат в аккуратный фрейм данных.
Хитрость заключается в том, чтобы объединить результаты с str_c
а также summarise
,
tibble(gene1 = gene1,
gene2 = gene2,
gene3 = gene3) %>%
gather(gene_name, gene_type) %>%
group_by(gene_type) %>%
summarise(genes = str_c(gene_name, collapse = ", "))
# A tibble: 4 x 2
gene_type genes
<chr> <chr>
1 Chicken gene1, gene3
2 Dog gene1, gene2
3 Human gene2, gene3
4 Panda gene1, gene2, gene3
Я согласен с Юлиусом (выше), что лучший способ хранить генные векторы - это список. Именованный список будет еще лучше, так как:
my_gene_list <- set_names(list(gene1, gene2, gene3), str_c("gene", 1:3) )
Это аккуратно дало бы тот же результат...
my_gene_list %>% as_tibble() %>%
gather(gene_name, gene_type) %>%
group_by(gene_type) %>%
summarise(genes = str_c(gene_name, collapse = ", "))
# A tibble: 4 x 2
gene_type genes
<chr> <chr>
1 Chicken gene1, gene3
2 Dog gene1, gene2
3 Human gene2, gene3
4 Panda gene1, gene2, gene3