2017-05-26 23 views
0

我有一个数据框,其中包含由多个编码器生成的一组项目评分。并非所有的编码员都排列所有项目。对于每个项目,我希望根据排名前两位编码者的评分生成平均值,如外部排名系统所示。编码从A(最高)到D(最低)排列。在我当前的代码,我命令由译码器的列排序(从A到d),然后使用一个for循环:计算通过外部列选择的列的子集上的行平均值

CoderA CoderB CoderC CoderD 
1  2  1  NA  1 
2  1  3  3  NA 
3  NA  NA  4  5 
4  7  6  7  6 
5  3  3  4  2 
6  2  2  NA  NA 
7  2  NA  2  1 
8  5  3  NA  4 
9  7  7  6  NA 
10  1  NA  3  4 

df <- data.frame(
CoderA = c(2,1,NA,7,3,2,2,5,7,1), 
CoderB = c(1,3,NA,6,3,2,NA,3,7,NA), 
CoderC = c(NA,3,4,7,4,NA,2,NA,6,3), 
CoderD = c(1,NA,5,6,2,NA,1,4,NA,4)) 

df$first_sc <- apply(df, 1, function(x) names(df[which(!is.na(x))])[1]) 
df$sec_sc <- apply(df, 1, function(x) names(df[which(!is.na(x))])[2]) 

for (x in seq(1,nrow(df))) { 
    first_rating <- df[x,df$first_sc[x]] 
    second_rating <- df[x,df$sec_sc[x]] 
    df$BestAvg[x] <- (first_rating + second_rating)/2 
    } 

问题1:任何建议用于更简洁的解决方案,以上述简单的情况? (for循环不是首选,但我卡在索引中相似的应用功能。)

问题2:在第二个数据帧,列通过编码器排名(例如,列排序订购'编码器','编码器','编码器C','编码器A')。考虑到这个约束,我该如何解决同样的问题?

+0

对于第一个问题,你(df,1,function(x)mean(x [!is.na(x)] [1:2]))''。不知道我理解第二个问题,你不能预先重新排序列吗? – Lamia

+0

你的建议是问题1的一个很好的解决方案;谢谢!问题2适用于更加动态的情况。在我的完整脚本中,编码器的外部排名根据其他数据进行调整,并可以从脚本的一部分更改为另一部分。每次排名变化时,我都不想重新排列列,因此需要直接指定列排名的替代方案。 – Jane

回答

1

对于第一个问题, 你可以使用apply得到每行的第2个非NA值的平均值:

df$BestAvg = apply(df,1,function(x) mean(x[!is.na(x)][1:2])) 

在这种情况下该编码器的排名实际上是CoderD > CoderB > CoderC > CoderA

r = c("CoderD", "CoderB", "CoderC", "CoderA") 
df$BestAvg2 = apply(df,1,function(x) mean(x[r][!is.na(x[r])][1:2])) 

这将返回:

 CoderA CoderB CoderC CoderD BestAvg BestAvg2 
1  2  1  NA  1  1.5  1.0 
2  1  3  3  NA  2.0  3.0 
3  NA  NA  4  5  4.5  4.5 
4  7  6  7  6  6.5  6.0 
5  3  3  4  2  3.0  2.5 
6  2  2  NA  NA  2.0  2.0 
7  2  NA  2  1  2.0  1.5 
8  5  3  NA  4  4.0  3.5 
9  7  7  6  NA  7.0  6.5 
10  1  NA  3  4  2.0  3.5 
1

使用dplyrtidyr ...

df2 <- df %>% mutate(case=1:n()) %>% #add case numbers 
       gather(key=coder,value=score,-case) %>% #convert to long format 
       filter(!is.na(score)) %>% #remove NA scores 
       arrange(case,coder) %>% #order by case and coder 
       group_by(case) %>% #group by case 
       summarise(bestavg=mean(head(score,2))) %>% #mean of top two 
       right_join(df %>% mutate(case=1:n())) #merge with original data 

df2 
# A tibble: 10 x 6 
    case bestavg CoderA CoderB CoderC CoderD 
    <int>  <dbl> <dbl> <dbl> <dbl> <dbl> 
1  1  1.5  2  1  NA  1 
2  2  2.0  1  3  3  NA 
3  3  4.5  NA  NA  4  5 
4  4  6.5  7  6  7  6 
5  5  3.0  3  3  4  2 
6  6  2.0  2  2  NA  NA 
7  7  2.0  2  NA  2  1 
8  8  4.0  5  3  NA  4 
9  9  7.0  7  7  6  NA 
10 10  2.0  1  NA  3  4 

这将工作提供您的姓名编码排序成你想要的优先顺序(如你描述)。数据框中列的顺序无关紧要。

+0

谢谢!这很好。为了确保编码器名称在列出现错误时正确排序,我在编排器语句之前添加了一行,它将编码器转换为因子并指定正确的级别顺序:mutate(coder = factor(coder,levels = c('CoderA' ,'CoderB','CoderC','CoderD')))%>%' – Jane