基于第二个数据帧中的值的子集数据帧

时间:2018-08-27 14:35:47

标签: r

我有一个数据框df,它具有两列,例如:

> head(df1[,c(10,11)])
       ColA      ColB
1        12        20
2         7         5
3        32        38
4        37        46
5        15        15
6         4         4

我有第二个数据框,也有2列具有匹配名称的列。相反,只有两个数字,例如:

> head(df2)
       ColA      ColB
1        50        30

我想基于df1对应列中的值对df2中的值进行子集化。手动执行以下操作:

colA_vector <- df1[df1$colA < 50,]
colB_vector <- df1[df1$ColB < 30,]

我该如何以更通用的方式这样做?我不想硬编码任何东西。列名“ ColA”或“ ColB”可以是任何东西(因此要求使用这些列名的解决方案将无法正常工作)。

谢谢。

5 个答案:

答案 0 :(得分:3)

R为基础的情况下,我们可以这样做:

nms <- intersect(names(df1), names(df2))
df1[do.call(`&`, Map(`<`, df1[nms], df2[nms])),]
#   ColA ColB
# 1   12   20
# 2    7    5
# 5   15   15
# 6    4    4

或者如果两个data.frame具有相同的列顺序和相同的名称,则只是df1[do.call('&', Map('<', df1, df2)),]

使用软件包fuzzyjoin可能更具可读性:

library(fuzzy_join)
fuzzy_semi_join(df1, df2, match_fun = `<`)
#   ColA ColB
# 1   12   20
# 2    7    5
# 5   15   15
# 6    4    4

数据

df1 <- read.table(text="
ColA      ColB
1        12        20
2         7         5
3        32        38
4        37        46
5        15        15
6         4         4",h=T,strin=F)

df2 <- read.table(text="ColA      ColB
1        50        30",h=T,strin=F)

答案 1 :(得分:1)

如果我们想重复执行相同的任务,请创建一个函数

f1 <- function(dat1, dat2, colName) {
        dat1[dat1[[colName]] < dat2[[colName]],]
  }

f1(df1, df2, "ColA")
#  ColA ColB
#1   12   20
#2    7    5
#3   32   38
#4   37   46
#5   15   15
#6    4    4

f1(df1, df2, "ColB")
#  ColA ColB
#1   12   20
#2    7    5
#5   15   15
#6    4    4

数据

df1 <- structure(list(ColA = c(12L, 7L, 32L, 37L, 15L, 4L), ColB = c(20L, 
5L, 38L, 46L, 15L, 4L)), class = "data.frame", row.names = c(NA, 
-6L))

df2 <- structure(list(ColA = 50L, ColB = 30L), 
     class = "data.frame", row.names = "1")

答案 2 :(得分:1)

使用dplyr

df1 %>%
  filter(df1[,1] < df2[,1])

  ColA ColB
1   12   20
2    7    5
3   32   38
4   37   46
5   15   15
6    4    4

df1 %>%
  filter(df1[,2] < df2[,2])

  ColA ColB
1   12   20
2    7    5
3   15   15
4    4    4

同时基于两列进行子设置:

df1 %>%
  filter(df1[,1] < df2[,1] & df1[,2] < df2[,2])

  ColA ColB
1   12   20
2    7    5
3   15   15
4    4    4

答案 3 :(得分:0)

如果您不想使用fuzzyjoin连接包或自己创建函数,则可以重复第二个数据帧。

df1 <- data.frame("ColA" = c(12, 7, 32),
             "ColB" = c(20, 5, 38))
df2 <- data.frame("ColA" = 50,
              "ColB" = 30)

n <- nrow(df1)
df2_new <- do.call("rbind", replicate(n, df2, simplify = FALSE))
df1_which <- as.data.frame(df1 < df2_new)

colA_vector <- df1[df1_which$ColA, "ColA"]
colB_vector <- df1[df1_which$ColB, "ColB"]

答案 4 :(得分:0)

您可以尝试使用tidyverse功能。结果是过滤后的data.frames的列表。

foo <- function(x, y, ColA, ColB){
  require(tidyverse)
  var1 <- quo_name(ColA)
  var2 <- quo_name(ColB)
  x %>%
  select(a=!!var1, b=!!var2) %>% 
  mutate(colA_vector= a < y[[ColA]]) %>% 
  mutate(colB_vector= b < y[[ColB]]) %>% 
  gather(k, v, -a, -b) %>% 
  filter(v) %>%
  split(.$k) %>% 
  map(~select(.,-v,-k))
}
foo(df1, df2, "ColA", "ColB")
$colA_vector
   a  b
1 12 20
2  7  5
3 32 38
4 37 46
5 15 15
6  4  4

$colB_vector
    a  b
7  12 20
8   7  5
9  15 15
10  4  4