【问题标题】:Find nearest neighbour of points with the same value when comparing 2 different data sets in R在比较 R 中的 2 个不同数据集时找到具有相同值的点的最近邻
【发布时间】:2016-05-14 05:42:33
【问题描述】:

我有 2 个数据框(df1 和 df2),由三列组成; x 坐标、y 坐标、类别(有 5 个级别 A-E)。所以我基本上有两组点数据,每个点都被分配到一个类别

例如

X    Y    Cat
1    1.5  A
2    1.5  B
3.3  1.9  C

等等... (尽管我的两个数据框中都有 100 个点)

我想从第二个数据帧 (df2) 中为我的第一个数据帧 (df1) 中的每个点找到同一类别的最近邻。

我在spatstat包中使用了nncross,用df2为df1中的每个点找到最近的邻居,然后列出这些距离中的每一个,如下所示;

# Convert the dataframes to ppp objects

df1.ppp <- ppp(df1$X,df1$Y,c(0,10),c(0,10),marks=df1$Cat)
df2.ppp <- ppp(df2$X,df2$Y,c(0,10),c(0,10),marks=df2$Cat)

# Produce anfrom output that lists the distance from each point in df1 to its nearest neighbour in df2

out<-nncross(X=df1.ppp,Y=df2.ppp,what=c("dist","which"))

但是我正在努力弄清楚如何使用存储在 ppp 对象中的类别标签(由标记定义)来从同一类别中找到最近的邻居。我相信它应该是相当直截了当的,但如果有人有任何建议或任何替代方法来达到相同的结果,我将不胜感激。

【问题讨论】:

    标签: r nearest-neighbor spatstat


    【解决方案1】:

    首先要处理一些人工数据:

    library(spatstat)
    
    # Artificial data similar to the question
    set.seed(42)
    X1 <- rmpoint(100, win = square(10), types = factor(LETTERS[1:5]))
    X2 <- rmpoint(100, win = square(10), types = factor(LETTERS[1:5]))
    

    然后是一个简单的解决方案(但它会丢失 id 信息):

    # Separate patterns for each type:
    X1list <- split(X1)
    X2list <- split(X2)
    
    # For each point in X1 find nearest neighbour of same type in X2:
    out <- list()
    for(i in 1:5){
      out[[i]] <- nncross(X1list[[i]], X2list[[i]], what=c("dist","which"))
    }
    

    最后,一个丑陋的解决方案,恢复邻居的 id:

    # Make separate marks for pattern 1 and 2 and collect into one pattern
    marks(X1) <- factor(paste0(marks(X1), "1"))
    marks(X2) <- factor(paste0(marks(X2), "2"))
    X <- superimpose(X1, X2)
    
    # For each point get the nearest neighbour of each type from both X1 and X2
    # (both dist and index)
    nnd <- nndist(X, by = marks(X))
    nnw <- nnwhich(X, by = marks(X))
    
    # Type to look for. I.e. the mark with 1 and 2 swapped
    # (with 0 as intermediate step)
    type <- marks(X)
    type <- gsub("1", "0", type)
    type <- gsub("2", "1", type)
    type <- gsub("0", "2", type)
    
    # Result
    rslt <- cbind(as.data.frame(X), dist = 0, which = 0)
    for(i in 1:nrow(rslt)){
      rslt$dist[i] <- nnd[i, type[i]]
      rslt$which[i] <- nnw[i, type[i]]
    }
    
    # Separate results
    rslt1 <- rslt[1:npoints(X1),]
    rslt2 <- rslt[npoints(X1) + 1:npoints(X2),]
    rslt1$which <- rslt1$which - npoints(X1)
    

    【讨论】:

    • 谢谢,这对点文件很有效,尽管我最终也设法通过从原始数据帧创建距离矩阵来解决这个问题!
    【解决方案2】:

    我还尝试了另一种方法来解决这个问题,但是通过使用 geosphere 包从我的原始数据帧创建一个距离矩阵,并找到了一种非常简单的方法来解决这个问题。

    # load geosphere library 
    library("geosphere")
    
    #create a distance matrix between all points in the 2 dataframes
    dist<-distm(df1[,c('X','Y')],df2[,c('X','Y')])
    
    # find the nearest neighbour to each point
    df1$nearestneighbor <- apply(dist,1,min)
    
    # create a distance matrix where only the distances between points of the same category are recorded
    sameCat <- outer(df1$Cat, df2$Cat, "!=")
    dist2 <- dist + ifelse(sameCat, Inf, 0)
    
    # find the nearest neighbour of the same category
    df1$closestmatch <- apply(dist2,1,min)
    

    【讨论】:

    • 非常好的解决方案。但是,我猜你丢失了关于df2 中的哪个点是与df1 中的点最近的邻居的信息。你不需要那个吗?要使用 spatstat 执行此操作,您基本上只需将 distm 替换为 crossdist
    • 是的(尽管这不是必需的),知道哪些点邻居的信息当然非常有用,因此您的解决方案非常方便。
    猜你喜欢
    • 2014-12-01
    • 2020-09-16
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 2021-01-30
    相关资源
    最近更新 更多