Keener's method

Keener's method is a recursive technique based on Perron-Frobenius theorem. Let Si,j be the number of points, or any other relevant statistics, that i scores against j and Ai,j be the strength of i compared to j. The strength Ai,j can be interpreted as the probability that i will defeat team j in the future. For instance,

Ai,j=Si,j/(Si,j+Sj,i)
or, using Laplace's rule of succession,
Ai,j=(Si,j+1)/(Si,j+Sj,i+2).
Notice that in both cases 0Ai,j1 and Ai,j+Aj,i=1.

The Keener's rating r is the solution of the following recursive equation:

Ar=λr,
where λ is a constant and A is the team strength matrix, or
ri=1λjAi,jrj.
Hence, the thesis of Keener is that team i is strong if it defeated strong teams.

This is in fact eigenfactor centrality applied to strength matrix A. Assuming that matrix A is nonnegative and irreducible (or equivalently that the graph of A is connected), Perron-Frobenius theorem guarantees that a rating solution exists.

The following user-defined function keener computes the Keener's method:

# Keener # ASSUMPTION: graph of A is strongly connected # INPUT # matches: matches data frame # teams: team names # OUTPUT # r: Keener rating # value = eigenvalue # A: match matrix # g: match graph keener = function(matches, teams) { # number of teams n = length(teams) # number of matches m = dim(matches)[1] # match matrix A = matrix(0, nrow=n, ncol=n, byrow=TRUE) # populate match matrix for (i in 1:m) { p = matches[i,"team1"] q = matches[i,"team2"] s1 = matches[i, "score1"] s2 = matches[i, "score2"] A[p,q] = (s1 + 1) / (s1 + s2 + 2); A[q,p] = (s2 + 1) / (s1 + s2 + 2); } # check assumptions g = graph_from_adjacency_matrix(A, mode="directed", weighted=TRUE) if (!is.connected(g, mode="strong")) { cat("The graph is not strongly connected") return(NULL) } e = eigen(A) v = e$values[1] r = Re(e$vectors[,1]) if (r[1] < 0) { r = -r } names(r) = teams V(g)$teams = teams return(list(r = r, value = v, A = A, g = g)) }