# ranking based on lower confidence interval

I have a database of bridge scores from a local bridge club that effectively contains for this question, three fields: name, date and score. The score is a percentage, normally ranging from say 30% to 70%. For fun I would like to rank the players' ability.

One way would be to simply compare their means. But this doesn't take into account how often one plays (someone who consistently scores say 58% should perhaps be better ranked than someone who plays once with 60%). So I had the idea to rank by the lower bound of the 95% confidence bound calculated from their scores: lb = mean-t*s/sqrt(n).

Now I have another problem: it can be the case that a player suddenly scores a big result and by consequence lowers their ranking score. For example: after {55,56,56,57,58} the lb value is 54.98 then one tournament later with a nice 70% this becomes {55,56,56,57,58,70} with an lb value of 52.7. This non-monotonicity seems counter intuitive.

So my question: is there a better way to create such a ranking that is monotone (i.e. when a new score is better than the current mean, then the ranking doesn't decrease) and takes into account how often a player plays.

While writing this question I realised another factor that could be taken into account: the order of the inputs. The six results as presented (assuming chronological order) imply that this player is improving. Whereas if the results were really ordered {70,58,57,56,56,55} then perhaps we should conclude that the players' powers are weakening.

• You might consider some kind of exponentially-weighted moving average, perhaps combined with the approach here. Sep 30 '14 at 11:25
• @Glen_b When you say "here" you mean, "here" on this question? Hence I weight the scores, then apply the lower confidence interval calculation on that data: right? Does this guarantee the transitive property? Sep 30 '14 at 12:23
• Yes, here in your question. No, it wouldn't guarantee that transitivity -- it's not clear what aspects of your present solution must be retained and which aspects are less important (and so isn't an answer to your main question). However, it would incorporate the issue in your last paragraph (and that may improve the situation somewhat). Sep 30 '14 at 13:14
• @Glen_b Ok. I will give it a go and play around with it. Many thanks. Sep 30 '14 at 13:26
• I'm looking for the same. Perhaps if you know what algorithm Yelp employs to rank their results based on ratings and confidence, then you could use the same. Please post if you found a method. Mar 10 '19 at 8:11

## 2 Answers

Bridge is special! In tournaments multiple pairs play the same hands, so any rating should not be based only on total score, but on how players/pairs does compared to other players/pairs of the same cards! Could also depend on type of tournament. You must also specify if you want ranking of individual players or pairs. Rating of individual players will need that individuals play in different pairs.

I had a similar problem. R code demonstration.

t.test(c(1.1,2),conf.level = .9)$$co t.test(c(2.1,2),conf.level = .9)$$co
t.test(c(3.1,2),conf.level = .9)\$co


It is caused by the standard deviation shrinking. I offset the problem by using 75th percentile of standard deviations of all items linearly combined with actual sd. However my goals were a bit different than OP. SD suddenly increasing was not a problem only SD drastically decreasing by chance and low N. Maybe always keeping mean SD of all individuals could do what OP wants? Still my solution seems so hackey. Maybe somewhere exists a much better formulation of this problem with more formal solutions.

ttm <- function(x,psd,cl=.95,u_l="u",dsda=10){
if(cl>=1 | cl<=0) warning("confidence level out of bounds")
if(!is.vector(x)) warning("x not a vector")
n <- length(x)
if( n < 1 ) warning("x has length 0")
if(n>1){
nsd <- sd(x) * min( n / dsda , 1) + psd * max((1 - n / dsda) , 0)
} else {
nsd <- psd
}
ttt <- qt((1-(1-cl)/2),df = max((n-1),1))
entrvl <- ttt * nsd / sqrt(n)
if(u_l=="u"){  return( mean(x) + entrvl) }
if(u_l=="l"){  return( mean(x) - entrvl) }
}