R: сопоставление двух столбцов для восстановления порядка наблюдений (история пометки-повторного захвата)

У меня есть проблема, похожая на ту, что я писал здесь:

Сравнение двух столбцов: логический- значение из столбца 1 также находится в столбце 2?

Однако данные представлены в несколько ином формате. Общая структура данных — это список в одном столбце фотографий, сделанных за 3-дневный период, и другой столбец фотографий, которые соответствуют фотографиям в столбце 1. Другая информация — это день, когда была сделана фотография, так что люди за каждый день взаимоисключающие — не более одной фотографии конкретного человека в день (т. е. «А» никогда не будет соответствовать «Б» в моем примере ниже, потому что они оба из дня 1).

photo <- c('A','B','C','D','E','F','G','H','I','J','K','K','L')
day <- c(1,1,1,1,2,2,2,3,3,3,3,3,3)
matching_photo <- c(NA,NA,NA,NA,NA,'A','B','E',NA,NA,'F','A','C')
DF <- data.frame(photo,day,matching_photo)

Выходные данные, которые я ищу, таковы:

serial.no <- c(1,2,3,4,5,6)
individuals <- c('A,F,K','B,G','C,L','D','E,H','I')
histories <- c('111','110','101','100','011','001')
finalDF <- data.frame(individuals,histories)

Который включает в себя серийный номер для идентификации человека (придуманный по ходу дела, так что просто начните с последовательного ряда с 1), список фотографий, соответствующих каждому человеку в столбце, и истории. Истории имеют двоичный формат, поэтому, если вас наблюдали в первый день, а не до третьего дня, ваша история будет «101». Но если бы вас наблюдали только во второй день, ваша история была бы «010».

Одна из проблем, с которыми я столкнулся с этим конкретным набором данных (по сравнению с проблемой, указанной выше), заключается в том, что если человека видят 3 дня подряд, в столбце фотографий есть две записи для этого человека («K» в мой пример выше), совпадающие фотографии обоих предыдущих дней ("A" и "F"). Я ценю любую оказанную помощь. Спасибо!


person Nate    schedule 12.01.2012    source источник
comment
Небольшой дружеский совет: вы задали несколько вопросов, на которые получили несколько полезных ответов (по крайней мере, на это указывают ваши комментарии!). Если вы отметите ответ как принятый (щелкните галочку рядом с ответом), если он решит вашу проблему, другим пользователям этого сайта будет очень полезно. Таким образом, другие, просматривающие ваш вопрос, узнают, какой ответ решил вашу проблему. (Это также обычно считается вежливым поступком здесь.)   -  person joran    schedule 12.01.2012
comment
Извините, я пойду сделаю это. Я этого не понимал! Сделанный. Мне потребовалась минута, чтобы найти маленькую галочку. Спасибо.   -  person Nate    schedule 12.01.2012
comment
Понятно. Я всегда получал хорошие ответы здесь!   -  person Nate    schedule 12.01.2012
comment
Что сказал @joran: никаких проблем, и не чувствуйте принуждения принимать, когда вы не получаете ответ, который работает. Я знал, что вы просто не знали - черт возьми, вы даже заранее поблагодарили внизу этого вопроса и (что еще лучше) опубликовали воспроизводимые данные! Спасибо за это!   -  person Josh O'Brien    schedule 12.01.2012


Ответы (1)


Сложность здесь заключается в том, чтобы найти те группы фотографий, которые принадлежат одному и тому же человеку. Если животное на фотографии 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 фотографий, A-L. Фотографии одного и того же животного отмечены цифрой 1. Другие ячейки отмечены точками, а не 0, потому что это на самом деле специальное представление, разработанное для разреженных матриц и предоставляемое пакетом Matrix. (Я выбрал это представление на случай, если у вас огромный набор данных: nlarge фотографий создадут матрицу с 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
person Josh O'Brien    schedule 12.01.2012
comment
Хороший. Я только что попробовал это - получил ошибку в этой строке M ‹- 1 * with (pairs2, sparseMatrix (i = c (seq_len (n), photo), должны ли пары2 быть парами? Кажется, это работает, если я сделаю это редактирование .Сейчас попробую на своих реальных данных.Отчитаюсь.Спасибо. - person Nate; 13.01.2012
comment
Ну, я какое-то время возился с этим, и по какой-то странной причине я не могу заставить его работать с моими реальными данными. Надеюсь, я ничего не упустил из виду, но я долго выкладывался по этому поводу. Ошибка, которую я получаю, относится к строке sparseMatrix. В нем говорится, что NA в (i,j) не разрешены. Сравнивая данные примера, в j есть NA, но он работает и не выдает эту ошибку. Что еще это может означать? Я пытался убедиться, что мой DF разделен на разные объекты и что они имеют символьный формат, но это не помогло. Кажется, что все парные шаги работают нормально... Любые советы? - person Nate; 13.01.2012
comment
Похоже, что-то не так с файлом пар. У него есть NA. Я не понял, как именно это генерируется, хотя. Данные выглядят правильно. Я отчитаюсь позже. - person Nate; 13.01.2012
comment
Хорошо, я понял это. Из-за недосмотра при обработке данных в уникальной колонке отсутствовала одна фотография! Пар для курса. - person Nate; 13.01.2012
comment
Это работает фантастически!!!!!!!!!!!!!!!!!!! Это, вероятно, очевидно для большинства людей, но вы не должны получать NA в своем объекте пар. Я получил один, потому что совпадение для этой конкретной точки данных было исключено из уникальных фотографий. К вашему сведению, я использую это для (настраиваемого) вывода результатов WildID. - person Nate; 13.01.2012
comment
Рад, что это сработало для вас. Я был заинтригован отчасти из-за моего собственного опыта, и основные интересы связаны с экологией. Не могли бы вы оставить ссылку на программу WildID, о которой вы говорите? - person Josh O'Brien; 13.01.2012
comment
Как ребенок R, я вполне уверен, что мне потребовались бы недели, если не месяцы, чтобы решить эту проблему самостоятельно, так что еще раз спасибо. Я даже не слышал об igraph. Проблема, на которую я ссылаюсь в своем посте, решает, как использовать вывод WildID по умолчанию. Проблема, которую вы помогли мне решить, связана с полным дампом данных, который создается пользовательской программой java от одного из авторов. Мне нужно проконсультироваться с ним, прежде чем я дам эту ссылку. Это огромная экономия времени, если программа на 100% точна для вашей проблемы. Вот ванильный WildID: dartmouth.edu/~envs/faculty/bolger.html< /а> - person Nate; 13.01.2012
comment
Джош, если вас интересует программа, которая создает файл дампа результатов, я могу отправить его вам по электронной почте, но не могу предоставить общедоступную ссылку. Как отправить ПМ на этом сайте? - person Nate; 14.01.2012
comment
Привет, Нейт. Я думаю, это возможно, только если мы начнем сеанс чата, а я действительно не знаю, как это сделать. Тем не менее, мне было бы интересно посмотреть программу. Мой адрес электронной почты: josh m obrien AT gmail com (без пробелов). Я удалю это, как только получу от вас известие. Спасибо! - person Josh O'Brien; 18.01.2012
comment
Джош, только что отправил тебе письмо. - person Nate; 27.01.2012