【问题标题】:Creating a sequential ranking based on previous ratings根据之前的评级创建顺序排名
【发布时间】:2020-07-29 18:27:27
【问题描述】:

我在按顺序更新排名时遇到问题,无论我如何尝试寻找解决方案 - 或自己想出一个解决方案 - 我都失败了。

我正在尝试分析顺序选择实验的结果,在该实验中,参与者必须找到可能的最佳选项(评分最高的选项)。他们在每次试验中都获得了评分。

我有一个 ID、一个 order 和一个 rating 变量用于每个选择。 ID 是参与者,rating 表示选项的好坏(评分越高越好),order 是试用次数(在这个例子中,有 4 次试验)

ID       rating        order
1        4             1
1        3             2
1        5             3
1        2             4
2        3             1
2        5             2
2        2             3
2        1             4

我想创建一个名为“current_rank”的新变量,它基本上是当前选择的评分排名。这个变量总是需要考虑所有以前的试验和评级,例如对于ID“1”的参与者,这将是:

试用 1:rating = 4,表示这是目前为止最好的评分,current_rank = 1

试用 2:rating = 3,表示这是目前为止第二好的评分,current_rank = 2

试用 3:评分 = 5,这意味着这是迄今为止最好的评分,使其成为新的第 1 名,因此 current_rank = 1

试验 4:评分 = 2,这意味着这远非最佳,current_rank = 4

如果我可以对所有参与者和所有选择执行此操作,我的数据库应该如下所示:

ID       rating        order        current_rank
1        4             1            1
1        3             2            2
1        5             3            1
1        2             4            4
2        3             1            1
2        5             2            1
2        2             3            3
2        1             4            4

我可以像这样成功地创建一个整体排名变量:

db %>%
  arrange(ID, order) %>%
  group_by(ID) %>%
  mutate(ovr_rank = min_rank(desc(rating)))

但我的目标是创建一个按顺序排列的变量。这将使得可以看到参与者可能基于之前的评级对当前评级形成了什么样的意见,而无需知道未来的评级可能是什么。我尝试创建循环或使用 apply 函数,但还没有找到解决方案。

非常感谢任何和所有想法!

【问题讨论】:

    标签: r loops sequence ranking


    【解决方案1】:

    使用runner 在累积窗口(或滚动窗口)中应用任何 R 函数。下面我使用了runner,它滚动评级并对目前的“可用”数据应用排名函数(累积排名)。取消注释 print 以展示进入 function(x) 的内容。

    library(dplyr)
    library(runner)
    
    data %>%
      arrange(ID, order) %>%
      group_by(ID) %>%
      mutate(
        current_rank = runner(
          x = rating,
          f = function(x) {
            # print(x)
            rank_available_at_the_moment <- rank(-x, ties.method = "last")
            tail(rank_available_at_the_moment, 1)
          }
        )
      )
    
    
    # # A tibble: 8 x 4
    # # Groups:   ID [2]
    #       ID rating order current_rank
    #     <int>  <int> <int>        <int>
    # 1     1      4     1            1
    # 2     1      3     2            2
    # 3     1      5     3            1
    # 4     1      2     4            4
    # 5     2      3     1            1
    # 6     2      5     2            1
    # 7     2      2     3            3
    # 8     2      1     4            4
    

    数据

    data <- read.table(text = "ID       rating        order
    1        4             1
    1        3             2
    1        5             3
    1        2             4
    2        3             1
    2        5             2
    2        2             3
    2        1             4", header = TRUE)
    

    【讨论】:

    • 感谢您提供此解决方案!这真的很容易理解并将其实现到我的代码中。我从来没有听说过这个包,但它似乎真的很有用。我可能会使用不同的 ties.method,但除此之外,这正是我想要的!
    【解决方案2】:

    这段代码可以工作:

    df <- tibble(
      ID = c(1,1,1,1,2,2,2,2),
      rating = c(4,3,5,2,3,5,2,1),
      rank = c(1,0,0,0,0,0,0,0)
    )
    
    for(i in 2:nrow(df)){
      if(df$ID[i] != df$ID[i-1]){
        df$rank[i] <- 1
      } else {
        df$rank[i] <- which(sort(df[1:i,]$rating[which(df$ID == df$ID[i])], decreasing = TRUE) == df$rating[i])
      }
    }
    

    解释:

    请注意,我假设您的数据框已经根据 ID 和顺序进行了排序。在我的df 中没有order 列,但这主要是为了简单起见(在我的解决方案中不一定需要它,再次假设行已经按 ID 和顺序排序)。

    for 循环只是查看该行的 ID 是否与上面的行不同,它会自动获得排名 1。否则,它会查看 df 从第 1 行到第 i 行的子集,子集再次按相似的 ID,按降序对该子集中的评分(包括我们当前的评分)进行排序,并将我们当前要求的评分的位置分配为其排名值。

    我希望这能回答您的问题并为您提供见解。

    【讨论】:

    • 感谢您抽出宝贵时间提供解决方案!我接受了一个不同的答案,因为它更适合我的 tidyverse 风格并且更容易实现。
    【解决方案3】:

    这里有两个使用data.table的选项:

    1) non-equi join 查找之前的所有试验和包括当前试验,对评分进行排名并提取当前排名:

    DT[, cr := .SD[.SD, on=.(ID, trial<=trial), by=.EACHI, order(order(-rating))[.N]]$V1]
    

    2) non-equi join 查找在当前试验之前的试验中高于当前评分的评分数:

    DT[, cr2 := DT[DT, on=.(ID, trial<=trial, rating>rating), by=.EACHI, .N + 1L]$V1]
    

    请注意,评级中可能存在关联,最好指定应如何处理评级关联。

    输出:

       ID rating trial cr cr2
    1:  1      4     1  1   1
    2:  1      3     2  2   2
    3:  1      5     3  1   1
    4:  1      2     4  4   4
    5:  2      3     1  1   1
    6:  2      5     2  1   1
    7:  2      2     3  3   3
    8:  2      1     4  4   4
    

    数据:

    library(data.table)
    DT <- fread("ID       rating        trial
    1        4             1
    1        3             2
    1        5             3
    1        2             4
    2        3             1
    2        5             2
    2        2             3
    2        1             4")
    

    【讨论】:

    • 感谢您抽出宝贵时间提供解决方案!我接受了一个不同的答案,因为它更适合我的 tidyverse 风格并且更容易实现。
    • 没问题我理解
    猜你喜欢
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多