2012-08-08 23 views
0

我在工作中處理大量的調查數據等,而且我經常需要製作各種評分程序來逐行處理數據水平。例如,我現在正在處理一個表格,其中包含來自心理測量工具的12個具有分量表分數的列。這些將使用樂器創建者提供的表格轉換爲標準化樂譜。目前看來很簡單。在R行中使用mapply()和列

但是,有四張表格 - 根據性別和年齡範圍,樂器的得分有所不同。因此,例如,一名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的原因是數據框在第一個索引中的分數爲零。

從根本上說,該功能似乎不是很複雜,我知道我可以使用一個循環,我會爲(1×:number_of_records)做只是實現它,但我的理解是,這樣做是不良的做法。我希望簡單地使用應用()來做到這一點,就像如下:

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

不幸的是,R似乎並不贊同這種做法,因爲它不會通過傳遞到後面的參數矢量迭代,而是試圖把它們作爲一個整體的論點。該解決方案似乎是mapply(),但我無法弄清楚是否有辦法在行上使用mapply(),而不是列。

所以,我想我的問題是三倍的。一,有沒有辦法在行上使用mapply()?二,有沒有辦法讓apply()迭代參數?三,那裏有更好的選擇嗎?我已經看到並聽到很多關於plyr軟件包的信息,但我並不想在完全調查Base R中的選項之前跳到那個版本。

+0

這看起來就像是如果你正確地組織你的數據,它可以用一個'merge'來完成。 – joran 2012-08-08 22:11:05

回答

1

您可以重寫'converter',以便向量性別,年齡和行索引,然後使用轉換數組和數字分數列的數據數組對數據進行查找和分配。使用apply還有一個額外的問題,因爲它將所有的x參數轉換爲「character」類,因爲性別類是「character」。目前尚不清楚您的代碼normdf[ rawscores+1, convertvec]應該是數組提取還是函數調用。

在沒有工作示例的未經檢驗的(與normdfmydata):

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) 
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評論,還是使用normdf的三維或四維數組。尚未確定。