Rでさらに2つの基準を使用して重複する時間間隔を特定する


10

重複したエントリや重複したエントリがないか、長期間にわたる鳥の観察を確認する必要があります。

異なるポイント(A、B、C)の観測者が観測を行い、紙の地図にマークを付けました。種、観測点、およびそれらが見られた時間間隔の追加データを含むラインフィーチャに取り込まれたライン。

通常、観察者は観察中に電話で連絡を取り合いますが、時には忘れてしまうため、重複した行を取得します。

私はすでにデータを円に接する線に減らしたので、空間分析を行う必要はありませんが、各種の時間間隔を比較するだけで、比較によって見つかったのは同じ個体であることを確信できます。

私は今、Rで以下のエントリを識別する方法を探しています。

  • 重複した間隔で同じ日に行われます
  • そしてそれが同じ種である場合
  • 異なる観測点(AまたはBまたはCまたは...)から作成されたもの)

ここに画像の説明を入力してください

この例では、重複する可能性のある同じ個人のエントリを手動で見つけました。観測点が異なり(A <-> B)、種は同じ(Sst)で、開始時間と終了時間の間隔が重なっています。

ここに画像の説明を入力してください

ここで、data.frameに「duplicate」という新しいフィールドを作成し、両方の行にエクスポートできるように共通のIDを与え、後で何をするかを決定します。

すでに利用可能な解決策を探してたくさん検索しましたが、種のプロセスをサブセット化する必要があり(できればループなし)、2 + x観測点の行を比較する必要があるという事実については何も見つかりませんでした。

試してみるデータ:

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")

私はここで言及されているdata.table関数foverlapsの部分的な解決策を見つけました/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)

もちろん、これはどういうわけか「機能」しますが、結局私が達成したいことではありません。

まず、観測点をハードコーディングする必要があります。任意の数のポイントを取るソリューションを見つけたいと思います。

第二に、結果は、本当に簡単に作業を再開できる形式ではありません。一致する行は実際には同じ行に配置されますが、私の目標は行を下に配置することですが、新しい列では、それらに共通の識別子があります。

3番目に、間隔が3つすべてのポイントから重複している場合は、手動でもう一度確認する必要があります(データには当てはまりませんが、通常は可能です)。

最後に、グループIDで識別可能なすべての候補を含む新しいdata.frameを受け取ります。これは、行に戻って追加の調査のために結果をレイヤーとしてエクスポートできます。

だから誰もこれを行う方法のアイデアはありますか?


私は完全に理解しているとは思いませんが、PostgreSQLではかなり単純なタスクのようです。時間範囲の関数があります。私が理解しているとして、それは、PostgreSQLとR.の間で共有データに簡単にする必要があります
ニクラス・アベン

私はPostgresの知識がゼロではないことを認めざるを得ませんが、実際、今晩ビールを飲むとき、私はこれのためにいくつかのSQLものが利用できるかもしれないという考えも持っていました。私がデータセットで行う必要がある残りの操作については、Rがツールですが、SQL関数はいくつかのパッケージを介してR内でも実行できることを知っています。調査中....
Bernd V.

データセットの大きさは何百、何千、何百万行ですか?SQL関数の場合、sqldfは見つかりましたか?
シンバマング2016

その間、私は実用的な解決策を見つけました。恥ずかしいので、今のところ投稿していません。他の人に役立つようにもっと一般的にする必要があります、そして私はそれをできるだけ早く投稿します。
Bernd V.

すべてベクトル化され、forループを使用しない場合は、+ 1されます。
シンバマング2016

回答:


1

一部のコメンターが言及したように、SQLはかなり複雑な制約のセットを表現するのに適したオプションです。sqldfのパッケージには、簡単に自分でリレーショナルデータベースを設定しなくてもRにSQLのパワーを使用できるようになります。

SQLを使用したソリューションを次に示します。実行する前に、データの間隔列の名前をSQLで予約されているため、名前を変更する必要がstartTimeありましendTimefrom

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)

理解を助けるために、SQL応答dupes_wideは次のようになります。

                         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

自己結合 FROM testdata x JOIN testdata y単一のデータセットから行のペアを見つけることは、自己結合です。すべての行を他のすべての行と比較する必要があります。ON式は、ペアを維持するための制約を示しています。

重複する間隔:このSQL(ソース)で使用した重複の定義はfoverlaps、あなたのために行っていたものとはかなり異なると確信しています。「within」タイプを使用しました。これは、前の観測obsPointが完全に後の観測内にあることを必要としますobsPoint(ただし、Cの観測が完全にBの観測内にある場合などは、逆を逃します)。幸運なことに、オーバーラップの異なる定義をエンコードする必要がある場合、SQLでは簡単です。

異なる点:異なる観測点から重複が行われたという制約は、実際に表現され(x.obsPoint <> y.obsPoint)ます。私がそれを入力した場合、SQLは各行で鳥が順序を入れ替えただけで、複製されたすべてのペアを2回返します。代わりに<、行の一意の半分のみを保持するためにaを使用しました。(これはこれを行う唯一の方法ではありません)

一意の重複ID:以前のソリューションと同様に、SQL自体が同じ行に重複をリストします。 SQLiteでのhex(randomblob(16))ハックな(ただし推奨される)方法で、各ペアに一意のIDを生成します。

出力形式:同じ行の重複が気に入らなかったため、melt分割して、merge重複したIDを最初のデータフレームに割り当てます。

制限:私のソリューションは、同じ鳥が3 つ以上のトラックで捕獲される場合を処理しません。それはトリッキーで、やや不明確です。たとえば、時間範囲が次のようになっている場合

    |-Bird1-|
             |-Bird2-|
                      |-Bird3-|

その後、Bird1はの複製であるBird2の複製である、Bird3は、しかしあるBird1Bird3重複?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.