【问题标题】:Fastest method to remove rows that are slightly different by a given threshold epsilon删除与给定阈值 epsilon 略有不同的行的最快方法
【发布时间】:2018-04-24 21:35:48
【问题描述】:

在我的数据中,我有多行彼此之间仅略有不同,例如0.001。如果发生这种情况,我只想保留 1 条记录。是否有任何现有的函数/包可以进行逐行比较并在差异小于给定阈值 epsilon 时删除行?我在想distinct(., epsilon = 0.001)

例子:

df <- data.frame(
  IDname = c("aaa1", "bbb2", "ccc3", "ddd4"),
  g = c(0.00501, 0.00499, 2, 2),
  t = c(0.005002, 0.004991, 2.001, 2.0001),
  x = c(1.0001, 1, 2, 2.00001)
)

df

期望的输出:

  IDname       g        t       x
1   aaa1 0.00501 0.005002 1.00010
3   ccc3 2.00000 2.001000 2.00000

【问题讨论】:

  • 您的示例和输出似乎不一致。对于epsilon = 0.0001,第 3 行和第 4 行是不同的,不是吗?只有第 1 行和第 2 行中的值在 epsilon 中相似。

标签: r duplicates unique diff distinct


【解决方案1】:

为什么没有 round 值 + unique

df <- data.frame(

  g = c(1.001, 1, 2.00001, 2),
  t = c(1, 1.001, 2.001, 2.0001),
  x = c(1.0001, 1, 2, 2.00001)
)

vect <- sapply(df, function(x) unique(round(x, 2)) )
data.frame(vect)

这仅在每列的长度相等时才有效。

【讨论】:

  • 答案是错误的,因为如果您将第二个 g 值更改为 2,您将获得相同的结果。唯一性需要应用于 data.frame 的行。此外,如果 vaues 是半整数的每一侧,则值不会被假定为相等。 (如 0.49999 和 0.50001 将变为 0 和 1 而不是 0.5)虽然如果问题作者假设值接近整数,那很好,但它又不能处理 epsilon 容差
  • 感谢@W W 和@BenoitLondon 的帮助!我针对更通用的情况编辑了我的问题,这使得该解决方案不再起作用
  • @BenoitLondon 实际上有round(x, 2) 所以对于 0.49999 和 0.50001 它将是:0.50 和 0.50 :)
【解决方案2】:

假设 OP 的示例中存在错误(请参阅我上面的评论),这是在 pasted 行值上使用 duplicated 的解决方案。

如果 OP 澄清并且我误解了问题,将删除。

# Your data
df <- data.frame(
  IDname = c("aaa1", "bbb2", "ccc3", "ddd4"),
  g = c(0.00501, 0.00499, 2, 2),
  t = c(0.005002, 0.004991, 2.001, 2.0001),
  x = c(1.0001, 1, 2, 2.00001)
)

df[!duplicated(apply(round(df[, -1], 3), 1, paste, collapse = "_")), ];
#  IDname       g        t       x
#1   aaa1 0.00501 0.005002 1.00010
#3   ccc3 2.00000 2.001000 2.00000
#4   ddd4 2.00000 2.000100 2.00001

更普遍地适用于任何公差epsilon

epsilon <- 0.0001;
df[!duplicated(apply(round(df[, -1], -log10(epsilon) - 1), 1, paste, collapse = "_")), ];

使用层次聚类的方法(灵感来自@BenoitLondon)

我们可以使用欧几里得距离矩阵进行层次聚类,并通过相似性与聚类观察(行)完全链接。

# Calculate euclidean distance matrix
dist <- dist(df[, -1], method = "euclidean");

# Perform hierarchical clustering with complete linkage
hc <- hclust(dist, method = "complete");

我们现在可以通过识别两个相似观测值之间的最大欧几里德距离由dmax = sqrt(sum_m epsilon^2) = sqrt(m) * epsilon 给出来切割树,其中m 是(数字)列的数量。因此,我们可以在 h = dmax 的高度砍树。

# Cut the tree
epsilon <- 0.0001;
grp <- cutree(hc, h = sqrt(ncol(df[, -1])) * epsilon);
grp;
#[1] 1 1 2 3    

然后折叠的dataframe

df[!duplicated(grp), ];
#  IDname       g        t       x
#1   aaa1 0.00501 0.005002 1.00010
#3   ccc3 2.00000 2.001000 2.00000
#4   ddd4 2.00000 2.000100 2.00001

【讨论】:

  • 感谢指正!我更新了我的问题并包含了一个带有 ID 的新列。你能相应地修改你的答案吗?
  • 原始示例和输出仍然不匹配(epsilon 中的第 3 行和第 4 行仍然不同)。我已经对列IDname 和任意容差epsilon 进行了更改。
  • 如果您将df &lt;- data.frame(a= 0:10, b = 0.001*0:10, c = 1); epsilon = 0.001设为半整数左右的值的奇怪行为,它会保留2行0和6。我认为这个问题是不恰当的,但它可能在这种特殊情况下有效,尽管一般答案将涉及聚类恕我直言。
  • @BenoitLondon 我没有关注你。在您的示例中,如果我这样做 epsilon &lt;- 0.001; df[!duplicated(apply(round(df, -log10(epsilon) - 1), 1, paste, collapse = "_")), ]; 我会保留所有行(如预期的那样)。请注意,在 OP 的示例中,我排除了第一个 ID 列(根据 OP 的要求);在您的示例中,您需要包括所有列
  • @BenoitLondon 您可能对我添加的(分层)聚类方法感兴趣(受您的聚类思想启发)。
猜你喜欢
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
  • 2018-09-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-30
  • 1970-01-01
  • 2022-11-14
相关资源
最近更新 更多