【问题标题】:R compare values from one dataframe from values from other dataframeR比较来自一个数据帧的值与来自另一个数据帧的值
【发布时间】:2018-11-13 16:12:30
【问题描述】:

我对 R 很陌生,所以还在学习很多东西。我一直在四处寻找,但找不到适合我问题的答案。 我有这两个数据集:

d1
    Criteria Order Low High
1        a     1   0   10
2        a     1  11   20
3        a     1  21   30
4        b     1   0   13
5        b     1  14   32
6        a     2   5   22
7        a     2   0    4
8        b     2   0   18

然后d2

 Criteria Order Final
1        a     1    13
2        b     2    12
3        a     1     8
4        a     2     2 

我想知道当d2$Final 在d1$Low 和d1$High 内并且条件和顺序都匹配时,是否有任何方法可以向d1 添加额外的列。我期望得到的是这样的:

 Criteria Order Low High Final
1        a     1   0   10     8
2        a     1  11   20    13
3        a     1  21   30    NA
4        b     1   0   13    NA
5        b     1  14   32    NA
6        a     2   5   22    NA
7        a     2   0    4     2
8        b     2   0   18    12  

甚至在 Final 列中输出 1/0 表示真或假也可以。

提前致谢

【问题讨论】:

  • 这是一个常见且偶尔难以回答的问题。幸运的是,如果您的数据不大,您可以使用笛卡尔连接和一些过滤,如下所示:mango-solutions.com/blog/…

标签: r dataframe comparison


【解决方案1】:

这使用 SQL 创建一个复杂的连接。 Order 周围需要 [...] 是为了将其与同名关键字区分开来。

library(sqldf)

sqldf("select d1.*, d2.Final
  from d1 
  left join d2 on d1.Criteria = d2.Criteria and
                  d1.[Order] = d2.[Order] and
                  d2.Final between d1.Low and d1.High")

给出问题中显示的相同输出:

  Criteria Order Low High Final
1        a     1   0   10     8
2        a     1  11   20    13
3        a     1  21   30    NA
4        b     1   0   13    NA
5        b     1  14   32    NA
6        a     2   5   22    NA
7        a     2   0    4     2
8        b     2   0   18    12

注意

可重现形式的数据:

Lines1 <- "
    Criteria Order Low High
1        a     1   0   10
2        a     1  11   20
3        a     1  21   30
4        b     1   0   13
5        b     1  14   32
6        a     2   5   22
7        a     2   0    4
8        b     2   0   18"

Lines2 <- "
  Criteria Order Final
1        a     1    13
2        b     2    12
3        a     1     8
4        a     2     2"

d1 <- read.table(text = Lines1)
d2 <- read.table(text = Lines2)

【讨论】:

    【解决方案2】:

    如果您的数据“很大”,则此解决方案不适合您:笛卡尔连接将爆炸,超出“标准”计算机在内存方面所能承受的范围。

    但是,如果您的数据足够小(非常相对的术语),那么您可以执行 cartesian-join(也称为完全或完全外连接)并过滤结果。 (此解决方案是 https://www.mango-solutions.com/blog/in-between-a-rock-and-a-conditional-join 中的一个部分的实现。还有其他部分讨论 SQL 和 fuzzyjoin,两者都是值得的候选人。)

    三种方言,取决于你的喜好。

    基础 R

    a <- merge(d2, d1, all.x=T)
    a <- transform(a, Final = ifelse(Low <= Final & Final <= High, Final, NA))
    a[!duplicated(a),]
    #   Criteria Order Final Low High
    # 1        a     1    NA   0   10
    # 2        a     1    13  11   20
    # 3        a     1    NA  21   30
    # 4        a     1     8   0   10
    # 5        a     1    NA  11   20
    # 7        a     2    NA   5   22
    # 8        a     2     2   0    4
    # 9        b     2    12   0   18
    

    它有一个额外的行,试图优雅地工作......

    dplyr

    library(dplyr)
    full_join(d1, d2) %>%
      mutate(Final = if_else(between(Final, Low, High), Final, NA_integer_)) %>%
      group_by(Criteria, Order, Low, High) %>%
      summarise(Final = coalesce(Final)[1]) %>%
      ungroup()
    # Joining, by = c("Criteria", "Order")
    # # A tibble: 8 x 5
    #   Criteria Order   Low  High Final
    #   <chr>    <int> <int> <int> <int>
    # 1 a            1     0    10    NA
    # 2 a            1    11    20    13
    # 3 a            1    21    30    NA
    # 4 a            2     0     4     2
    # 5 a            2     5    22    NA
    # 6 b            1     0    13    NA
    # 7 b            1    14    32    NA
    # 8 b            2     0    18    12
    

    data.table

    library(data.table)
    as.data.table(d2)[d1, on = .(Final > Low, Final < High, Criteria, Order),
                      .(Criteria, Order, Low, High, x.Final)]
    #    Criteria Order Low High x.Final
    # 1:        a     1   0   10       8
    # 2:        a     1  11   20      13
    # 3:        a     1  21   30      NA
    # 4:        b     1   0   13      NA
    # 5:        b     1  14   32      NA
    # 6:        a     2   5   22      NA
    # 7:        a     2   0    4       2
    # 8:        b     2   0   18      12
    

    (还有一个使用data.table::foverlaps 的解决方案可能更快或更节省内存。阅读链接,这很有帮助。)


    数据:

    d1 <- structure(list(Criteria = c("a", "a", "a", "b", "b", "a", "a", 
    "b"), Order = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L), Low = c(0L, 
    11L, 21L, 0L, 14L, 5L, 0L, 0L), High = c(10L, 20L, 30L, 13L, 
    32L, 22L, 4L, 18L)), class = "data.frame", row.names = c("1", 
    "2", "3", "4", "5", "6", "7", "8"))
    d2 <- structure(list(Criteria = c("a", "b", "a", "a"), Order = c(1L, 
    2L, 1L, 2L), Final = c(13L, 12L, 8L, 2L)), class = "data.frame", row.names = c("1", 
    "2", "3", "4"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2021-01-26
      • 2019-08-20
      • 2013-06-14
      • 1970-01-01
      • 2022-10-01
      • 1970-01-01
      相关资源
      最近更新 更多