【问题标题】:How to utilize recursive functions to help rank matrix rows - R如何利用递归函数来帮助排列矩阵行 - R
【发布时间】:2014-10-21 01:58:17
【问题描述】:

我想要一些关于如何最好地解决这个难题的建议。我有一些方法可以使用手动编写的长手代码来解决它。我觉得好像我需要使用递归函数,但我仍然不太擅长使用它们。我希望这个问题不会太长,我试图在提供足够信息的同时尽可能简洁。对不起,如果它太长了 - 虽然希望有人会感兴趣。

我有一个矩阵mat1

#   A B C D E F G
# A 0 2 1 1 0 1 1
# B 0 0 0 1 2 2 1
# C 1 2 0 0 0 2 1
# D 1 1 2 0 1 2 1
# E 2 0 2 1 0 2 1
# F 1 0 0 0 0 0 1
# G 1 1 1 1 1 1 0

这表示行和列中个人之间的竞赛结果。数字是指行中的个人与列中的个人“获胜”的频率。

我希望使用以下标准从 1-7 对个人 A-G 进行排名:

  • 对所有其他人的获胜次数(最多获胜应排名 1,最少获胜 7,第二多获胜 2,依此类推)

  • 如果获胜次数相同,则排名应基于仅考虑获胜次数相同的个人之间的比赛时获得的获胜次数。

  • 如果个人的获胜次数仍然相同,则应随机应用排名。

我意识到这不是一个很好的排名系统,但这不是这里的问题。根据上述方案,排名应该如下:

  • 1 - D 或 E - D 和 E 获得并列最高的总冠军 (8),并且在他们之间的比赛中也获得相同的胜利。
  • 2 - E 或 D - 随机选择 D 或 E 作为 1 级和 2 级
  • 3 - A 或 C - 与 A、B、C、G 并列共 6 胜,在 ABCG 的内容中均获得 4 胜
  • 4 - C 或 A - 考虑到 C&A 之间的比赛都有 1 胜,所以随机选择 rank3 和 rank4
  • 5 - G - 与 A、B、C、G 并列 6 胜,在 A、B、C、G 之间的比赛中取得 3 胜
  • 6 - B - 与 A、B、C、G 并列 6 胜,但在 A、B、C、G 之间的比赛中只有 1 胜
  • 7 - F - 在整体获胜矩阵中获胜次数最少

我尝试过的:

storeresults <- vector("list") #use this to store results of the following

第 1 步:使用winsfun 函数(见下文)识别每个人的获胜次数以及获胜次数是否唯一(如 dupes 列所示):

w1 <- winsfun(mat1)
storeresults[[1]] <- w1  #store results

w1 只有“F”的获胜次数是唯一的,因此可以首先排名(第 7):

#  wins ranks dupes
#A    6   4.5  TRUE
#B    6   4.5  TRUE
#C    6   4.5  TRUE
#D    8   1.5  TRUE
#E    8   1.5  TRUE
#F    2   7.0 FALSE
#G    6   4.5  TRUE

第 2 步:对于非唯一获胜(即重复排名)的个人,将其子集到矩阵中,仅考虑与其他获胜次数相同的人进行比赛,并在可能的情况下确定新排名。 p>

allSame(w1[,3]) #FALSE - this says that not all wins/ranks are unique so need to subset

s2 <- subsetties(w1)  #this just splits the data into groups by number of wins (see below)

w2 <- lapply(s2, winsfun, m=mat1)
storeresults[[2]] <- w2 # store results 

w2 可以看出,那些在Step1(“D”和“E”)中获得8胜(最多)的人(“D”和“E”)每个人都赢了一场。它们不能被戏弄分开,因此将随机排名第 1 和第 2。仅考虑彼此之间的比赛时,那些获得 6 场胜利(A、B、C、G)的人的获胜次数是不同的。 “B”和“G”可以分别排在总排名第6和总排名第5。我们需要重新考虑“A”和“C”在相互竞争的情况下:

$`6`
  wins ranks dupes
A    4   1.5  TRUE
B    1   4.0 FALSE
C    4   1.5  TRUE
G    3   3.0 FALSE

$`8`
  wins ranks dupes
D    1   1.5  TRUE
E    1   1.5  TRUE

第 3 步:在需要的地方重复第 2 步

 allSame(w2[[1]][,3])  #FALSE - need to subset again as not everyone has same number of wins
    allSame(w2[[2]][,3])  #TRUE  - no more action required
    
    s3 <- subsetties(w2[[1]])
    
w3 <- winsfun(s3[[1]], m=mat1)
storeresults[[3]] <- w3 #store results

w3当考虑“A”和“C”时,他们各有一场胜利,所以现在应该随机排名第二和第三名。它们不能被戏弄分开。

  wins ranks dupes
A    1   1.5  TRUE
C    1   1.5  TRUE

allSame(w3[,3])  #TRUE - no more action required - both have same number of wins

第 4 步处理存储的结果

storeresults  
# I can manually work out ranks from this, but have yet to work out how to do it in R

以下是上面用到的函数:

计算子集矩阵的获胜和排名的函数

winsfun <- function(m, out=NULL){

if (is.null(out)==F){
m1 <- m[rownames(out),rownames(out)]
wins <- apply(m1, 1, sum)
ranks <- rank(-wins)
dupes <- duplicated(wins)| duplicated(wins, fromLast = T)
df <- data.frame(wins, ranks,dupes)
return(df)
}

else
wins <- apply(m, 1, sum)
ranks <- rank(-wins)
dupes <- duplicated(wins)| duplicated(wins, fromLast = T)
df <- data.frame(wins, ranks,dupes)
return(df)
}

对具有重复等级的行进行子集化的功能

 subsetties <- function(df){
        df1 <- df[df[,3]==T,]
        df1.sp <- split(df1, df1$wins)
        return(df1.sp)
    }

测试向量的所有元素是否相同的功能

allSame <- function(x) length(unique(x)) == 1

重新创建上述矩阵的代码:

structure(c(0, 0, 1, 1, 2, 1, 1, 2, 0, 2, 1, 0, 0, 1, 1, 0, 0, 
2, 2, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 2, 
2, 2, 0, 1, 1, 1, 1, 1, 1, 1, 0), .Dim = c(7L, 7L), .Dimnames = list(
    c("A", "B", "C", "D", "E", "F", "G"), c("A", "B", "C", "D", 
    "E", "F", "G")))

我希望这个问题很清楚。我正在尝试找出如何迭代地执行这个算法。我不太确定如何实现这一点,但希望通过长期写出来并提供我一直在使用的功能,这对某人来说可能是显而易见的。额外的一件事是,建议的解决方案最好是普遍适用的(即适用于不同大小的矩阵)。

【问题讨论】:

  • 为什么不使用rowSumsrank

标签: r recursion matrix


【解决方案1】:
calc_gain<-function(mat=mat1){
    if(nrow(mat)==1) {
        return(row.names(mat))
    } else {
        classement<-sort(rowSums(mat),decreasing=T)
        diffgains<-diff(classement)
        if (all(diffgains!=0)){
            return(names(classement))
        } else {
            if (all(diffgains==0)){
                return(sample(names(classement)))
            } else {
                parex<-split(classement,factor(classement,levels=unique(classement)))
                class_parex<-lapply(parex,function(vect){calc_gain(mat[names(vect),names(vect),drop=F])})
                return(unlist(class_parex))
            }
        }
    }
}

这是函数的作用:

  • 如果只有一个元素,则返回它的名称(只有“玩家”)
  • 否则,它会计算分数。
    • 如果没有平局,则按从前到后的顺序返回“玩家”
    • else, - 如果所有“玩家”的分数相同,则随机给出一个顺序。
      • 否则,它会根据分数拆分有序列表,并将函数(即递归部分)应用于分数相同的“玩家”子集。

【讨论】:

  • 这太棒了 - 谢谢。我用几个不同大小的矩阵检查了它,到目前为止它似乎概括得很好。我需要花一点时间更准确地了解它是如何做的,并且可能会有后续评论。无论如何,非常感谢。
  • @jalapic,不客气,如果有帮助我很高兴。该函数的第一部分(实际上是两个第一点)确保它在某个时间点结束,最后一部分可以解决问题......如果您有任何问题,请不要犹豫。
  • 再次感谢 - 在更详细地研究它之后,我确实看到了它是如何做到的 - 正是 diff 的使用使它真正变得优雅。尽管我认为构建递归函数需要与我习惯的思维方式略有不同。我只有一个小问题 - 我不太确定为什么需要 drop=F
  • 它确保在只剩下一个元素时一切顺利(例如,对于 mat1 中的 F):我们需要获取 row.names 所以 mat[one_element,one_element] 需要保持一个矩阵.
【解决方案2】:

这是一个开始:

步骤0:

> split(rownames(m), -rowSums( m ) )
$`-8`
[1] "D" "E"

$`-6`
[1] "A" "B" "C" "G"

$`-2`
[1] "F"

第一步:

m <-  m[ order( -rowSums(m) ), ])  # order within overall wins
  A B C D E F G
D 1 1 2 0 1 2 1
E 2 0 2 1 0 2 1
A 0 2 1 1 0 1 1
B 0 0 0 1 2 2 1
C 1 2 0 0 0 2 1
G 1 1 1 1 1 1 0
F 1 0 0 0 0 0 1

> rowSums( m )
D E A B C G F 
8 8 6 6 6 6 2 

Step2:4胜组内下单

> mred <- m[c("A","B","C","G"), c("A","B","C","G") ]
> mred
  A B C G
A 0 2 1 1
B 0 0 0 1
C 1 2 0 1
G 1 1 1 0
> rowSums(mred)
A B C G 
4 1 4 3 

> rownames(mred)[order(-rowSums(mred))]
[1] "A" "C" "G" "B"

【讨论】:

    猜你喜欢
    • 2015-05-25
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 2018-03-14
    • 1970-01-01
    • 2013-10-31
    • 2010-11-21
    相关资源
    最近更新 更多