1
df1 <- data.frame(Chr=1, Pos= c(100,200,300,400),stringsAsFactors=F)

df2 <- data.frame(Chr=1, PosStart= c(25,25,150,175,225,275,375),PosEnd= c(150,75,275,300,400,500,750),stringsAsFactors=F)

Posの値を比較して、df1anyPosStartPosEndof の間にあるかどうかを確認しようとしていますdf2。これは の 1 行以上の場合に当てはまりますdf2df1$Pos出力では、新しい列として追加しようとしていますdf2$CoPos。条件が true になるたびに。出力は次のようになります。

Chr PosStart PosEnd CoPos
1       25    150   100
1      150    275   200
1      175    300   200
1      225    400   300
1      275    500   300
1      375    750   400

私は次のようなことをしました:

for(i in 1:length(df1$Pos)){

    for(j in 1:length(df2$PosStart){

            df2$CoPos[j]<- df1$Pos[which(df2$PosStart[j] < df1$Pos[i] < df2$PosEnd[j])]
    }

}

ループせずにこれを行う方法があれば、誰か教えてください。また、ここで何が間違っていますか?何ヶ月もグラップリングした後でも、ループの概念をまだ理解していないと思います。

事前にたくさんありがとう。

4

2 に答える 2

5

applyの各行をチェックできます。df2

myfun <- function(x) {
  data.frame(df2[x['Pos'] < df2$PosEnd & x['Pos'] > df2$PosStart,], Pos=x['Pos'])
}

これは、条件が満たされたdf2から1つまたは複数の行と値を返しPosます。

> apply(df1, 1, myfun)
[[1]]
  Chr PosStart PosEnd Pos
1   1       25    150 100

[[2]]
  Chr PosStart PosEnd Pos
3   1      150    275 200
4   1      175    300 200

[[3]]
  Chr PosStart PosEnd Pos
5   1      225    400 300
6   1      275    500 300

[[4]]
  Chr PosStart PosEnd Pos
6   1      275    500 400
7   1      375    750 400

> 

次に、とを使用してリストに変換できplyrますldply

> library(plyr)
> ldply(apply(df1, 1, myfun), as.data.frame)
  Chr PosStart PosEnd Pos
1   1       25    150 100
2   1      150    275 200
3   1      175    300 200
4   1      225    400 300
5   1      275    500 300
6   1      275    500 400
7   1      375    750 400
> 

コメントのために編集:

これは、forループで行うのは難しいことです。事前にいくつの試合があるかわかりません。のすべての行がのすべての行とdf1一致するか、df2またはその間に何も一致しない可能性があります。したがって、出力をどれだけ大きくする必要があるかはわかりません。これは、Rでの悪いfor loop習慣の完璧な例です。のように、出力ベクトルに割り当てるのではなく、出力ベクトルを大きくしている場合は、「悪い時間になるでしょう」と言います。

そうは言っても、ループを機能させるには、CoPos最初に列を作成する必要があります。

df2$CoPos <- NA

次に、ループに似たものを実行します。

for (i in 1:length(df1$Pos)) {
    for (j in 1:length(df2$PosStart)) {
            if (df2$PosStart[j] < df1$Pos[i] & df2$PosEnd[j] > df1$Pos[i]) {
                    df2$CoPos[j] <- df1$Pos[i]
            }
    }

}

ただし、df1制約に適合する2つの行が見つかった場合は、2番目に見つかった行のみをの適切な行に記録しますdf2

代わりに、次のように新しいdata.frameを拡張できます。

df3 <- data.frame(Chr=1, Pos= c(100, 125, 200,300,400),stringsAsFactors=F)

out <- data.frame()

for (i in 1:length(df3$Pos)) {
    for (j in 1:length(df2$PosStart)) {
            if (df2$PosStart[j] < df3$Pos[i] & df2$PosEnd[j] > df3$Pos[i]) {
                    out <- rbind(out, cbind(df2[j,], df3$Pos[i]))
            }
    }

}

しかし、これをしないでください...しないでください:)私が伝道している間、 Rの一般的な落とし穴に関する優れた参考資料としてR-インフェルノを見てください。

于 2012-07-27T18:27:54.550 に答える
3

この場合は@Justin回答が機能しますが、各行/列を呼び出す前に data.frame をマトリックスに変換するapplyことを覚えていないと、data.frame で使用すると混乱を招くエラーが発生する可能性があります。applyFUN

この潜在的な問題を回避する、より一般的な解決策を次に示します。

compareFun <- function(x) {
  data.frame(df2[x > df2$PosStart & x < df2$PosEnd,], Pos=x)
}
do.call(rbind, lapply(df1$Pos, compareFun))

詳しく説明すると、df1anddf2が代わりChrに文字で定義されている場合、ジャスティンのソリューションはエラーをスローし、問題の原因が明確にならない:

df1 <- data.frame(Chr="1", Pos=c(100,200,300,400), stringsAsFactors=FALSE)
df2 <- data.frame(Chr="1", PosStart=c(25,25,150,175,225,275,375),
  PosEnd=c(150,75,275,300,400,500,750), stringsAsFactors=FALSE)
apply(df1, 1, myfun)
# Error in data.frame(df2[x["Pos"] < df2$PosEnd & x["Pos"] > df2$PosStart,  : 
#  arguments imply differing number of rows: 0, 1
于 2012-07-27T20:25:24.697 に答える