对于一个数据帧中的每一行,查找另一个数据帧中是否存在“关闭”行

时间:2018-06-30 16:19:17

标签: r dplyr summarization

我有以下数据框:

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中是否在所有列中都靠近该行(“邻居”),其中“ 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) )

在这种情况下,没有“邻居”,因此Im应该对df的所有行都获得“ FALSE”。

我的实际数据帧要比这大得多(数十列和数十万行,因此命名必须非常笼统,而不是“ x”,“ y”和“ z”。

我认为可以使用mutatefuns来完成此操作,例如,我尝试了以下这一行:

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

但是出现错误。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

您可以使用软件包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

答案 1 :(得分:0)

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

一般方法是规范所有属性。使每列的范围相同,零到一或负一比一。这样就可以均衡具有大和小值的列的效果。如果使用更高级的方法,则将调整后的列值居中于零。测试标准按相同比例缩放。

下一步是计算每个观察点到其邻近点的距离。如果数据集很小或计算时间很便宜,请计算每个观测值到彼此的距离。从观测值1(行1)到观测值2(行2)的欧几里得距离是sqrt((X1-X2)^ 2 + sqrt((Y1-Y2)^ 2 + ...)。选择您的条件并选择。

在您的情况下,截面标准更简单。如果没有一个属性比另一个观察值大,则两个观察值接近。我假设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。 总距离为零。为此,我们加上曼哈顿距离。当曼哈顿总距离大于.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%的机会与之匹配。示例数据对于该算法而言并不是一个很好的测试案例。

祝你好运

答案 2 :(得分:-1)

这是不使用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)