Dplyr 语法选择列并将它们转换为单个列表
Dplyr syntax selecting columns and converting them to a single list
我开始学习如何使用 dplyr 的管道 (%>%) 命令来操作数据帧。我喜欢它看起来更加流线型。然而,我刚遇到一个问题,我只用管道无法解决。
我有一个包含关系(网络)数据的数据框,如下所示:
前两列表示哪些项目(基因)之间存在关系,第三列包含有关该关系的信息:
a b c
1 Gene_1 Gene_2 X
2 Gene_2 Gene_3 R
3 Gene_1 Gene_4 X
我的目标是获得具有相同属性的独特基因列表。如果选择第 3 列中的属性 X
,我会得到这个数据框:
a b c
1 Gene_1 Gene_2 X
3 Gene_1 Gene_4 X
我想以这份独特基因列表结束:
genes = c("Gene_1" "Gene_2" "Gene_4")
项目(基因)来自第一列还是第二列都没有关系,我只想要一个唯一的列表。我想到了这个解决方案:
library(tidyr)
net = tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
b = c("Gene_2", "Gene_3", "Gene_4"),
c = c("X", "R", "X"))
df = net %>%
filter(c == "X") %>%
select(c(1,2))
genes = unique(c(df$a, df$b))
但我不满意,因为我无法在 dplyr 管道命令中执行所有操作。我必须在管道命令之外创建一个列表,然后对其调用 unique。
有没有办法通过调用另一个管道来完成这个任务?无论如何我找不到这样做。谢谢。
1) 像这样使用 {...}
:
net %>%
filter(c == "X") %>%
select(c(1,2)) %>%
{ unique(c(.$a, .$b)) }
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
2) 或使用 magrittr 的 %$%
管道:
library(magrittr)
net %>%
filter(c == "X") %>%
select(c(1,2)) %$%
unique(c(a, b))
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
3) 或使用 with
:
net %>%
filter(c == "X") %>%
select(c(1,2)) %>%
with(unique(c(a, b)))
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
由于结果不是数据框最好不要调用它df
.
我建议使用 tidyr::pivot_longer
将来自两个不同基因列的潜在匹配的多列重塑为值列(我们关心的)和名称列(引用原始列名称,我们不关心并且可以忽略)。然后 distinct
获得唯一匹配,最后匹配到列 c:
net %>%
pivot_longer(-c) %>%
distinct(c, value) %>%
filter(c == "X")
如果您希望结果作为向量,您可以添加 %>% pull(value)
。
这种方法的一个好处是我们已经为每一列计算了每组不同的基因 c
值,最后 filter
步骤只是将它缩小到一个例子 c
值。
结果
c value
<chr> <chr>
1 X Gene_1
2 X Gene_2
3 X Gene_4
[注意:我制作了 a = c("Gene_1", "Gene_2", "Gene_1")
和 b = c("Gene_2", "Gene_3", "Gene_4")
来匹配示例。]
我知道这个问题有几个答案,但我会用稍微不同的方式来回答它。也许对某人有用?
我也创建了一个数据集来演示。
library(tidyverse)
library(stringi) # only used in data generation
# data set creation 100 rows
a = paste0("Gene_",1:100)
b = paste0("Gene_",round(runif(100, 10, 99),digits = 0))
cC = paste0(stringi::stri_rand_strings(100, 1, '[A-Z]'))
# put it together and strip the information
data.frame(a = a, b = b, cC = cC) %>% # collect the data
filter(cC == "X") %>% # filter for attribute
select(-cC) %>% # remove attribute field
unlist() %>% # collapse the data frame into a vector
unique() # show me what's unique
# output example
# [1] "Gene_10" "Gene_12" "Gene_28" "Gene_77" "Gene_22" "Gene_41" "Gene_75"
# [8] "Gene_19"
unlist()
函数可能就是您要找的。
引用 ?unlist
的内置文档:“给定一个列表结构 x,unlist 将其简化为生成一个包含 x 中出现的所有原子组件的向量。”。 =29=]
由于 R 数据帧(和 tibbles)是作为长度相等的列向量列表实现的,unlist 函数将有效地将数据帧转换为向量。
使用 filter
和 select
对所需的行和列进行子集化,然后将结果通过 unlist()
和 unique()
进行管道传输。结果将是一个包含不同元素的向量。
library(dplyr)
# The example data
tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
b = c("Gene_2", "Gene_3", "Gene_4"),
c = c("X", "R", "X")) %>%
# Subset data for desired feature
filter(c == "X") %>%
# Select identifier columns
select(a, b) %>%
# convert to a vector
unlist() %>%
# derive unique elements
unique()
结果
[1] "Gene_1" "Gene_2" "Gene_4"
library(tidyverse)
net <- tibble(
a = c("Gene_1", "Gene_1", "Gene_3"),
b = c("Gene_2", "Gene_4", "Gene_5"),
c = c("X", "R", "X")
)
df <- net %>%
filter(c == "X") %>%
select(a, b)
df
#> # A tibble: 2 x 2
#> a b
#> <chr> <chr>
#> 1 Gene_1 Gene_2
#> 2 Gene_3 Gene_5
genes <- net %>%
select(-c) %>%
unlist() %>%
unique()
genes
#> [1] "Gene_1" "Gene_3" "Gene_2" "Gene_4" "Gene_5"
尽管 OP 也提出并接受了许多有启发性的答案,但我只想补充一点,以防万一,您希望它同时用于 c
中的所有值,请执行此操作
library(tidyverse)
net %>%
group_split(c, .keep = F) %>%
setNames(unique(net$c)) %>%
map(~ (.x %>% unlist() %>% unique()))
$X
[1] "Gene_2" "Gene_3"
$R
[1] "Gene_1" "Gene_2" "Gene_4"
我开始学习如何使用 dplyr 的管道 (%>%) 命令来操作数据帧。我喜欢它看起来更加流线型。然而,我刚遇到一个问题,我只用管道无法解决。
我有一个包含关系(网络)数据的数据框,如下所示:
前两列表示哪些项目(基因)之间存在关系,第三列包含有关该关系的信息:
a b c
1 Gene_1 Gene_2 X
2 Gene_2 Gene_3 R
3 Gene_1 Gene_4 X
我的目标是获得具有相同属性的独特基因列表。如果选择第 3 列中的属性 X
,我会得到这个数据框:
a b c
1 Gene_1 Gene_2 X
3 Gene_1 Gene_4 X
我想以这份独特基因列表结束:
genes = c("Gene_1" "Gene_2" "Gene_4")
项目(基因)来自第一列还是第二列都没有关系,我只想要一个唯一的列表。我想到了这个解决方案:
library(tidyr)
net = tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
b = c("Gene_2", "Gene_3", "Gene_4"),
c = c("X", "R", "X"))
df = net %>%
filter(c == "X") %>%
select(c(1,2))
genes = unique(c(df$a, df$b))
但我不满意,因为我无法在 dplyr 管道命令中执行所有操作。我必须在管道命令之外创建一个列表,然后对其调用 unique。
有没有办法通过调用另一个管道来完成这个任务?无论如何我找不到这样做。谢谢。
1) 像这样使用 {...}
:
net %>%
filter(c == "X") %>%
select(c(1,2)) %>%
{ unique(c(.$a, .$b)) }
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
2) 或使用 magrittr 的 %$%
管道:
library(magrittr)
net %>%
filter(c == "X") %>%
select(c(1,2)) %$%
unique(c(a, b))
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
3) 或使用 with
:
net %>%
filter(c == "X") %>%
select(c(1,2)) %>%
with(unique(c(a, b)))
## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
由于结果不是数据框最好不要调用它df
.
我建议使用 tidyr::pivot_longer
将来自两个不同基因列的潜在匹配的多列重塑为值列(我们关心的)和名称列(引用原始列名称,我们不关心并且可以忽略)。然后 distinct
获得唯一匹配,最后匹配到列 c:
net %>%
pivot_longer(-c) %>%
distinct(c, value) %>%
filter(c == "X")
如果您希望结果作为向量,您可以添加 %>% pull(value)
。
这种方法的一个好处是我们已经为每一列计算了每组不同的基因 c
值,最后 filter
步骤只是将它缩小到一个例子 c
值。
结果
c value
<chr> <chr>
1 X Gene_1
2 X Gene_2
3 X Gene_4
[注意:我制作了 a = c("Gene_1", "Gene_2", "Gene_1")
和 b = c("Gene_2", "Gene_3", "Gene_4")
来匹配示例。]
我知道这个问题有几个答案,但我会用稍微不同的方式来回答它。也许对某人有用?
我也创建了一个数据集来演示。
library(tidyverse)
library(stringi) # only used in data generation
# data set creation 100 rows
a = paste0("Gene_",1:100)
b = paste0("Gene_",round(runif(100, 10, 99),digits = 0))
cC = paste0(stringi::stri_rand_strings(100, 1, '[A-Z]'))
# put it together and strip the information
data.frame(a = a, b = b, cC = cC) %>% # collect the data
filter(cC == "X") %>% # filter for attribute
select(-cC) %>% # remove attribute field
unlist() %>% # collapse the data frame into a vector
unique() # show me what's unique
# output example
# [1] "Gene_10" "Gene_12" "Gene_28" "Gene_77" "Gene_22" "Gene_41" "Gene_75"
# [8] "Gene_19"
unlist()
函数可能就是您要找的。
引用 ?unlist
的内置文档:“给定一个列表结构 x,unlist 将其简化为生成一个包含 x 中出现的所有原子组件的向量。”。 =29=]
由于 R 数据帧(和 tibbles)是作为长度相等的列向量列表实现的,unlist 函数将有效地将数据帧转换为向量。
使用 filter
和 select
对所需的行和列进行子集化,然后将结果通过 unlist()
和 unique()
进行管道传输。结果将是一个包含不同元素的向量。
library(dplyr)
# The example data
tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
b = c("Gene_2", "Gene_3", "Gene_4"),
c = c("X", "R", "X")) %>%
# Subset data for desired feature
filter(c == "X") %>%
# Select identifier columns
select(a, b) %>%
# convert to a vector
unlist() %>%
# derive unique elements
unique()
结果
[1] "Gene_1" "Gene_2" "Gene_4"
library(tidyverse)
net <- tibble(
a = c("Gene_1", "Gene_1", "Gene_3"),
b = c("Gene_2", "Gene_4", "Gene_5"),
c = c("X", "R", "X")
)
df <- net %>%
filter(c == "X") %>%
select(a, b)
df
#> # A tibble: 2 x 2
#> a b
#> <chr> <chr>
#> 1 Gene_1 Gene_2
#> 2 Gene_3 Gene_5
genes <- net %>%
select(-c) %>%
unlist() %>%
unique()
genes
#> [1] "Gene_1" "Gene_3" "Gene_2" "Gene_4" "Gene_5"
尽管 OP 也提出并接受了许多有启发性的答案,但我只想补充一点,以防万一,您希望它同时用于 c
中的所有值,请执行此操作
library(tidyverse)
net %>%
group_split(c, .keep = F) %>%
setNames(unique(net$c)) %>%
map(~ (.x %>% unlist() %>% unique()))
$X
[1] "Gene_2" "Gene_3"
$R
[1] "Gene_1" "Gene_2" "Gene_4"