Xác định các khoảng thời gian chồng chéo với hai tiêu chí nữa trong R?


10

Tôi phải kiểm tra các quan sát chim được thực hiện trong một khoảng thời gian dài hơn cho các mục trùng lặp / chồng chéo.

Các quan sát viên từ các điểm khác nhau (A, B, C) đã quan sát và đánh dấu chúng trên bản đồ giấy. Những dòng được đưa vào một tính năng dòng với dữ liệu bổ sung cho loài, điểm quan sát và khoảng thời gian chúng được nhìn thấy.

Thông thường, các nhà quan sát giao tiếp với nhau qua điện thoại trong khi quan sát, nhưng đôi khi họ quên, vì vậy tôi nhận được những dòng trùng lặp đó.

Tôi đã giảm dữ liệu xuống các dòng chạm vào vòng tròn, vì vậy tôi không phải phân tích không gian, mà chỉ so sánh các khoảng thời gian cho mỗi loài và có thể khá chắc chắn rằng đó là cùng một cá thể được tìm thấy bằng cách so sánh .

Bây giờ tôi đang tìm cách trong R để xác định các mục đó:

  • được thực hiện trong cùng một ngày với một khoảng thời gian chồng chéo
  • và nơi nó là cùng một loài
  • và được tạo từ các điểm quan sát khác nhau (A hoặc B hoặc C hoặc ...))

nhập mô tả hình ảnh ở đây

Trong ví dụ này, tôi tìm thấy thủ công các mục có thể trùng lặp của cùng một cá nhân. Điểm quan sát là khác nhau (A <-> B), các loài là như nhau (Sst) và khoảng thời gian bắt đầu và kết thúc trùng nhau.

nhập mô tả hình ảnh ở đây

Bây giờ tôi sẽ tạo một trường mới "trùng lặp" trong data.frame của mình, cung cấp cho cả hai hàng một id chung để có thể xuất chúng và sau đó quyết định xem phải làm gì.

Tôi đã tìm kiếm rất nhiều giải pháp đã có sẵn, nhưng không tìm thấy bất kỳ điều gì liên quan đến thực tế là tôi phải đặt lại quy trình cho loài (tốt nhất là không có vòng lặp) và phải so sánh các hàng cho các điểm quan sát 2 + x.

Một số dữ liệu để chơi xung quanh:

testdata <- structure(list(bird_id = c("20150712_0810_1410_A_1", "20150712_0810_1410_A_2", 
"20150712_0810_1410_A_4", "20150712_0810_1410_A_7", "20150727_1115_1430_C_1", 
"20150727_1120_1430_B_1", "20150727_1120_1430_B_2", "20150727_1120_1430_B_3", 
"20150727_1120_1430_B_4", "20150727_1120_1430_B_5", "20150727_1130_1430_A_2", 
"20150727_1130_1430_A_4", "20150727_1130_1430_A_5", "20150812_0900_1225_B_3", 
"20150812_0900_1225_B_6", "20150812_0900_1225_B_7", "20150812_0907_1208_A_2", 
"20150812_0907_1208_A_3", "20150812_0907_1208_A_5", "20150812_0907_1208_A_6"
), obsPoint = c("A", "A", "A", "A", "C", "B", "B", "B", "B", 
"B", "A", "A", "A", "B", "B", "B", "A", "A", "A", "A"), species = structure(c(11L, 
11L, 11L, 11L, 10L, 11L, 10L, 11L, 11L, 11L, 11L, 10L, 11L, 11L, 
11L, 11L, 11L, 11L, 11L, 11L), .Label = c("Bf", "Fia", "Grr", 
"Kch", "Ko", "Lm", "Rm", "Row", "Sea", "Sst", "Wsb"), class = "factor"), 
    from = structure(c(1436687150, 1436689710, 1436691420, 1436694850, 
    1437992160, 1437991500, 1437995580, 1437992360, 1437995960, 
    1437998360, 1437992100, 1437994000, 1437995340, 1439366410, 
    1439369600, 1439374980, 1439367240, 1439367540, 1439369760, 
    1439370720), class = c("POSIXct", "POSIXt"), tzone = ""), 
    to = structure(c(1436687690, 1436690230, 1436691690, 1436694970, 
    1437992320, 1437992200, 1437995600, 1437992400, 1437996070, 
    1437998750, 1437992230, 1437994220, 1437996780, 1439366570, 
    1439370070, 1439375070, 1439367410, 1439367820, 1439369930, 
    1439370830), class = c("POSIXct", "POSIXt"), tzone = "")), .Names = c("bird_id", 
"obsPoint", "species", "from", "to"), row.names = c("20150712_0810_1410_A_1", 
"20150712_0810_1410_A_2", "20150712_0810_1410_A_4", "20150712_0810_1410_A_7", 
"20150727_1115_1430_C_1", "20150727_1120_1430_B_1", "20150727_1120_1430_B_2", 
"20150727_1120_1430_B_3", "20150727_1120_1430_B_4", "20150727_1120_1430_B_5", 
"20150727_1130_1430_A_2", "20150727_1130_1430_A_4", "20150727_1130_1430_A_5", 
"20150812_0900_1225_B_3", "20150812_0900_1225_B_6", "20150812_0900_1225_B_7", 
"20150812_0907_1208_A_2", "20150812_0907_1208_A_3", "20150812_0907_1208_A_5", 
"20150812_0907_1208_A_6"), class = "data.frame")

Tôi đã tìm thấy một giải pháp một phần với các hàm foverlaps của hàm data.table được đề cập, ví dụ ở đây /programming//q/25815032

library(data.table)
#Subsetting the data for each observation point and converting them into data.tables
A <- setDT(testdata[testdata$obsPoint=="A",])
B <- setDT(testdata[testdata$obsPoint=="B",])
C <- setDT(testdata[testdata$obsPoint=="C",])

#Set a key for these subsets (whatever key exactly means. Don't care as long as it works ;) )
setkey(A,species,from,to)    
setkey(B,species,from,to)
setkey(C,species,from,to)

#Generate the match results for each obsPoint/species combination with an overlapping interval
matchesAB <- foverlaps(A,B,type="within",nomatch=0L) #nomatch=0L -> remove NA
matchesAC <- foverlaps(A,C,type="within",nomatch=0L) 
matchesBC <- foverlaps(B,C,type="within",nomatch=0L)

Tất nhiên, điều này bằng cách nào đó "hoạt động", nhưng thực sự không phải là điều tôi muốn đạt được cuối cùng.

Đầu tiên, tôi phải cứng mã các điểm quan sát. Tôi muốn tìm một giải pháp lấy một số điểm tùy ý.

Thứ hai, kết quả không ở định dạng mà tôi thực sự có thể tiếp tục làm việc dễ dàng. Các hàng khớp thực sự được đặt VÀO cùng một hàng, trong khi mục tiêu của tôi là đặt các hàng bên dưới và trong một cột mới, chúng sẽ có một định danh chung.

Thứ ba, tôi phải kiểm tra lại một cách thủ công, nếu một khoảng trùng lặp từ cả ba điểm (không đúng với dữ liệu của tôi, nhưng nói chung là có thể)

Cuối cùng, tôi chỉ muốn nhận một dữ liệu mới. Trò chơi với tất cả các ứng cử viên được nhận dạng bởi một id nhóm mà tôi có thể tham gia trở lại các dòng và xuất kết quả dưới dạng một lớp để kiểm tra thêm.

Vì vậy, bất cứ ai có thêm ý tưởng làm thế nào để làm điều này?


Tôi không chắc là tôi hiểu đầy đủ, nhưng có vẻ như đây là một nhiệm vụ khá đơn giản trong PostgreQuery. Có chức năng cho phạm vi thời gian. Như tôi đã hiểu nó phải được dễ dàng để chia sẻ dữ liệu giữa PostgreSQL và R.
Nicklas Aven

Tôi phải thừa nhận rằng tôi không có kiến ​​thức nào về Postgres, nhưng thực sự, khi uống bia tối nay, tôi cũng có ý tưởng rằng một số thứ sql có thể có sẵn cho việc này. Đối với phần còn lại của hoạt động tôi phải thực hiện với tập dữ liệu, R là công cụ THE, nhưng tôi biết rằng các hàm sql cũng có thể được thực hiện trong R thông qua một số gói. Điều tra ....
Bernd V.

Bộ dữ liệu lớn đến mức nào - hàng trăm, hàng nghìn, hàng triệu hàng? Đối với các hàm SQL bạn đã tìm thấy sqldf ?
Simbamangu

Trong khi đó, tôi tìm thấy một giải pháp làm việc. Thật xấu hổ cho tôi tôi đã không đăng nó cho đến nay. Sẽ phải làm cho nó chung chung hơn để sử dụng cho người khác, và sau đó tôi sẽ đăng nó càng sớm càng tốt.
Bernd V.

Sẽ +1 nó nếu tất cả được véc tơ hóa và không sử dụng forcác vòng lặp!
Simbamangu

Câu trả lời:


1

Như một số nhà bình luận đã ám chỉ, SQL là một lựa chọn tốt để thể hiện các bộ ràng buộc khá phức tạp. Các sqldf gói làm cho nó dễ dàng để sử dụng sức mạnh của SQL trong R mà không cần phải thiết lập một cơ sở dữ liệu quan hệ cho mình.

Đây là một giải pháp sử dụng SQL. Trước khi chạy, tôi phải đổi tên các cột khoảng thời gian của dữ liệu của bạn thành startTimeendTimevì tên fromđược dành riêng trong SQL.

library(reshape2)
library(sqldf)

dupes_wide <- sqldf("SELECT hex(randomblob(16)) dupe_id, x.bird_id x_bird_id, y.bird_id y_bird_id
                     FROM testdata x JOIN testdata y
                          ON (x.startTime <= y.endTime)
                         AND (x.endTime >= y.startTime)
                         AND (x.species = y.species)
                         AND (x.obsPoint < y.obsPoint)")
dupes_long <- melt(dupes_wide, id.vars='dupe_id', value.name='bird_id')
merge(testdata, dupes_long[, c('dupe_id', 'bird_id')], by='bird_id', all.x=TRUE)

Để hỗ trợ sự hiểu biết, phản hồi SQL dupes_widekết thúc giống như thế này:

                         dupe_id x_bird_id y_bird_id
253FCC7A58FD8401960FC5D95153356C 20150727_1130_1430_A_2 20150727_1120_1430_B_1
9C1C1A13306ECC2DF78004D421F70CE6 20150727_1130_1430_A_5 20150727_1120_1430_B_4
1E8316DBF631BBF6D2CCBD15A85E6EF3 20150812_0907_1208_A_5 20150812_0900_1225_B_6

Tự tham gia FROM testdata x JOIN testdata y : Tìm các cặp hàng từ một tập dữ liệu là tự tham gia. Chúng ta cần so sánh mọi hàng với mọi thứ khác. Các ONbiểu hiện liệt kê các khó khăn cho việc giữ cặp.

Khoảng chồng lấp : Tôi khá chắc chắn định nghĩa về sự chồng lấp mà tôi đã sử dụng trong SQL ( nguồn ) này khác với những gì foverlapsđang làm cho bạn. Bạn đã sử dụng loại "bên trong", yêu cầu quan sát sớm hơn obsPointhoàn toàn trong phạm vi quan sát sau đó obsPoint(nhưng nó bỏ qua điều ngược lại, ví dụ nếu quan sát của C hoàn toàn nằm trong B '). May mắn thay, nó dễ dàng trong SQL nếu bạn cần mã hóa một định nghĩa khác về sự chồng chéo.

Điểm khác nhau : Hạn chế của bạn rằng các bản sao được tạo từ các điểm quan sát khác nhau sẽ thực sự được thể hiện (x.obsPoint <> y.obsPoint). Nếu tôi gõ nó, SQL sẽ trả về mọi cặp được nhân đôi hai lần, chỉ với các lệnh chuyển đổi chim trong mỗi hàng. Thay vào đó tôi đã sử dụng một <để chỉ giữ một nửa hàng duy nhất. (Đây không phải là cách duy nhất để làm điều này)

ID trùng lặp duy nhất : Giống như giải pháp trước đó của bạn, chính SQL liệt kê các bản sao trong cùng một hàng. hex(randomblob(16))là một cách hacky ( chưa được khuyến nghị ) trong SQLite để tạo ID duy nhất cho mỗi cặp.

Định dạng đầu ra : Bạn không thích các bản sao trong cùng một hàng, vì vậy hãy melttách chúng ra và mergegán ID trùng lặp lại cho khung dữ liệu ban đầu của bạn.

Hạn chế : Giải pháp của tôi không xử lý trường hợp cùng một con chim bị bắt trong hơn hai bản nhạc . Nó phức tạp hơn và hơi khó định nghĩa. Ví dụ: nếu khoảng thời gian của họ trông giống như

    | - Chim1 - |
             | - Chim2 - |
                      | - Chim3 - |

thì Bird1 là bản sao của Bird2 , là bản sao của Bird3 , nhưng Bird1Bird3 có phải là bản sao không?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.