我在工作中处理了大量的调查数据等,而且我经常需要制作各种评分程序来逐行处理数据。例如,我正在处理一个表,其中包含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的原因是数据框在第一个索引中得分为零。
从根本上说,这个函数看起来并不复杂,而且我知道我可以使用一个循环实现它,我会做(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中的选项之前,我不想跳到那个。
答案 0 :(得分:1)
您可以重写“转换器”,以便它采用性别,年龄和行索引的向量,然后使用转换数组和数字分数列的数据数组对convert_scores进行查找和分配。使用apply还有一个问题,因为它会将所有x参数转换为“character”类,因为性别类是“character”。目前尚不清楚您的代码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)
答案 1 :(得分: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
中的列,基于性别和年龄
normdf
中的行,基于原始值+ 1 我将在这里首先考虑这个问题,看看我是否可以根据jorans评论或使用normdf
的三维或四维数组得出更好的答案。还不确定。