2014-10-01 14 views
5

Witaj!R - Optymalizacja prędkości i rankingi szachów

Próbuję obliczyć ranking szachowy graczy dla wielu graczy w 6 różnych umiejętnościach (C1, C2, ... C6). Mam ogromną ramkę danych (dane) gier, która wygląda na podobną (head (dane)). W tej grze jedna osoba (użytkownik) wybiera pomiędzy dwiema innymi osobami (p1/p2), aby wygrać.

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 

w innej tabeli (old_users) I śledzenie wszystkich szachistów-score w 6 umiejętności (głowica (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          

Algorytm Algorytm przebiega przez jeden danych wiersz na raz w pętli for, za każdym razem patrząc na i'th wiersz. Algorytm przyjrzy się wynikom p1 i p2, a następnie uzyska wynik dla dwóch graczy. Następnie obliczyć ich nowy wynik na podstawie tego, kto wygrywa lub przegrywa, a następnie aktualizuje komórkę old_users z odpowiadającymi jej nowymi rankingami.

Co muszę zrobić muszę to zrobić tak szybko jak to możliwe, z czym teraz 6000+ liniach dane dataframe tylko 24 graczy, to zajmuje trochę czasu, aby uruchomić poprzez.

Próbowałem czas mój obecny pętli for, co daje następujące czasy, które jest o wiele za dużo.

user system elapsed 
104.72  0.28 118.02 

Pytania

  1. Dlaczego ten algorytm trwa tak długo, aby uruchomić poprzez? Czy są jakieś polecenia, które są złe w pętlach for itp.?
  2. Jak mogę szybciej osiągnąć to, czego chcę?

Aktualny dla pętli

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 
     } 

danych grać z

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

Każda pomoc jest bardzo cenione

Dziękujemy!

// HK

+0

"Przegrany" nie "luźniejszy". W każdym razie, nie potrzebujesz "które", tylko zestawienie porównania. Wygląda to jak zadanie dla SQL, więc możesz rzucić okiem na pakiety 'sqldf' i podobne. –

+1

Problem polega na tym, że każda nowa gra musi znać aktualny wynik meczu. To jest tylko problem szachowy. Więc jeśli w grze numer X gra się z niską wartością bieżącą, bije wynik z wysokim prądem. Wtedy osoba o niskim nominale zdobędzie więcej punktów za pobicie wyższego wyniku. – user4098307

+1

W takim przypadku wystarczy uruchomić dwa wyszukiwania rekordów (po jednym dla każdego gracza) i do tego właśnie służy oprogramowanie bazy danych. –

Odpowiedz

2

Dane, które pisał jest śmiesznie małe! Pomyśleć, że muszę coś zainstalować, żeby to unrar ...! Jeśli możesz przesłać znacznie większe dane, będę mógł przetestować przydatność mojej sugestii.

Polecam, aby przekształcić dane użytkowników w macierz z ids jako rownames i umiejętnościami takimi jak colnames. Czemu?

  1. Można uzyskać niewielką poprawę szybkości dostępu do danych za pomocą zwykłego indeksowania zamiast używać which(==) wszędzie. Albo przynajmniej sprawi, że twój kod będzie dużo czytelniejszy.

  2. Co ważniejsze, zmienianie wartości w macierzy odbywa się w miejscu, w oparciu o pamięć; podczas gdy z data.frame, myślę, że twój kod ciągle tworzy cały nowy obiekt, co musi być czasochłonne.


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

nie jest to dużo łatwiejsze do odczytania? Mam nadzieję, że będzie trochę szybciej, proszę przetestuj i daj mi znać. Lub dostarczyć większy zestaw danych, w którym możemy grać. Dzięki.

+1

Po raz pierwszy widziałem, jak ktoś używa 'data.matrix', myślałem, że nigdy nie opuściło pliku pomocy. Zastanawiałem się, gdzie to może być przydatne. –

Powiązane problemy