1

我在工作中要处理大量的调查数据等,而且我经常不得不制作各种逐行处理数据的评分程序。例如,我现在正在处理一个包含 12 列的表格,其中包含来自心理测量仪器的子量表分数。这些将使用仪器创建者提供的表格转换为标准化分数。到目前为止看起来很简单。

但是,有四张表 - 根据性别和年龄范围,该乐器的评分不同。因此,例如,一个 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()。

所以,我想我的问题是三方面的。一,有没有办法在行上使用 mapply() ?二,有没有办法让 apply() 迭代参数?第三,有更好的选择吗?我已经看到并听到了很多关于 plyr 包的信息,但在我完全研究 Base R 中存在的选项之前,我不想跳到那个。

4

2 回答 2

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数据框,它结合了所有其余部分。它具有以下列:

  • row and column:在原始数据中的位置
  • off:中的列normdf,基于性别和年龄
  • val: row in normdf, 基于原始值 + 1
  • norm:对应的归一化值

我会带着这个第一个想法在这里发布这个,看看我是否能想出一个更好的答案,或者基于 jorans 的评论,或者使用normdf. 还不确定。

于 2012-08-08T23:04:26.573 回答
1

您可以重写“转换器”,以便它获取性别、年龄和行索引的向量,然后您可以使用转换数组和数据数组(即数字分数列)对 convert_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 回答