R - 速度优化和国际象棋排名

use*_*307 5 algorithm optimization performance chess r

嗨,您好!

我正在尝试计算6种不同技能(C1,C2,... C6)中的一些玩家的玩家国际象棋排名.我有一个巨大的游戏数据框(数据)看起来像这样(头(数据)).在这个游戏中,一个人(用户)选择在另外两个人(p1/p2)之间获胜.

row.names   user    p1  p2  skill   win looser       time
---------------------------------------------------------
2             KE    CL  HK     C1    CL     HK  433508371
25            KE    HK  JT     c1    HK     JT  433508401
35            KE    AB  JT     C1    AB     JT  433508444
110           NF    IP  HE     C1    HE     IP  433508837
78            NF    IP  AS     C1    AS     IP  433508848
82            NF    IT  CV     C1    CV     IT  433508860
Run Code Online (Sandbox Code Playgroud)

在另一个表格(old_users)中,我跟踪所有玩家在6种技能中的国际象棋得分(head(old_users))

    user    C1    C2    C3    C4    C5    C6                                    
1     BD  1200  1200  1200  1200  1200  1200                                    
2     NF  1200  1200  1200  1200  1200  1200                                    
3     CH  1200  1200  1200  1200  1200  1200                                    
4     AR  1200  1200  1200  1200  1200  1200                                    
5     AS  1200  1200  1200  1200  1200  1200                                    
6     MS  1200  1200  1200  1200  1200  1200                                    
Run Code Online (Sandbox Code Playgroud)

算法 该算法在for循环中一次一行地运行数据,每次查看第i行.该算法将查找p1和p2的得分数据,检索两个玩家得分的技能.然后根据谁获胜或失败来计算他们的新分数,然后用相应的新排名更新old_users单元格.

我需要做什么 我需要尽快做到这一点,并且数据帧数据现在只有24个玩家的6000多行,需要一段时间才能完成.

我试图计算我当前的for循环,这给出了以下几次太多的时间.

  user   system  elapsed 
104.72     0.28   118.02 
Run Code Online (Sandbox Code Playgroud)

问题

  1. 为什么这个算法需要很长时间才能完成?在for-loops等等中是否有任何不好的命令?
  2. 如何以更快的方式实现我想要的目标?

当前for循环

for (i in 1:dim(data)[1]) {
  tmp_data<-data[i,]  #Take the i'th row in data
  score_col<-which(colnames(old_users)==tmp_data$skill) #find old_user column which matched the skill played
  winners_old_data<-old_users[which(old_users$user==tmp_data$win),] #Fetch winner's old scores
  loosers_old_data<-old_users[which(old_users$user==tmp_data$looser),] #Fetch looser's old scores 


  winners_new_score=winners_old_data[score_col]+(32/2)*(1-0+(1/2)*((loosers_old_data[score_col]-winners_old_data[score_col])/200)) #Calculate the winner's new score
  loosers_new_score=loosers_old_data[score_col]+(32/2)*(0-1+(1/2)*((winners_old_data[score_col]-loosers_old_data[score_col])/200)) #Calculate the looser's new score

  old_users[old_users$user==winners_old_data[[1]],score_col]<-winners_new_score #update cell in old_users
  old_users[old_users$user==loosers_old_data[[1]],score_col]<-loosers_new_score #update cell in old_users
      }
Run Code Online (Sandbox Code Playgroud)

要播放的数据

https://drive.google.com/file/d/0BxE_CHLUGoS0WlczUkxLM3VtVjQ/edit?usp=sharing

很感谢任何形式的帮助

谢谢!

// HK

flo*_*del 2

你发布的数据太小了!想想我必须安装一些东西才能解压它......!如果您可以发布更大的数据,我将能够测试我的建议有多有用。

我建议您将用户数据转换为一个矩阵,其中 ids 作为行名,技能作为列名。为什么?

  1. 通过正常索引访问数据而不是which( == )到处使用,您可能会获得小幅速度提升。或者至少它会让你的代码更具可读性。

  2. 更重要的是,矩阵内的值的改变是在内存中就地完成的;而使用 data.frame 时,我认为您的代码每次都会创建全新的对象,这一定很耗时。


# read and transform your data
data  <- read.csv("data.txt", header = FALSE)
names(data) <- c("user", "p1", "p2", "skill", "win", "looser", "time")
users <- data.matrix(read.csv("users.txt", header = FALSE, row.names = 1))
colnames(users) <- paste("C", 1:6)

for (i in 1:nrow(data)) {
   game <- data[i,]
   winner.old <- users[game$win,    game$skill]
   looser.old <- users[game$looser, game$skill]
   winner.new <- winner.old + 32/2 * (1 - 0 + (1/2) * (looser.old-winner.old) / 200)
   looser.new <- looser.old + 32/2 * (0 - 1 + (1/2) * (winner.old-looser.old) / 200)
   users[game$win,    game$skill] <- winner.new
   users[game$looser, game$skill] <- looser.new
}
Run Code Online (Sandbox Code Playgroud)

是不是更容易阅读呢?希望它也会快一点,请测试并告诉我。或者提供我们可以使用的更大的数据集。谢谢。