【问题标题】:Calculate row means on subset of columns selected via external rank计算通过外部排名选择的列子集的行均值
【发布时间】:2017-05-26 16:52:47
【问题描述】:

我有一个数据框,其中包含由多个编码员生成的一组项目评级。并非所有编码员都对所有项目进行排名。对于每个项目,我想根据前两名编码员的评分生成一个平均值,如外部排名系统所示。编码员的排名从 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: 在第二个数据帧中,列按编码器排名排序(例如,列按 'CoderD'、'CoderB'、'CoderC'、 '编码器')。考虑到这种约束,我该如何解决同样的问题?

【问题讨论】:

  • 对于第一个问题,您可以使用apply(df,1,function(x) mean(x[!is.na(x)][1:2]))。不确定我是否理解第二个问题,您不能事先对列重新排序吗?
  • 您的建议是问题 1 的一个很好的解决方案;谢谢!问题 2 适用于更动态的情况。在我的完整脚本中,编码员的外部排名会根据其他数据进行调整,并且可以从脚本的一部分更改为另一部分。我不想在每次排名发生变化时重新排序列,因此寻求可以直接指定列排名的替代方案。

标签: r dataframe


【解决方案1】:

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

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

如果编码者的排名实际上是CoderD &gt; CoderB &gt; CoderC &gt; 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

【讨论】:

    【解决方案2】:

    使用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
    

    如果您的编码器名称按照您想要的偏好顺序排序(如您所描述的),这将起作用。数据框中列的顺序无关紧要。

    【讨论】:

    • 谢谢!这很好用。为了确保在列乱序时编码器名称正确排序,我在排列语句之前添加了一行,将编码器转换为因子并指定正确的级别顺序:mutate(coder = factor(coder, levels = c('CoderA', 'CoderB', 'CoderC', 'CoderD'))) %&gt;%
    猜你喜欢
    • 2022-01-21
    • 2012-06-12
    • 2021-07-21
    • 2019-01-27
    • 2020-09-07
    • 1970-01-01
    相关资源
    最近更新 更多