【问题标题】:Merging two sets of data by data.table roll='nearest' function通过data.table roll='nearest'函数合并两组数据
【发布时间】:2019-01-02 21:35:52
【问题描述】:

我有两组数据。

set_A 的样本(总行数:45467):

ID_a    a1  a2  a3  time_a
2   35694   5245.2  301.6053    00.00944
3   85694   9278.9  301.6051    23.00972
4   65694   9375.2  301.6049    22.00972
5   85653   4375.5  301.6047    19.00972
6   12694   5236.3  301.6045    22.00972
7   85697   5345.2  301.6043    21.00972
8   85640   5274.1  301.6041    20.01000
9   30694   5279.0  301.6039    20.01000

set_B 的样本(总行数:4798):

ID_b    b1  b2  source  time_b
2   34.20   15.114  set1.csv.1  20.35750
7   67.20   16.114  set1.csv.2  21.35778
12  12.20   33.114  set1.csv.3  22.35806
17  73.20   67.114  set2.csv.1  23.35833
23  88.20   42.114  set2.csv.2  19.35861
28  90.20   52.114  set3.csv.1  00.35889

我对@9​​87654325@ 的结果感兴趣,来自set_A 的行与time_atime_b 的最接近值匹配(输出行总数:4798)。在set_A 中,time_a 的值可以重复多次(例如,ID_a[8,][ID_a[9,]) - 哪一行将与来自set_B 的行合并并不重要(在这种情况下为@987654334 @)。预期结果示例:

ID_b    b1  b2  source  time_b      ID_a    a1  a2  a3  time_a
2   34.20   15.114  set1.csv.1  20.35750    8   85640   5274.1  301.6041    20.01000
7   67.20   16.114  set1.csv.2  21.35778    7   85697   5345.2  301.6043    21.00972
12  12.20   33.114  set1.csv.3  22.35806    4   65694   9375.2  301.6049    22.00972
17  73.20   67.114  set2.csv.1  23.35833    3   85694   9278.9  301.6051    23.00972
23  88.20   42.114  set2.csv.2  19.35861    5   85653   4375.5  301.6047    19.00972
28  90.20   52.114  set3.csv.1  00.35889    2   35694   5245.2  301.6053    00.00944

我在 stackoverflow 上遇到了许多类似的问题,我真的很喜欢 data.table 库代码,因为它们看起来非常优雅。但是,我进行了几次失败的尝试,我收到了一个基于两组构建的表(总行数 45467)或仅将一列 time_a 合并到 set_B... 不过,我不会挑剔如果有人有其他想法,我将非常感谢您的帮助。

我正在处理的代码示例:

setDT(set_B)
setDT(set_A)
setkey(set_B, time_b) [, time_a:=time_b]
test_ab <- set_B[set_A, roll='nearest']

因此,我不仅收到了一个包含应该忽略的数据的表,而且还收到了列名中的“一团糟”(例如,包含ID_a 值的列称为time_a)。

我真的很感谢你的帮助!

【问题讨论】:

    标签: r merge data.table


    【解决方案1】:

    以下是基于您提供的示例数据的分步示例:

    # Sample data
    library(data.table)
    setDT(set_A)
    setDT(set_B)    
    
    # Create time column by which to do a rolling join
    set_A[, time := time_a]
    set_B[, time := time_b]
    setkey(set_A, time)
    setkey(set_B, time)
    
    # Rolling join by nearest time
    set_merged <- set_B[set_A, roll = "nearest"]
    
    unique(set_merged[order(ID_b)], by = "time")
    #    ID_b   b1     b2     source   time_b     time ID_a    a1     a2       a3
    # 1:    2 34.2 15.114 set1.csv.1 20.35750 20.01000    8 85640 5274.1 301.6041
    # 2:    7 67.2 16.114 set1.csv.2 21.35778 21.00972    7 85697 5345.2 301.6043
    # 3:   12 12.2 33.114 set1.csv.3 22.35806 22.00972    4 65694 9375.2 301.6049
    # 4:   17 73.2 67.114 set2.csv.1 23.35833 23.00972    3 85694 9278.9 301.6051
    # 5:   23 88.2 42.114 set2.csv.2 19.35861 19.00972    5 85653 4375.5 301.6047
    # 6:   28 90.2 52.114 set3.csv.1  0.35889  0.00944    2 35694 5245.2 301.6053
    #      time_a
    # 1: 20.01000
    # 2: 21.00972
    # 3: 22.00972
    # 4: 23.00972
    # 5: 19.00972
    # 6:  0.00944
    

    两个cmets:

    1. 我们创建一个新的time 列,以避免丢失set_Aset_B 的原始时间列之一。如果需要,您始终可以在加入后删除 time 列。
    2. 我们使用uniqueID_b 的顺序删除重复的time 行。您在帖子中提到“合并哪一行并不重要”,但如果您确实想保留 特定 行,您可能需要调整这行代码。

    更新(感谢@Henrik)

    正如@Henrik 指出的那样,您所追求的实际上是set_A 相对于set_B 的滚动连接,在这种情况下您不需要处理重复的行。

    翻译成

    library(data.table)
    setDT(set_A)
    setDT(set_B)    
    
    # Create time column by which to do a rolling join
    set_A[, time := time_a]
    set_B[, time := time_b]
    
    set_A[set_B, on = "time", roll = "nearest"][order(ID_a)]
    #   ID_a    a1     a2       a3   time_a     time ID_b   b1     b2     source
    #1:    2 35694 5245.2 301.6053  0.00944  0.35889   28 90.2 52.114 set3.csv.1
    #2:    3 85694 9278.9 301.6051 23.00972 23.35833   17 73.2 67.114 set2.csv.1
    #3:    5 85653 4375.5 301.6047 19.00972 19.35861   23 88.2 42.114 set2.csv.2
    #4:    6 12694 5236.3 301.6045 22.00972 22.35806   12 12.2 33.114 set1.csv.3
    #5:    7 85697 5345.2 301.6043 21.00972 21.35778    7 67.2 16.114 set1.csv.2
    #6:    9 30694 5279.0 301.6039 20.01000 20.35750    2 34.2 15.114 set1.csv.1
    #  time_b
    #1:  0.35889
    #2: 23.35833
    #3: 19.35861
    #4: 22.35806
    #5: 21.35778
    #6: 20.35750
    

    样本数据

    set_A <- read.table(text =
        "ID_a    a1  a2  a3  time_a
    2   35694   5245.2  301.6053    00.00944
    3   85694   9278.9  301.6051    23.00972
    4   65694   9375.2  301.6049    22.00972
    5   85653   4375.5  301.6047    19.00972
    6   12694   5236.3  301.6045    22.00972
    7   85697   5345.2  301.6043    21.00972
    8   85640   5274.1  301.6041    20.01000
    9   30694   5279.0  301.6039    20.01000", header = T)
    
    set_B <- read.table(text =
        "ID_b    b1  b2  source  time_b
    2   34.20   15.114  set1.csv.1  20.35750
    7   67.20   16.114  set1.csv.2  21.35778
    12  12.20   33.114  set1.csv.3  22.35806
    17  73.20   67.114  set2.csv.1  23.35833
    23  88.20   42.114  set2.csv.2  19.35861
    28  90.20   52.114  set3.csv.1  00.35889", header = T)
    

    【讨论】:

    • 非常感谢代码和简单清晰的解释,它帮助了很多!我刚刚做了一个更改:unique(set_merged[order(ID_b)], by = "time") 相反,我写了unique(set_merged[order(ID_b)], by = "ID_b"),因为set_B 中的一些时间值也被复制了(ID_b 是唯一的)。
    • 您不想在i 中使用“set_B”来查找x 中的“set_A”行吗? set_A[set_B, on="time", roll = "nearest"]。那么你就不需要unique 步骤了。此外,如果您使用on,则不需要两个setkey 步骤。此外,setDT 通过引用更新,因此分配 (&lt;-) 是多余的。请注意,由于 'set_A' 中的重复时间,某些匹配项会有所不同。
    • 小补充:如果你用fread代替read.table,读取的结果已经是data.table。如果使用T,则使用TRUE 也是(或似乎是)更好的做法。
    • 我认为这个问题中的小例子(是的,在实际问题中)非常好,可以更好地了解data.table 连接类型:Why does XY join of data.tables not allow a full outer join, or a left join?
    • 就个人而言,我喜欢使用on 参数,而不是设置键。在x[i, on = , ...] 中,您要加入的内容很明确。 on here 的一些很好的例子。干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多