R:匹配两列以重建观测顺序(标记重新捕获历史)

R:匹配两列以重建观测顺序(标记重新捕获历史),r,matching,R,Matching,我有一个类似于我在这里发布的问题: 但是,数据的格式略有不同。一般数据结构是一列中的列表,其中一列是3天内拍摄的照片,另一列是与第1列中的照片相匹配的照片。另一个信息是照片拍摄的日期,因此每天拍摄的个人照片是相互排斥的-特定个人每天的照片不超过一张(即,在我下面的示例中,“a”永远不会与“B”匹配,因为它们都来自第1天) photo这里棘手的部分是找到那些都是同一个人的照片组。如果照片A中的动物与照片G中的动物相匹配,并且照片L与照片G相匹配,则需要一种算法,该算法将识别照片A、G和L作为所有

我有一个类似于我在这里发布的问题:

但是,数据的格式略有不同。一般数据结构是一列中的列表,其中一列是3天内拍摄的照片,另一列是与第1列中的照片相匹配的照片。另一个信息是照片拍摄的日期,因此每天拍摄的个人照片是相互排斥的-特定个人每天的照片不超过一张(即,在我下面的示例中,“a”永远不会与“B”匹配,因为它们都来自第1天)


photo这里棘手的部分是找到那些都是同一个人的照片组。如果照片A中的动物与照片G中的动物相匹配,并且照片L与照片G相匹配,则需要一种算法,该算法将识别照片A、G和L作为所有链接

这是网络分析中的一个经典问题,因此我转向了
igraph
包,它自称为“网络分析和可视化”包。它包括一个函数
clusters()
,该函数将从“邻接矩阵”(对节点之间的连接进行编码的矩阵)中拉出链接的簇,如下所示:

 [1,] 1 . . . . . . . . . . .
 [2,] . 1 . . . . . . . . . .
 [3,] . . 1 . . . . . . . . .
 [4,] . . . 1 . . . . . . . .
 [5,] . . . . 1 . . . . . . .
 [6,] 1 . . . . 1 . . . . . .
 [7,] . 1 . . . . 1 . . . . .
 [8,] . . . . 1 . . 1 . . . .
 [9,] . . . . . . . . 1 . . .
[10,] . . . . . . . . . 1 . .
[11,] 1 . . . . 1 . . . . 1 .
[12,] . . 1 . . . . . . . . 1
上面的矩阵是数据的邻接矩阵。12行和12列代表12张照片,A-L。同一动物的照片标有
1
。其他单元格用点标记,而不是
0
,因为这实际上是一种特殊表示法,专为稀疏矩阵设计,由
矩阵
包提供。(如果你有一个巨大的数据集,我选择了这种表示:
nlarge
photos将生成一个包含
nlarge^2
单元的矩阵,这可能会占用你的计算机内存。)

在下面的代码中,第一个块构造邻接矩阵,第二个块提取每个动物的照片簇,第三个块将结果以您要求的形式放回一起

library(Matrix)
library(igraph)

# Construct an adjacency matrix, in which pairs of photos of the same  
# individual are encoded with 1's
photos <- as.character(unique(DF$photo))
n <- length(photos)
pairs <- subset(DF, !is.na(matching_photo), 
                select = c("photo", "matching_photo"))
pairs[] <- lapply(pairs, FUN=function(X) match(X, photos))
M <- 1 * with(pairs, sparseMatrix(i = c(seq_len(n), photo), 
                                  j = c(seq_len(n), matching_photo)))

# Extract vectors of photos of the same individual
(clust <- clusters(graph.adjacency(adjmatrix=M)))
# $membership
#  [1] 0 1 2 3 4 0 1 4 5 6 0 2
# $csize
# [1] 3 2 2 1 2 1 1
# $no
# [1] 7

# Process results of clustering to construct output data.frame
DF2 <- cbind(individual = clust$membership, 
             subset(DF, !duplicated(photo), select=c("photo", "day")))
grps <- tapply(DF2$photo, DF2$individual, paste, collapse=",")
days <- tapply(DF2$day, DF2$individual, 
               FUN=function(X) paste((1 * unique(DF$day) %in% X), collapse=""))
data.frame(individual = as.numeric(names(grps)), photos = grps, days=days)
#   individual photos days
# 0          0  A,F,K  111
# 1          1    B,G  110
# 2          2    C,L  101
# 3          3      D  100
# 4          4    E,H  011
# 5          5      I  001
# 6          6      J  001
库(矩阵)
图书馆(igraph)
#构造一个邻接矩阵,其中一对相同的照片
#个人用1编码

照片和一些友好的建议:你已经问了几个问题,得到了一些有用的答案(至少,你的评论是这么说的!)。如果您将答案标记为已接受(单击他们旁边的复选标记),如果它解决了您的问题,则对使用此网站的其他人将非常有帮助。这样,别人看到你的问题就会知道哪个答案解决了你的问题。(通常也认为在这里做有礼貌的事)对不起,我会去做。我没有意识到!完成。我花了一分钟才找到那个小复选标记。谢谢,明白了。我在这里总是得到很好的回答!@joran所说的:没问题,当你没有得到一个有效的答案时,不要觉得有任何强迫去接受。我知道你根本不知道——见鬼,你甚至在这个问题的底部提前写了一封感谢信,而且(更妙的是)还发布了可复制的数据!为此干杯!美好的我刚刚试过这个-在这条线上出现了一个错误“我很好,我已经在这上面混了一段时间了,出于一些奇怪的原因,我不能让它在我的真实数据上工作。我希望我没有忽略什么,但我一直在这件事上倾诉。我得到的错误是sparseMatrix线。它说“NA's in(I,j)是不允许的。”。“比较示例数据,j中有NA,但它可以工作,不会抛出错误。这还意味着什么?我已经试着确保我的DF被分割成不同的对象,并且它们是字符格式的,但这没有帮助。这对舞步看起来都很好。。。有什么提示吗?好像pairs文件有问题。它有一个NA。我还没有弄清楚这是如何产生的。数据看起来是正确的。我稍后再报告。好的,我想好了。由于篡改数据时的疏忽,unique列中缺少一张照片!当然了,这真是太棒了!这对大多数人来说可能是显而易见的,但是你不应该在你的对象中得到NA。我得到了一张,因为那个特定数据点的匹配被排除在独特的照片之外。仅供参考,我将此用于WildID的(自定义)分数输出。
 [1,] 1 . . . . . . . . . . .
 [2,] . 1 . . . . . . . . . .
 [3,] . . 1 . . . . . . . . .
 [4,] . . . 1 . . . . . . . .
 [5,] . . . . 1 . . . . . . .
 [6,] 1 . . . . 1 . . . . . .
 [7,] . 1 . . . . 1 . . . . .
 [8,] . . . . 1 . . 1 . . . .
 [9,] . . . . . . . . 1 . . .
[10,] . . . . . . . . . 1 . .
[11,] 1 . . . . 1 . . . . 1 .
[12,] . . 1 . . . . . . . . 1
library(Matrix)
library(igraph)

# Construct an adjacency matrix, in which pairs of photos of the same  
# individual are encoded with 1's
photos <- as.character(unique(DF$photo))
n <- length(photos)
pairs <- subset(DF, !is.na(matching_photo), 
                select = c("photo", "matching_photo"))
pairs[] <- lapply(pairs, FUN=function(X) match(X, photos))
M <- 1 * with(pairs, sparseMatrix(i = c(seq_len(n), photo), 
                                  j = c(seq_len(n), matching_photo)))

# Extract vectors of photos of the same individual
(clust <- clusters(graph.adjacency(adjmatrix=M)))
# $membership
#  [1] 0 1 2 3 4 0 1 4 5 6 0 2
# $csize
# [1] 3 2 2 1 2 1 1
# $no
# [1] 7

# Process results of clustering to construct output data.frame
DF2 <- cbind(individual = clust$membership, 
             subset(DF, !duplicated(photo), select=c("photo", "day")))
grps <- tapply(DF2$photo, DF2$individual, paste, collapse=",")
days <- tapply(DF2$day, DF2$individual, 
               FUN=function(X) paste((1 * unique(DF$day) %in% X), collapse=""))
data.frame(individual = as.numeric(names(grps)), photos = grps, days=days)
#   individual photos days
# 0          0  A,F,K  111
# 1          1    B,G  110
# 2          2    C,L  101
# 3          3      D  100
# 4          4    E,H  011
# 5          5      I  001
# 6          6      J  001