R组的近似值

问题描述 投票:0回答:2

我有一个R数据框架(250,000行),有些数据看起来是这样的。

df = data.frame(X = c(1000.005, 1000.7, 1200, 1566, 1766.55, 1767.30, 33.45, 33.25, 400.67, 400.77), Y = c(38.6, 38.4, 32.0, 32.01, 39.99, 39.20, 12.21, 12.11, 33.81, 33.91), Angle = c(50, 36, 27, 77, 26, 34, 29, 14, 37, 55)) 

所以我的目标是根据X和Y值的近似值对数据进行分组,差值不超过1. 对于上图所示的数据集,分组安排是这样的:

data.frame(X = c(1000.005, 1000.7, 1200, 1566, 1766.55, 1767.30, 33.45, 33.25, 400.67, 400.77), Y = c(38.6, 38.4, 32.0, 32.01, 39.99, 39.20, 12.21, 12.11, 33.81, 33.91), Angle = c(50, 36, 27, 77, 26, 34, 29, 14, 37, 55), group = c(1,1, 2, 3, 4,4, 5, 5, 6, 6))

在R中是否有一个函数可以通过设置行的差值来进行分组(在我的例子中,差值将是1)?

r group-by approximation
2个回答
0
投票

这个问题有点混乱,即使有你的意见,我也会分享一些可能的解决方案。

即使你确定每个观测值都有一个对应的观测值是 "最接近 "的,你如何定义距离?标准的欧氏距离?但如果每对观测值真的有'重复',那为什么不直接看最接近的数值,比如说,X值,如果两个之间莫名其妙的出现了平局,那就看Y值?还是反过来?如果真的有唯一的观测值对,任何方法都应该得到同样的答案。所以只要选一个最简单的,然后建立一个距离矩阵,然后选取每个距离的最小值,如果对于第j个观测值,第i个观测值的距离最小,那么你就知道这些形成了一对。如果你想同时使用(X,Y),就用标准的欧几里得距离。

接下来是数据集大小的问题。250,000是相当大的,所以使用 dist 可能是行不通的。老实说,鉴于上述情况,我建议你写一个for循环,其中对于第i个观测值,如果第j个观测值是最接近的,那么你就为它们组成一个对,并更新你正在搜索的数据集来删除它们。它不会很好看,但应该运行得相当快。如果你在这方面遇到困难,请告诉我们。

最后,正如评论中所指出的,标准的方法可能是使用一些聚类方法。也许让聚类大小等于数据集大小的一半?你甚至可以做一个分步聚类的方法,在每一步都指定一半的数据集大小,查看组内,取最小的对子,然后得到一个更新的数据集,你再次聚类,重复直到你得到唯一的对子。

25万行,这两种方法其实应该问题不大。


0
投票

我觉得你的数据大小使用分组在计算上还是很容易的。下面是一个略显凌乱的 data.table 的方法。

library(data.table)
setDT(df)
group <- df[,ID := 1:.N][
  ,df[abs(X - .SD[,X]) < 1 & abs(Y - .SD[,Y]) < 1,.(ID2 = ID)],by = ID,.SDcols = c("X","Y")][
  ,.(df[ID,],df[ID2,])][
    ,Distance := sqrt((X-X.1)^2+(Y-Y.1)^2)][
      Distance <= 1,][
        !duplicated(ID.1),rleid(ID)]

df[,`:=`(Group = group, ID = NULL)]
df
#           X     Y Angle Group
# 1: 1000.005 38.60    50     1
# 2: 1000.700 38.40    36     1
# 3: 1200.000 32.00    27     2
# 4: 1566.000 32.01    77     3
# 5: 1766.550 39.99    26     4
# 6: 1767.300 39.20    34     5
# 7:   33.450 12.21    29     6
# 8:   33.250 12.11    14     6
# 9:  400.670 33.81    37     7
#10:  400.770 33.91    55     7

首先,我们对数据集本身的行进行子集,这些行在1以内的行,对两个 XY. 如果点在任何一个维度上都超过1,那么它们不可能比1更接近。我们用 .SDcols 只对子集 .SD 为我们关心的列。接下来,我们将行绑定在一起。然后,我们用欧氏距离的公式手动计算距离。接下来,我们选择那些在1以内的行。ID 所以我们可以使用上一步的 rleid!duplicated 来进行分组。然后再把它加回原始数据,就可以了。

你会根据这需要多长时间和多少内存来知道它是否会工作。

df[,ID := 1:.N][,df[abs(X - .SD[,X]) < 1 & abs(Y - .SD[,Y]) < 1,.(ID2 = ID)],by = ID,.SDcols = c("X","Y")]

请注意,你的预期输出可能会有误差 因为5点和6点之间的距离是1. 089。

dist(rbind(c(1766.550,39.99),c(1767.300,39.20)))
#         1
#2 1.089312
© www.soinside.com 2019 - 2024. All rights reserved.