2014-10-01 5 views
5

Hallo zusammen!R - Geschwindigkeitsoptimierung und Chess Rankings

Ich versuche, Spieler Schach-Rankings für eine Reihe von Spielern in 6 verschiedenen Fähigkeiten (C1, C2, ... C6) zu berechnen. Ich habe einen riesigen Datenrahmen (Daten) von gespielten Spielen, der ähnlich aussieht (Kopf (Daten)). In diesem Spiel wählt eine Person (Benutzer) zwischen zwei anderen Personen (p1/p2), um zu gewinnen.

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 

In einer anderen Tabelle (old_users) Ich behalte den Überblick über alle Schach Partituren Spieler in den sechs Fähigkeiten (Kopf (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          

Der Algorithmus Der Algorithmus läuft durch einen Daten reihe zu einem zeitpunkt in einer for-schleife, jedes mal in der i-ten reihe. Der Algorithmus sucht die Score-Daten von p1 und p2, retrive die Punkte der beiden Spieler für die gespielte Fähigkeit. Berechnen Sie dann ihre neue Punktzahl basierend darauf, wer gewinnt oder verliert, und aktualisieren Sie dann die old_users-Zelle mit den entsprechenden neuen Rankings.

Was benötige ich ich tun muss dies so schnell wie möglich zu tun und mit den Datenrahmen Daten sind jetzt 6000+ Linien für nur 24 Spieler dauert es eine Weile durchlaufen.

Ich habe versucht, meine aktuelle for-Schleife Zeit zu geben, die die folgenden Zeiten gibt, die viel zu viel ist.

user system elapsed 
104.72  0.28 118.02 

Fragen

  1. Warum dauert dieser Algorithmus so lange durchlaufen? Gibt es irgendwelche Befehle, die in For-Schleifen usw. nicht gut sind?
  2. Wie erreiche ich schneller, was ich will?

Aktuelle for-Schleife

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 
     } 

Daten mit

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

Jede Hilfe ist sehr viel

geschätzt zu spielen

Vielen Dank!

// HK

+0

"Verlierer" nicht "loser". Wie auch immer, du brauchst nicht das 'was', nur die Vergleichsaussage. Das sieht nach einem Job für SQL aus, also sollten Sie sich die Pakete 'sqldf' und ähnliche Pakete ansehen. –

+1

Das Problem ist, dass Sie für jedes neu gespielte Spiel den aktuellen Spielerstand der übereinstimmenden Spieler kennen müssen. Das ist genau das Schachproblem. Wenn also im Spiel Nummer X ein mit einem niedrigen aktuellen Punktestand gespielt wird, wird ein mit einem hohen aktuellen Punktestand gespielt. Dann erhält die Person mit niedriger Bewertung mehr Punkte, um die höhere Punktzahl zu schlagen. – user4098307

+1

In diesem Fall müssen Sie nur zwei Datensatzsuchen (eine für jeden Player) ausführen, und dafür ist die Datenbanksoftware zuständig. –

Antwort

2

Die Daten, die Sie geschrieben ist lächerlich klein! Zu denken, dass ich etwas installieren musste, um es zu lösen ...! Wenn Sie bitte viel größere Daten posten könnten, kann ich testen, wie nützlich mein Vorschlag ist.

Ich würde Ihnen empfehlen, die Benutzerdaten in eine Matrix mit IDs als rownames und Fähigkeiten wie colnames zu verwandeln. Warum?

  1. Sie könnten die Daten über normale Indizierung Zugriff eher eine kleine Verbesserung der Geschwindigkeit erhalten, indem als which(==) überall verwenden. Zumindest wird es Ihren Code viel lesbarer machen.

  2. Noch wichtiger ist, dass die Änderung von Werten innerhalb einer Matrix in-Memory erfolgt; Während ich mit einem data.frame arbeite, denke ich, dass dein Code jedes Mal ein ganz neues Objekt erstellt, was zeitaufwändig sein muss.


# 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 
} 

Ist das nicht viel einfacher, es zu lesen? Hoffentlich wird es auch ein bisschen schneller, bitte testen und lassen Sie es mich wissen. Oder stellen Sie einen größeren Datensatz zur Verfügung, mit dem wir spielen können. Vielen Dank.

+1

Das erste Mal, dass ich jemanden gesehen habe 'data.matrix' Ich dachte, es nie die Hilfedatei verlassen. Ich habe mich gefragt, wo es nützlich sein könnte. –