2017-01-05 8 views
1

これは明らかなものでなければならないと思うが、一日中それをパズルして答えを探しているので、いくつかの入力。apply()を使用して行列をサブセット化するときの返り値の奇妙な振る舞い

短いバージョンでは、データフレームを別のデータフレームの値でサブセット化して平均を返すためにapply()を使用すると、入力行の数が9より大きい場合は最初の9回の反復に対してNAが返されます。入力行の数が9より少ない場合、そのデータは正常に戻されます。それを引き起こすために私が何をしたのかはわかりません。

私は2つのデータフレームを持っています。最初のデータは、多数のサンプルから順に取られたデータです。 「ID」列の因子レベルはサンプルを表す。各因子内で、「長さ」欄は、サンプルを横切る線で測定が行われた場所に対応する。 2つの異なる測定値に対して2つのデータ列があります。

set.seed(10) 
ID=factor(sort(rep(paste(letters[1:10]), times=10))) 
Length=seq(1:10) + runif(10, 0, 0.9) 
Values_1=c(1:20) 
Values_2=c(21:40) 
test_data=cbind.data.frame(ID, Length, Values_1, Values_2) 

次の私は「TEST_DATA」の「長さ」の列のサブセットに使用するカットオフ値の行列があります。以下は、これがどのように見えるかの単純化され、再現性、表現です。各行には、サブセットのサンプルとそのサブセットの開始点と終了点が表示されます。

ID2=sort(rep(paste(letters[1:10]), times=2)) 
Start=c(1, 5, 1, 5) 
Stop=c(5, 10, 7, 10) 
Row=c(1:20) 
cutoffs=cbind.data.frame(ID2, Start, Stop, Row) 
colnames(cutoffs)=c("ID", "Start", "Stop", "Row") 
#I'm recycling the cutoffs here. In reality the cutoffs are all pretty different 

私は手動でデータをサブセット場合、それは私が選ぶ任意の行のために働く、

r=9 
subset1=test_data$Values_1[test_data[,1] == cutoffs[r,1] & 
          test_data[,2] >= cutoffs[r,2] & 
          test_data[,2] <= cutoffs[r,3] & 
          !is.na(test_data[,3])] 
#[1] 1 2 3 4 
mean(subset1) 
#There are no NA's in this test data, but the !is.na is there to catch NA's that exist in the real data 

が、私はすべてのデータのものをサブセットに適用される機能を構築奇妙な取得し、私はなぜか。関数を実行すると、cutoffs [10:20、]の値だけが返され、最初の9つのサンプルにはNAが与えられます。しかし、行1と行9の間のカットオフのサブセットを実行すると、正しい値が返されます。

apply(cutoffs, 1, function(x){ 
    subset_1=test_data$Values_1[test_data[,1] == cutoffs[x[4],1] & 
           test_data[,2] >= cutoffs[x[4],2] & 
           test_data[,2] <= cutoffs[x[4],3] & 
           !is.na(test_data[,3])] 
    subset_2=test_data$Values_2[test_data[,1] == cutoffs[x[4],1] & 
           test_data[,2] >= cutoffs[x[4],2] & 
           test_data[,2] <= cutoffs[x[4],3] & 
           !is.na(test_data[,4])] 
    Mean_1=mean(subset_1) 
    Mean_2=mean(subset_2) 
    c(Mean_1, Mean_2) 
}) 

    #  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20] 
    #[1,] NA NA NA NA NA NA NA NA NA  7 13.5 17 2.5  7 13.5 17 2.5  7 13.5 17 
    #[2,] NA NA NA NA NA NA NA NA NA 27 33.5 37 22.5 27 33.5 37 22.5 27 33.5 37 

#Running the same function, but subsetting below 9 rows it returns the correct values 
#apply(cutoffs[1:9,], 1, function(x){... 
#  1 2 3 4 5 6 7 8 9 
#[1,] 2.5 7 13.5 17 2.5 7 13.5 17 2.5 
#[2,] 22.5 27 33.5 37 22.5 27 33.5 37 22.5 

私は、これには何らかの正当な理由があることがわかっていますが、私はそれが何であるか把握できません。どんな助けでも大歓迎です。

もっとエレガントな方法があれば教えてください。実際のデータセットははるかに大きく、 "cutoffs"に相当するのは約3K行、 "test_data"は250K行です。この関数は実行に長い時間がかかりますので、これを行うより良い方法があると仮定しています。

+0

予想される出力を表示できますか?それは単なるサブセットですか? – akrun

答えて

1

まず、は、データフレームにapplyを使用しません。これは、dfを行列に変換します。つまり、すべての列が単一の型に変換されます。特に、列のいずれかが文字または因子である場合、結果の行列も文字になります。

しかし、これは問題ではありません。あなたが提示してきた最初のコードの塊を見てみましょう:

subset1 <- test_data$Values_1[test_data[,1] == cutoffs[r,1] & 
           test_data[,2] >= cutoffs[r,2] & 
           test_data[,2] <= cutoffs[r,3] & 
           !is.na(test_data[,3])] 

そして、第2のコードチャンク:

subset_1 <- test_data$Values_1[test_data[,1] == cutoffs[x[4],1] & 
           test_data[,2] >= cutoffs[x[4],2] & 
           test_data[,2] <= cutoffs[x[4],3] & 
           !is.na(test_data[,3])] 
subset_2 <- test_data$Values_2[test_data[,1] == cutoffs[x[4],1] & 
           test_data[,2] >= cutoffs[x[4],2] & 
           test_data[,2] <= cutoffs[x[4],3] & 
           !is.na(test_data[,4])] 

これらはxの第四要素の意義あるもの(同じではありませんか? )。最初のコードチャンクがあなたが望むものであると仮定すると、それをすべての行に適用すると、次のようになります。

sapply(seq_len(nrow(cutoffs)), function(r) { 
    vals1 <- test_data$Values_1[test_data[,1] == cutoffs[r,1] & 
           test_data[,2] >= cutoffs[r,2] & 
           test_data[,2] <= cutoffs[r,3] & 
           !is.na(test_data[,3])] 
    vals2 <- test_data$Values_2[test_data[,1] == cutoffs[r,1] & 
           test_data[,2] >= cutoffs[r,2] & 
           test_data[,2] <= cutoffs[r,3] & 
           !is.na(test_data[,3])] 
    c(mean(vals1), mean(vals2)) 
}) 

#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20] 
#[1,] 2.5 7 13.5 17 2.5 7 13.5 17 2.5  7 13.5 17 2.5  7 13.5 17 2.5  7 13.5 17 
#[2,] 22.5 27 33.5 37 22.5 27 33.5 37 22.5 27 33.5 37 22.5 27 33.5 37 22.5 27 33.5 37 
+0

これは機能します!本当にありがとう。 – JHegg

+0

なぜこの問題が起こったのかはっきりしています。 'apply(cutoffs、1、function(x){x})'は反復ごとに行全体を返します。だから、私は 'x [4]'を使っていました。なぜなら、第4列は単純に列番号であるからです。 10回反復した後にNAを出現させ、x [4]やその他のものを呼び出す何かを適用することは内部的なものですか? – JHegg

+0

'cutoffs's'文字の最初の列から正しく理解すると、apply()を使ってすべての列が文字になります。ですから、RがXにどのように作用するのかは、キャラクターに変わった後の動作です。もしそうなら、それは何ですか?私はその場合、すべての反復で失敗すると思います。 – JHegg