1

私は仕事で大量の調査データなどを扱っており、行ごとにデータを処理するさまざまなスコアリングプログラムを作成しなければならないことがよくあります。たとえば、私は現在、心理測定機器からのサブスケールスコアを持つ12列を含むテーブルを扱っています。これらは、楽器の作成者によって提供されたテーブルを使用して正規化されたスコアに変換されます。これまでのところ簡単に思えます。

ただし、4つのテーブルがあります。楽器のスコアは、性別と年齢層によって異なります。したがって、たとえば、14歳の女性と10歳の男性は、異なる正規化テーブルを取得します。すべての正規化データはRデータフレームに保存されます。

私がやりたいのは、行に適用できる関数を作成することです。この関数は、正規化データからルックアップされたベクトルを返します。だから、漠然とこのようなもの:

converter <- function(rawscores,gender,age) {
    if(gender=="Male") {
        if(8 <= age & age <= 11) {convertvec <- c(1:12)}
        if(12 <= age & age <= 14) {convertvec <- c(13:24)}
    }
    else if(gender=="Female") {
        if(8 <= age & age <= 11) {convertvec <- c(25:36)}
        if(12 <= age & age <= 14) {convertvec <- c(37:48)}
    }

    converted_scores <- rep(0,12)
    for(z in 1:12) {
        converted_scores[z] <- conversion_table[(unlist(rawscores)+1)[z],
                                                convertvec[z]]
    }
    rm(z)
    return(converted_scores)
}

編集済み:昨日実際に動作するようになったコードでこれを更新しました。このバージョンは、スコアを含む単純なベクトルを返します。これが私がそれをどのように実装したかです。

mydata[,21:32] <- 0
for(x in 1:dim(mydata)[1]) {
    tscc_scores[x,21:32] <- converter(mydata[x,7:18],
                                      mydata[x,"gender"],
                                      mydata[x,"age"])
}

これは機能しますが、私が言ったように、それは悪い習慣であると理解するように与えられていますか?

補足:rawscores + 1の理由は、データフレームの最初のインデックスのスコアがゼロであるためです。

基本的に、この関数はそれほど複雑ではないように思われ、for(x in 1:number_of_records)を実行するループを使用して実装できることはわかっていますが、そうすることは不適切な方法であると理解しています。次のように、単にapply()を使用してこれを行うことを望んでいました。

apply(X=mydata[,1:12],MARGIN=1,
      FUN=converter,gender=mydata[,"gender"],age=mydata[,"age"])

残念ながら、Rはこのアプローチを承認していないようです。これは、後続の引数に渡されるベクトルを反復処理せず、全体としてそれらを引数として受け取ろうとするためです。解決策はmapply()のように見えますが、列ではなく行に対してmapply()を使用する方法があるかどうかわかりません。

ですから、私の質問は3つあると思います。1つは、行に対してmapply()を使用する方法はありますか?2つ目は、apply()で引数を反復処理する方法はありますか?そして3つ、そこにもっと良いオプションはありますか?私はplyrパッケージについて多くのことを見聞きしましたが、Base Rに存在するオプションを完全に調査する前に、それに飛びつきたくありませんでした。

4

2 に答える 2

1

'converter'を書き直して、性別、年齢、行インデックスのベクトルを取得し、変換配列と数値スコア列を使用するデータ配列を使用して、converted_scoresへのルックアップと割り当てを行うことができます。性別クラスが「文字」であるため、applyを使用するとすべてのx引数が「文字」クラスに変換されるため、追加の問題があります。コードnormdf[ rawscores+1, convertvec]が配列抽出なのか関数呼び出しなのかは明確ではありませんでした。

実例がない場合はテストされていません(、normdfを使用mydata):

 converted_scores <- matrix(NA, nrow=NROW(rawscores), ncol=12) 
 converter <- function(idx,gender,age) {
     gidx <- match(gender, c("Male", "Female") )
     aidx <- findInterval(age, c(8,12,15) ) 
     ag.idx <- gidx + 2*aidx -1  
          # the aidx factor needs to be the same number of valid age categories
     cvt <- cvt.arr[ ag.idx, ]

     converted_scores[idx] <- normdf[rawscores+1,convertvec]
     return(converted_scores)
 }
 cvt.arr <- matrix(1:48, nrow=4, byrow=TRUE)[1,3,2,4] # the genders alternate
 cvt.scores <- mapply(converter, 1:NROW(mydata), mydata$gender, mydata$age)
于 2012-08-08T22:40:31.853 に答える
1

このようなものを行ごとに適用するのではなく、列ごとに適用することをお勧めします。その理由は、列が12列しかないためですが、行が多い可能性があります。

次のコードは私にとってはうまくいきます。もっと良い方法があるかもしれませんが、それでもあなたにとっては面白いかもしれません。

offset <- with(mydata, 24*(gender == "Female") + 12*(age >= 12))
idxs <- expand.grid(row = 1:nrow(mydata), col = 1:12)
idxs$off <- idxs$col + offset
idxs$val <- as.numeric(mydata[as.matrix(idxs[c("row", "col")])]) + 1
idxs$norm <- normdf[as.matrix(idxs[c("val", "off")])]
converted <- mydata
converted[,1:12] <- as.matrix(idxs$norm, ncol=12)

ここで注意が必要なのはidxs、残りすべてを組み合わせたこのデータフレームです。次の列があります。

  • 行と列:元のデータでの位置
  • オフ:normdf性別と年齢に基づく、の列
  • val:normdf元の値+ 1に基づく、の行
  • ノルム:対応する正規化された値

この最初の考えでこれをここに投稿し、joransのコメントに基づいて、またはの3次元または4次元配列を使用して、より良い答えを思い付くことができるかどうかを確認しnormdfます。まだ分​​からない。

于 2012-08-08T23:04:26.573 に答える