【问题标题】:Merging two datasets on approximate values在近似值上合并两个数据集
【发布时间】:2015-06-14 04:43:44
【问题描述】:

我需要合并(左连接)两个数据集xy

merge(x,y, by.x = "z", by.y = "zP", all.x = TRUE)

z 中的每个值都不存在于zP 中,但zP 中必须存在最接近的值。所以我们需要在zP 中使用最接近的值来进行合并。 例如

z <- c(0.231, 0.045, 0.632, 0.217, 0.092, ...)
zP <- c(0.010,0.013, 0.017, 0.021, ...)

我们如何在 R 中做到这一点?

【问题讨论】:

  • 您应该提供一个可重现的示例和您想要的输出。否则将很难为您提供帮助。
  • ...然后将可重现的示例放在 stackoverflow 上,因为这不是一个非常数据科学的问题,而且在 stackoverflow 上还有大约一百万的 R 用户。
  • 我投票结束这个问题,因为它属于 Stackoverflow.com

标签: r dataset


【解决方案1】:

根据您提供的信息,听起来您希望将所有观察结果保留在x 中,然后对于x 中的每个观察结果,您希望在y 中找到最小化列之间距离的观察结果@ 987654325@ 和zP。如果那是您正在寻找的东西,那么这样的东西可能会起作用

> library(data.table)

> x <- data.table(z = c(0.231, 0.045, 0.632, 0.217, 0.092), k = c("A","A","B","B","B"))
> y <- data.table(zP = c(0.010, 0.813, 0.017, 0.421), m = c(1,2,3,4))

> x
       z k 
1: 0.231 A 
2: 0.045 A 
3: 0.632 B 
4: 0.217 B 
5: 0.092 B 
> y
      zP m
1: 0.010 1
2: 0.813 2
3: 0.017 3
4: 0.421 4

> find.min.zP <- function(x){
+   y[which.min(abs(x - zP)), zP]
+ }

> x[, zP := find.min.zP(z), by = z]

> x
   z k    zP
1: 0.231 A 0.421
2: 0.045 A 0.017
3: 0.632 B 0.813
4: 0.217 B 0.017
5: 0.092 B 0.017

> merge(x, y, by="zP", all.x = T, all.y = F)
      zP     z k m
1: 0.017 0.045 A 3
2: 0.017 0.217 B 3
3: 0.017 0.092 B 3
4: 0.421 0.231 A 4
5: 0.813 0.632 B 2

鉴于我经常使用data.table,这是我脑海中突然出现的解决方案。请注意,在这里使用data.table 可能是也可能不是最优雅的方式,甚至可能不是最快的方式(尽管如果xy 很大,一些涉及data.table 的解决方案可能是最快的) .另请注意,这可能是使用data.table“糟糕”的一个例子,因为我没有努力优化速度。如果速度很重要,我强烈建议您阅读github wiki 上的有用文档。希望对您有所帮助。

编辑:

正如我所怀疑的,data.table 提供了一种更好的方法,Arun 在 cmets 中指出了这一点。

> setkey(x, z)
> setkey(y, zP)
> y[x, roll="nearest"]

      zP m k
1: 0.045 3 A
2: 0.092 3 B
3: 0.217 3 B
4: 0.231 4 A
5: 0.632 2 B

唯一的区别是 z 列现在被命名为 zP 并且原来的 zP 列已经消失了。如果保留该列很重要,您始终可以将 y 中的 zP 列复制到名为 z 的新列并加入该列。

> y[, z := zP]
> setkey(x, z)
> setkey(y, z)
> y[x, roll='nearest']
      zP m     z k
1: 0.017 3 0.045 A
2: 0.017 3 0.092 B
3: 0.017 3 0.217 B
4: 0.421 4 0.231 A
5: 0.813 2 0.632 B

这稍微减少了输入,但真正的改进在于大型数据集的计算时间。

> x <- data.table(z = runif(100000, 0, 100), k = sample(LETTERS, 100000, replace = T))
> y <- data.table(zP = runif(50000, 0, 100), m = sample(letters, 50000, replace = T))

> start <- proc.time()
> x[, zP := find.min.zP(z), by = z]
> slow <- merge(x, y, by="zP", all.x = T, all.y = F)
> proc.time() - start
  user  system elapsed 
104.849  0.072 106.432 

> x[, zP := NULL] # Drop the zP column we added to x doing the merge the slow way
> start <- proc.time()
> y[, z := zP]
> setkey(x, z)
> setkey(y, z)
> fast <- y[x, roll='nearest']
> proc.time() - start
 user  system elapsed 
0.046   0.000   0.045

# Reorder the rows and columns so that we can compare the two data tables
> setkey(slow, z)
> setcolorder(slow, c("z", "zP", "k", "m"))
> setcolorder(fast, c("z", "zP", "k", "m"))
> all.equal(slow, fast)
TRUE

请注意,更快的方法要快 2,365 倍!对于具有超过 100,000 个观测值的数据集(这些天相对较小),我预计时间增益会更加显着。这就是为什么如果您正在处理大型数据集,阅读 data.table 文档是值得的。通过使用内置方法,您通常可以实现非常大的加速,但除非您查看,否则您不会知道它们的存在。

【讨论】:

  • 不错的答案。但是,它可以通过使用roll = "nearest"滚动连接 来完成。将xy 上的键设置为zzP 并执行:y[x, roll="nearest"]。就是这样。
  • @Arun,感谢您的提示!我以前没有使用过滚动连接,但我很高兴我现在知道了它们。我更新了答案以显示您的建议并显示滚动连接在大型数据集上的速度有多快。此外,感谢伟大的新 github wiki,文档得到了很大改进。我真的很感谢你们在包装中所做的所有工作。我发现它对很多事情都非常有用。
  • 约瑟夫,谢谢。是的,我们正在努力为接下来的连接、重叠连接和重塑添加详细的插图。希望我们能尽快到达那里:-)。
猜你喜欢
  • 2012-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多