我在R中工作,有两个表由id变量连接(出于某些原因,我不想合并它们)。示例性对象如下所示:
a <- data.frame(id=c(1L,2L,3L),
var1=c(0,1,3))
b <- data.frame(id=c(1L,1L,2L,2L,3L,3L),
var2=rnorm(6))
我想要做的是在第一个数据库中查找关于var1上给定条件的行,仅选择Ids然后使用这些id值来过滤数据库2中的观察。我想知道我是否可以在一个管道中执行此操作,如如下:
a %>%
filter(var1==1) %>%
select(id) %>%
filter(b,id==.)
或
a %>%
filter(var1==1) %>%
select(id) %>% c() %>% unlist()
filter(b,id==.)
两个示例都不起作用,可能是因为我只能通过管道运算符而不是原子值传递data.frames或其他对象。我是对的吗?
答案 0 :(得分:2)
好像您正在寻找semi_join
:
a %>% filter(var1 == 1) %>% semi_join(b, ., by = "id")
# id var2
# 1 2 0.8283845
# 2 2 -0.5286006
<强> semi_join 强>
返回x中匹配值的所有行,y 只保留x中的列。
半连接与内连接不同,因为内连接将是 为y的每个匹配行返回一行x,其中半连接将为 永远不要复制x行。
答案 1 :(得分:1)
其他答案为如何获得所需结果提供了很好的解决方案。要回答问题末尾的问题:
您的示例不会失败,因为管道在某种程度上限制了它的管道。问题在于管道运算符%>%
实际上做了什么。它将左侧的结果作为右侧的FIRST参数进行管道,无论您在何处使用.
。因此,filter(b,id==.)
它不会过滤b,它实际上会过滤您之前语句的结果。在第一个示例中调用traceback()
时,您可以看到此信息。如果我们看一下两个相关的结果:
....
9: filter(., b, id == .)
....
1: a %>% filter(var1 == 1) %>% select(id) %>% filter(b, id == .)
在1:
我们会看到您的代码,但在9:
,我们会看到R实际读取的内容。filter(b, id == .)
实际上被视为filter(., b, id == .)
答案 2 :(得分:0)
我只是将它分为两个阶段:
selected_ids = a %>% filter(var1 == 1) %>% select(id) %>% unlist()
b %>% filter(id %in% selected_ids)
# id var2
# 1 2 0.8054040
# 2 2 -0.5000918
或合并数据集并直接执行操作:
merged_data = merge(a, b)
merged_data %>% filter(var1 == 1)
# id var1 var2
# 1 2 1 0.8054040
# 2 2 1 -0.5000918
我更喜欢第二种选择。
答案 3 :(得分:0)
我们可以从id
a
获取var = 1
并选择b
匹配的id
中的所有行
b[b$id %in% a$id[a$var1 == 1], ]
# id var2
#3 2 1.0294
#4 2 0.7369
类似的事情可以在dplyr
中通过
library(dplyr)
b %>%
filter(id == a$id[a$var1 == 1])
答案 4 :(得分:0)
以下是使用data.table
setDT(a)[b, on = "id"][var1==1]
或使用dplyr
left_join(b, a, by = "id") %>%
filter(var1==1)
答案 5 :(得分:0)
你可以做到这一点(虽然我同意其他人的意见,我更喜欢合并或某种联合)。
您可以通过在表达式(.
)周围添加括号来解决包含{}
作为第一个参数的问题。然后,将.
视为data.frame(即使在select
之后),并调用所需的列。像这样:
a %>%
filter(var1==1) %>%
{filter(b,id==.$id)}
返回:
id var2
1 2 -0.2992151
2 2 -0.4115108