2017-03-30 11 views
4

Iは、次のデータがあると:R data.table距離

d = data.table(id = 1, x = c(1, 10, 17, 35, 37, 45)) 

IはグループIDによってxの各i番目の要素は、30〜要素を有しているかどうかを確認しますそれよりも大きい40。だから、xの最初の要素のid(1)で、1の後のxの値が31と41の間にあるかどうか調べたいと思います。答えはyesです。最初の要素ではTRUEです。最後に、私は、取得するために探しています:

d_final = data.table(id = 1, x = c(1, 10, 17, 35, 37, 45), valid_gap = c(T, T, F, F, F, F)) 

私はしばらくのために同僚と、この質問について考えてきた、と私たちは本当にここにループを使用しないようにしようとしているが、理解することはできませんそれを出す。これはループなしでも可能ですか?

私の最高の試みのようなものです:

d[, valid_gap := any(between(rdist(x[ .N - .I ])[,1], left = 30, right = 40)), by = id] 

が、私は間違った考えである疑いがあるループにいるかのようにXによってインデックスにしようとして問題を考えています。

EDIT - "悪い" ソリューション:

x = c(1, 10, 17, 35, 37, 45) 
valid_gap = c() 

for(i in 1:length(x)) { 
    if(i == length(x)){ 
    valid_gap = c(valid_gap, F) 
    } else { 
    valid_gap = c(valid_gap, any(between(rdist(x[ x >= x[i] ])[,1], left = 30, right = 40))) 
    } 
} 
valid_gap 

事前にありがとうございます!私は非エクイが参加推測

答えて

5

がループよりも高速でなければなりません:行ごとに

d[, v := 
    d[.(id = id, x0 = x + 30, x1 = x + 40), on=.(id, x >= x0, x <= x1), 
    .N 
    , by=.EACHI][, N > 0L] 
] 

    id x  v 
1: 1 1 TRUE 
2: 1 10 TRUE 
3: 1 17 FALSE 
4: 1 35 FALSE 
5: 1 37 FALSE 
6: 1 45 FALSE 

、我々...

  1. は、関心のある区間内のすべての一致を検索します;
  2. これらを数えます(.N)。カウントが0に

を超えた場合、その後

  • チェック最初のステップは、mult="first"でわずかに速いかもしれません。

  • +0

    また、次のようになります。[x> = x [i]])[、1]、left = 30、right = 40) (findInterval(x + 40、x)> i30) ' –

    +0

    @alexis_lazありがとう、それはそれを行うクールな方法です。私はそれが別の答えのために十分に異なっていると思うが、あなたが好きならそれをここに加えることができる。 left.openオプション(x = c(0、30)がc(TRUE、FALSE)を与えるようにする)や、間隔の閉じた/開いた状態を微調整するのに関連するものfindIntervalを使って)。 – Frank

    +0

    あなたは 'left.open = TRUE'について正しいでしょう。それを逃した。また、ソートされた "x"だけを受け入れます。確かに 'findInterval'はそれを使う方法を少し調べる必要があります - 私は、引数の' expand.grid'に 'Map'を使ってすべての可能な使い方を調べています:)。私はそれがあなたの答えに追加することができると思います - それを "グループで"ラップすると、あなたの答えにさらに近づくでしょう。 –

    1
    library('data.table') 
    myfun <- function(y, z) 
    { 
        any(z > y+30 & z < y+40) # check for values between the range 
    } 
    myfun <- Vectorize(FUN = myfun, vectorize.args = 'y') # vectorize myfun() function for 'y' argument 
    
    d = data.table(id = 1, x = c(1, 10, 17, 35, 37, 45)) 
    d[, valid_gap := myfun(y = x, z = x), by = .(id)] 
    d 
    # id x valid_gap 
    # 1: 1 1  TRUE 
    # 2: 1 10  TRUE 
    # 3: 1 17  FALSE 
    # 4: 1 35  FALSE 
    # 5: 1 37  FALSE 
    # 6: 1 45  FALSE 
    
    +0

    @vryb値45の行6がTRUEになる必要がありますか? – Sathish

    +0

    元の質問のサンプルデータを編集して、問題をより明確に示していると思います。私はあなたのアプローチが残念ながら働いているとは思わない。グループidでxのi番目の値より30と40以上の値をチェックしていないので、値30と40をチェックしているだけだ。 17 + 30と17 + 40の間に値がないため、17はFを返します。ここ – vryb

    +0

    は、私が何をしたいのかの "悪い" バージョンです: 'X = cで(1、10、17、35、37、45) valid_gapの=のC()(I 1で用 :長さ(X)){ IF(I ==長さ(X)){ valid_gapの= Cの(valid_gap、F) }他{ valid_gapの= Cの(valid_gap、任意の(間(のrdist(X } } valid_gap' – vryb