从更大的``查找''样式数据中查找2列的最接近值。

时间:2019-05-22 15:02:29

标签: r data.table lookup closest

我有一个data.tabledt_1),其中包含2列(Observed_AObserved_B)的测量值。我需要使用这些列中的值,并在分别引用列data.tabledt_2的样式为Modeled_AModeled_B)的第二次查找中查找最接近两个列的值。最终目标是,使用dt_2中最匹配的行,在dt_2Variable_1Variable_2和{{ 1}})并将其添加到Variable_3中。

我希望使用dt_1的{​​{1}}函数,因为我的实际data.table很大(roll; 30列和35000行)({{1} }; 17列和15,000行),但我不确定如何同时使用2列来完成此操作。

以下是一些示例数据:

data.tables
dt_1

注意:我通常不会发布这么长的示例(dt_2),但我认为问题的本质是有根据的。

3 个答案:

答案 0 :(得分:2)

答案的执行时间比较

library(ggplot2)
library(dplyr)
library(data.table)
library(microbenchmark)

mbm <- microbenchmark::microbenchmark(
  dplyr = dt_2 %>% 
    slice(
      apply(dt_1[,-1], 1, function(x) {
        (abs(x[1] - dt_2$Modeled_A) + abs(x[2] - dt_2$Modeled_B)) %>% 
          which.min()
      })
    ) %>% 
    mutate(id = as.character(1:nrow(.))) %>% 
    inner_join(dt_1, ., by = "id"),

  data.table = dt_1[, c(.SD, dt_2[which.min(abs(Observed_A-Modeled_A) + abs(Observed_B-Modeled_B))]), 
       by=dt_2[, seq_len(.N)]],

  data.table.reference = dt_1[, names(dt_2) := dt_2[which.min(abs(Observed_A-Modeled_A) + abs(Observed_B-Modeled_B))], 
                              by=dt_1[, seq_len(.N)]])
autoplot(mbm)

enter image description here

实际数据的执​​行时间

我将其包括在内是为了显示较大数据表的性能差异,其中dt_1由约35,000行30列组成,而dt_2由约15,000行和17列组成。

>

enter image description here

答案 1 :(得分:1)

我不擅长data.table,但这是一种tidyverse可能会帮助您的方式-

dt_1 %>% 
  tibble::rownames_to_column("id") %>% 
  mutate(cj = 1) %>% 
  inner_join(dt_2 %>% mutate(cj = 1), by = "cj") %>%
  select(-cj) %>% 
  mutate(
    closeness = abs(Observed_A - Modeled_A) + abs(Observed_B - Modeled_B),
    # closeness = 0 means perfect match
  ) %>% 
  arrange(id, closeness) %>% 
  group_by(id) %>% 
  slice(1) %>% 
  ungroup()

# A tibble: 8 x 9
  id    Observed_A Observed_B Modeled_A Modeled_B Variable_1 Variable_2 Variable_3 closeness
  <chr>      <dbl>      <dbl>     <dbl>     <dbl>      <int>      <int>      <int>     <dbl>
1 1         - 9.70      -3.10    - 9.80     -2.80          4        448        251     0.400
2 2         -10.8       -5.20    -11.4      -5.90         80        865         63     1.30 
3 3         - 9.70      -4.50    - 9.80     -4.30         37        857        281     0.300
4 4         - 9.20      -4.10    - 9.80     -4.30         37        857        281     0.800
5 5         - 9.50      -3.00    - 9.80     -2.80          4        448        251     0.500
6 6         -10.1       -2.70    - 9.80     -2.80          4        448        251     0.400
7 7         - 8.30      -2.60    - 8.20     -2.80         86        885        246     0.300
8 8         - 7.60      -2.60    - 8.20     -2.80         86        885        246     0.800

编辑:此方法避免了交叉联接,因此不应有内存问题。看看这是否足够快。无论哪种方式,我认为data.table都应该更快。

dt_1 <- dt_1 %>% 
  tibble::rownames_to_column("id")

dt_2 %>% 
  slice(
    apply(dt_1[,-1], 1, function(x) {
      (abs(x[1] - dt_2$Modeled_A) + abs(x[2] - dt_2$Modeled_B)) %>% 
      which.min()
    })
  ) %>% 
  mutate(id = as.character(1:nrow(.))) %>% 
  inner_join(dt_1, ., by = "id")

  id Observed_A Observed_B Modeled_A Modeled_B Variable_1 Variable_2 Variable_3
1  1       -9.7       -3.1      -9.8      -2.8          4        448        251
2  2      -10.8       -5.2     -11.4      -5.9         80        865         63
3  3       -9.7       -4.5      -9.8      -4.3         37        857        281
4  4       -9.2       -4.1      -9.8      -4.3         37        857        281
5  5       -9.5       -3.0      -9.8      -2.8          4        448        251
6  6      -10.1       -2.7      -9.8      -2.8          4        448        251
7  7       -8.3       -2.6      -8.2      -2.8         86        885        246
8  8       -7.6       -2.6      -8.2      -2.8         86        885        246

答案 2 :(得分:1)

使用与Shree相同的距离量度,但在data.table中使用(虽然不要以为会更快):

library(data.table)
setDT(dt_1)
setDT(dt_2)
dt_1[, c(.SD, dt_2[which.min(abs(Observed_A-Modeled_A) + abs(Observed_B-Modeled_B))]), 
    by=dt_1[, seq_len(.N)]]

输出:

   dt_1 Observed_A Observed_B Modeled_A Modeled_B Variable_1 Variable_2 Variable_3
1:    1       -9.7       -3.1      -9.8      -2.8          4        448        251
2:    2      -10.8       -5.2     -11.4      -5.9         80        865         63
3:    3       -9.7       -4.5      -9.8      -4.3         37        857        281
4:    4       -9.2       -4.1      -9.8      -4.3         37        857        281
5:    5       -9.5       -3.0      -9.8      -2.8          4        448        251
6:    6      -10.1       -2.7      -9.8      -2.8          4        448        251
7:    7       -8.3       -2.6      -8.2      -2.8         86        885        246
8:    8       -7.6       -2.6      -8.2      -2.8         86        885        246

编辑: 速度差异可能是由于列数很大。使用引用更新的另一种可能性:

library(data.table)
setDT(dt_1)
setDT(dt_2)
dt_1[, names(dt_2) := dt_2[which.min(abs(Observed_A-Modeled_A) + abs(Observed_B-Modeled_B))]), 
    by=dt_1[, seq_len(.N)]]

或者如果dt_1和dt_2都是矩阵,则使用基数R可能会更快。