对于数据框中的每一行,查找另一个数据框中是否有 "close" 行

for each row in a data frame, find whether there is a "close" row in another data frame

我有以下数据框:

library(dplyr)
set.seed(42)
df <- data_frame(x = sample(seq(0, 1, 0.1), 5, replace = T), y = sample(seq(0, 1, 0.1), 5, replace = T), z= sample(seq(0, 1, 0.1), 5, replace = T) )

对于df中的每一行,我想找出df2中是否有一行在所有列中都接近它("neighbor"),其中"close"表示每列相差不超过0.1。

因此,例如,行 (1, 0.5, 0.5) 的适当邻居将是 (0.9, 0.6, 0.4)。 第二组数据为

set.seed(42)
df2 <- data_frame(x = sample(seq(0, 1, 0.1), 10, replace = T), y = sample(seq(0, 1, 0.1), 10, replace = T), z= sample(seq(0, 1, 0.1), 10, replace = T) )

在这种情况下没有 "neighbor",所以我应该为 df 的所有行得到 "FALSE"。

我的实际数据框比这个大很多(几十列,几十万行,所以命名必须很笼统,而不是"x","y"和"z".

我觉得这可以使用 mutatefuns 来完成,例如我试过这一行:

df <- df %>% mutate_all(funs(close = (. <= df2(, .)+0.1) & (. >= df2(, .)-0.1))

但是出错了。

有什么想法吗?

您可以使用包 fuzzyjoin

library(fuzzyjoin)

# adding two rows that match
df2 <- rbind(df2,df[1:2,] +0.01)

df %>%
  fuzzy_left_join(df2,match_fun= function(x,y) y<x+0.1 & y> x-0.1 ) %>%
  mutate(found=!is.na(x.y)) %>%
  select(-4:-6)

# # A tibble: 5 x 4
#     x.x   y.x   z.x found
#   <dbl> <dbl> <dbl> <lgl>
# 1   1     0.5   0.5 TRUE 
# 2   1     0.8   0.7 TRUE 
# 3   0.3   0.1   1   FALSE
# 4   0.9   0.7   0.2 FALSE
# 5   0.7   0.7   0.5 FALSE

在此处查找更多信息:Joining/matching data frames in R

这是一种在没有 fuzzyjoin

的情况下计算该列的方法
library(tidyverse)

found <- 
  expand.grid(row.df  = seq(nrow(df)),
              row.df2 = seq(nrow(df2))) %>% 
      mutate(in.range = pmap_lgl(., ~ all(abs(df[.x,] - df2[.y,]) <= 0.1))) %>% 
      group_by(row.df) %>% 
      summarise_at('in.range', any) %>% 
      select(in.range)

在多维数据集中查找 close 条目的机器学习方法是欧几里得距离。

一般的做法是规范化所有的属性。使每列的 运行ge 相同,零比一或负数一比一。这平衡了具有大值和小值的列的效果。当使用更高级的方法时,人们会将调整后的列值以零为中心。测试标准按比例缩放。

下一步是计算每个观测值与其邻居的距离。如果数据集很小或计算时间很短,计算每个观测值之间的距离。从 observation1 (row1) 到 observation2 (row2) 的欧几里得距离是 sqrt((X1 - X2)^2 + sqrt((Y1 - Y2)^2 + ...)。选择你的标准和 select.

在你的情况下,部分标准更简单。如果没有属性与另一个观察值相差超过 0.1,则两个观察值接近。我假设 df 和 df2 具有相同顺序的相同列数。我假设近距离观察相对较少。我的方法告诉我,一旦我们发现一对距离很远,就停止调查。如果您有数十万行,同时计算所有组合,您可能会耗尽内存。

~~~~~

你有一个大问题。如果您的数据集 df 和 df2 各有十万行和四打列,则机器需要进行 4.8e+11 次比较。最后的记分卡将有 1e+10 个结果(近距离或远距离)。我从一些子集开始与泪流满面的结果进行比较。 R 想要相同大小的矩阵。我设计的 kluge 没有成功。因此,我回到了 FORTRAN 的时代,并用循环来完成。使用循环方法,您可以将问题子集化并在不冒烟的情况下完成。

根据示例数据,我手动进行了比较,全部 150 个:nrow(df) * nrow(df2) * ncol(df)。根据您给出的定义,样本数据中没有密切观察。

这是我打算在 运行将结果提交到 df 中的新列之前呈现结果的方式。

    dfclose <- matrix(TRUE, nrow = nrow(df), ncol = nrow(df2))
    dfclose # Have a look

此矩阵描述了从 df 中的观察(dfclose 中的行)到 df2 中的观察(dfclose 中的列)的距离。如果关闭,则条目为 TRUE。

这里是距离测量结果的存储库:

    dfdist <- matrix(0, nrow = nrow(df), ncol = nrow(df2))
    dfdist # have a look; it's the same format, but with numbers

我们首先假设 df a 中的所有观测值都接近 df2。 总距离为零。为此,我们添加了曼哈顿距离。当曼哈顿总距离大于 0.1 时,它们不再靠近。不用再评价了。

    closeCriterion <- function(origin, dest) {
      manhattanDistance <- abs(origin-dest)
      #print(paste("manhattanDistance =", manhattanDistance))
      if (manhattanDistance < .1) ret <- 0 else ret <- 1
    }

    convertScore <- function(x) if (x>0) FALSE else TRUE

    for (j in 1:ncol(df)) {
      print(paste("col =",j))
      for (i in 1:nrow(df)) {
        print(paste("df row =",i))
        for (k in 1:nrow(df2)) {
          # print(paste("df2 row (and dflist column) =", k))
          distantScore <- closeCriterion(df[i,j], df2[k,j])
          #print(paste("df and dfdist row =", i, "  df2 row (and dflist column) =", k, "     distantScore = ", distantScore))
         dfdist[i,k] <- dfdist[i,k] + distantScore
         }
      }
    }

    dfdist  # have a look at the numerical results

    dfclose <- matrix(lapply(dfdist, convertScore), ncol = nrow(df2))

我想看看这个过程在规模上会是什么样子。

    set.seed(42)
    df <- matrix(rnorm(3000), ncol = 30)
    set.seed(42)
    df2 <-matrix(rnorm(5580), ncol = 30)
    dfdist <- matrix(0, nrow = nrow(df), ncol = nrow(df2))

然后我运行代码块看看会发生什么。

~~~

你可以考虑问题的定义。我 运行 模型好几次,改变了接近度的标准。如果 df2 中三打列的每一列中的条目都有 90% 的机会匹配其在 df 中的对应项,则该行只有 2.2% 的匹配机会。示例数据不是该算法的良好测试用例。

祝你好运