Ranking algorithms to compare "Rankings" - algorithm

Is there an algorithm that allows to rank items based on the difference of the position of those items in two rankings but also "weighted" with the position, e.g. one Player that goes from position 2->1 should be ranked higher than a player that went from 9->8.
Toy example, I have two lists/ranks:
Rank 1:
Player a
Player b
Player c
Player d
...
Rank 2:
Player d
Player c
Player a
Player b
...
I was thinking to "weight" the ranking difference with the average ranking (or other value), for example, if a player goes from 9->8 the value used to rank will be (9-8)/avg(8,9) = 1/8,5.

What you want seems more or less equivalent to Spearman's rank correlation in non-parametric statistics. It basically sums the squares of the amount_moved (the difference between the old rank and the new rank)

Number your list backwards. Calculate the "value" of moving between positions as the difference of the squares of these numbers.
So if you've got 10 items in your list:
2->1 would be 10^2 - 9^2 = 19
9->8 would be 3^2 - 2^2 = 5.
Hard to tell if this is exactly what you're after without knowing what kind of relative weights you're after. If this doesn't quite suit you, try raising/lowering the exponent to find something that fits.

Related

Finding algorithm that minimizes a cost function

I have a restroom that I need to place at some point. I want the restroom's placement to minimize the total distance people have to travel to get there.
So I have x apartments, and each house has n people living in each apartment, so the apartments would be like a_1, a_2, a_3, ... a_x and the number of people in a_1 would be n_1, a_2 would be n_2, etc. No two apartments can be in the same space and each apartment has a positive number of people.
So I know the distance between an apartment a_1 and the proposed bathroom, placed at a, would be |a_1 - a|.
MY WORKING:
I defined a cost function, C(a) = SUM[from i = 1 to x] (n_i)|a_i - a|. I want to find the location a that minimizes this cost function, given two arrays - one for the location of the apartments and one for the number of people in each apartment. I want my algorithm to be in O(n) time.
I was thinking of representing this as a graph and using MSTs or Djikstra's but that would not meet the O(n) runtime. Clearly, there must be something I can do without graphs, but I am unsure.
My understanding of your problem:
You have a once dimensional line with points a1,...,an. Each point has a value n1,....n, and you need to pick a point a that minimizes the cost function
SUM[from i = 1 to x] (n_i)|a_i - a|.
Lets assume our input a1...an is sorted.
Our strategy will be a sweep from left to right, calculating possible a on the way.
Things we will keep track of:
total_n : the total number of people
left_n : the number of people living to the left or at our current position
right_n : the number of people living to the right of our current position
a: our current postition
Calculate:
C(a)
left_n = n1
right_n = total_n - left_n
Now we consider what happens to the sum if we move our restroom to the right 1 step. The people on the left get 1 step further away, but the people on the right get 1 step closer.
We can say that C(a+1) = C(a) +left_n -right_n
If the range an-a1 is fairly small, we can use this and just step through the range using this formula to update the sum. Note that when this sum starts increasing we have gone too far and can safely stop.
However, if the apartments are very far apart we cannot step 1 by 1 unit. We need instead to step apartment by apartment. Note
C(a[i]) = C(a[i-1]) + left_n*(a[i]-a[a-1]) - right_n*(a[i]-a[i-1])
If at any point C(a[i]) > C(a[i-1]) we know that the correct position of the restroom is somewhere between i and i-1.
We can calculate that position, lets call it x.
The sum at x is C(a[i-1]) + left_n*(x-a[i-1]) - right_n*(x-a[i-1]) and we want to minimize this. Note that everything but x is known values.
We can simplify to
f(x) = C(a[i-1]) + left_n*x-left_n*a[i-1]) - right_n*x-left_n*a[i-1])
Constant terms cannot affect our decision so we are actually looking to minize
f(x) = x*(left_n-right_n)
We see that if left_n < right_n we want the restroom to be at i+1, but if left_n > right_n we want the restroom to be at i.
We need to at most do this calculation at each apartment, so the running time is O(n).

Algorithm to optimize a team formation based on player rating and power

I want to create an algorithm for a hypothetical game where you can create as many groups as desired with a given list of players.
Suppose I have a list of players, where every player is represented by their rating.
Given The following matrix
The numbers in yellow correspond to the amount of players in any given group.
The numbers in white correspond to the score that each player in the group is contributing.
The numbers in orange correspond to the rating threshold needed for the corresponding score.
For example, if I have a group of players of rating [50, 100], using the matrix it can be determined that they are each generating a score of 26.45, since the total rating is 150 and there are two players in that group. The total score in that team is 52.90.
Ideally the algorithm would return the groups that yield to the best score, with the constraints that I can make as many groups as wanted, and not all players need to be put in a group.
What would be a good way to get started or solve this algorithm?
I'd reduce this problem to weighted set packing and use a mixed integer program (MIP) solver library such as OR-Tools.
For every subset S of players that can form a group, we have a variable x(S) that is 1 if we choose the subset and 0 otherwise. We let the score of the subset be score(S), so that the objective is to maximize the sum over S of score(S) x(S). We have a constraint for each player p: the sum over all S containing p of x(S) is at most 1.
For example, with three players with all nonempty subsets as possible groups, we would get
maximize score({1}) x({1}) + score({2}) x({2}) + score({3}) x({3}) +
score({1,2}) x({1,2}) + score({1,3}) x({1,3}) + score({2,3}) x({2,3}) +
score({1,2,3}) x({1,2,3})
subject to
x({1}) + x({1,2}) + x({1,3}) + x({1,2,3}) <= 1
x({2}) + x({1,2}) + x({2,3}) + x({1,2,3}) <= 1
x({3}) + x({1,3}) + x({2,3}) + x({1,2,3}) <= 1
x({1}), ..., x({1,2,3}) in {0, 1}
Unless the scores are close to linear, modern MIP solvers on modern hardware should be able to scale to 20 players. If not, there are more complicated techniques.

Combinatorial optimization for selecting the players of a football team

I'm thinking of using integer programming to generate the optimal combination of football players to comprise a team.
Though the problem itself is simple, I'm having trouble formulating an efficient constraint for position eligibility.
I've searched stackoverflow for variants on the classic integer programming problems and came up with a temporary solution, but want to verify if the current one is efficient.
Problem
Select 11 players for a football (soccer) team from a finite set of potential players.
The team is composed of 11 slots: 5 offense, 5 defense, and 1 goal keeper.
Each role has its own respective pool of eligible players.
(e.g. goalies can only be selected from a set of players that have gloves)
Each player is assigned a 'skill score' that represents their skill
Objective function
Maximize: sum of all 11 player skill scores
Constraints
All 11 slots must be filled with at least 1 player
1 player may occupy only 1 slot
Each slot must be filled by a player that is eligible for the role
My temporary solution
Let xij: player i in consideration for slot j (j=1, 2,..., 11, 1 <= i <= n)
and w: n x 1 weight matrix representing skill score for player i
1. sum_j(xij) == 1 for each slot j
2. 0 <= sum_i(xij) <= 1 for each player i
3. 0 <= xij <= 1 if player i is eligible for slot j, == 0 otherwise
maximize sum(wTx)
I could not yet think of an elegant way to operationalize 3, so my answer for now is to hard code each cell to be 0.
I'm planning to use an integer programming library in Python (cvxpy or PuLP).
Would the current design lead to any issues in convergence or computation time?
Would there be a more efficient way to model the problem?
Notes
For simplicity, let's assume that while a player can be a candidate for multiple roles, their skill point does not change depending on role
Would the problem formulation change if the players' skill scores change depending on their synergy with other players? I'm thinking that simply expanding the x matrix by nC2 possible interactions could work, but am curious if there are better solutions.
Your IP formulation looks OK. However, this problem can also be solved using Dynamic Programming:
Let the array dp[n][mask] represent the maximum possible score you can get for placing players from 1 to n into positions that the 0 digits in the mask's binary representation correspond. For example dp[5][0b11111110101] is equal to the maximum score you can get for placing players 1 to 5 into positions 2 and 4. (second and fourth bits of the mask are zero.)
Now we recursively define dp[n][mask]:
dp[n][mask] = max{
dp[n-1][mask], # the case when we don't use player n
max_j{ dp[n-1][mask|(1<<j)] + w[n] } (1 <= j <= 11 and mask's jth bit is 0)
}
The base case is when n=0.
dp[0][mask] = {
-infinity, if there are 0 bits in mask # there are empty positions left, we want to strictly discourage this case.
0, if all 11 bits of mask is 1
}

Maximize the score of circular arrangement of numbers

I am looking for an efficient algorithm to solve a problem of arranging a circular set of numbers between 1-12 to get the highest score.
The score of an arrangement is given by the sum of the score of all its adjacent pairs
To get the score of an adjacent pair (a,b), the following steps are calculated:
1. Find x such that (a+x) mod 12 = b
2. Look up x in a score table
3. The value in the score table at index 'x' is the score of the pair (a,b).
This is repeated for every adjacent pair and the sum is the score of the arrangement.
Here is an example:
Suppose the score table is [5,4,6,7,2,7,-2,-6,-8,-2,6,12,13]
Consider these numbers: 5, 12, 8, 9
For each adjacent pairs,
the values for x are: 5 -> 12: 7
12 -> 8: 8
8 -> 9: 1
9 -> 5: 8
The values for score[x] are:
score[7] = -6
score[8] = -8
score[1] = 4
score[8] = -6
The sum of the score[x] values is: (-6) + (-8) + (4) + (-6)
= -18
The goal is to come up with an algorithm to efficiently arrange the numbers to maximize the score, given the numbers themselves - up to twenty of them between 1 and 12 - and the score table.
Many thanks,
You can solve this problem with an exact TSP solver.
Imagine there's a set of cities, each which has a "value". We'll say that the value of a city x is V(x). Now imagine that to travel from city x to y it costs S(V(y) - v(X) (mod 12)). Note that S is your score table and V(y) - V(x) (mod 12) is the value to be looked up in the score table.
The goal of TSP is to find what order you should visit all the cities exactly once to optimize your cost -- in this case, you want to maximize your cost. (Alternatively, you could just make your scoring function negative and minimize your cost.)
That is, TSP will give you a permutation of the set of cities that optimize your score. Since your cities are actually the values you're interesting in permuting, it will give you a permutation of your values that produces an optimal score.
So.. Find a program or library that allows you to specify how much it costs to fly from city x to city y and then let it run and it'll give you the optimal permutation of your cities -- then you can replace the city IDs with the value (V(id)) to get the optimal solution you were looking for.
You could write your own TSP solver as well -- branch & bound techniques look popular.

Algorithm: finding the biggest element of a list

The catch: only comparisons between elements of the list is allowed. For example, suppose we have 1,000,000 chess players, and we are assigned the task of finding the best chess player in the group. We can play one chess player against any other chess player. Now, we want to minimize the maximum number of games any player plays.
If player A beats player B, and B beats C, we can assume that A is better than C. What is the smallest n such that no player plays more than n games?
#Carl: This is not homework; it's actually a subproblem of a larger problem from SPOJ.
I would wager a guess that the answer is the binary log of the number of people.
You set up a binary tree as a tournament ladder. This means the most games anyone plays is the height of the tree. The height of the binary tree would be log n
How do I find the biggest element of a list
If the list is ordered, then the biggest element is the first (or last) element of the list.
If the list is not ordered then:
Element biggest = list.get(0);
for (Element e : list) {
if (e.compareWith(biggest) > 0) {
biggest = e;
}
}
For example, suppose we have 1,000,000 chess players, and we are assigned the task of finding the best chess player in the group. Now, we want to minimize the maximum number of games any player plays.
With the new constraint of the last sentence ...
Answer #1: zero games played. Compare the chess player's rankings and the one with the best ranking is the objectively best player ... according to the ranking.
Answer #2: at most ceiling(log2(nos_players)) games played per player. A "knock out" / elimination tournament eliminates half the players in each round, so the number of rounds and hence the maximum number of games played by any one player is ceiling(log2(nos_players)).
The corresponding algorithm is trivially:
List players = ...
while (players.size() > 1) {
List winners = new ArrayList();
Iterator it = players.iterator();
while (it.hasNext()) {
Player p1 = it.next();
if (it.hasNext()) {
Player p2 = it.next();
int result = p1.compareTo(p2);
if (result < 0) {
winners.add(p2);
} else if (result > 0) {
winners.add(p1);
} else {
throw new Exception("draws are impossible in chess");
}
} else {
winners.add(p1); // bye
}
}
players = winners;
}
(Aside: if you also have a predetermined ranking for the players and the number of players N is at least 2 less than ceiling(log2(N)), you can arrange that the best 2 players get a bye in one round. If the best 2 players meet in the final, then everyone will have played less than ceiling(log2(N)) games ... which is an improvement on the solution where the byes are allocated randomly.)
In reality, answer #2 does not work for the game of chess because it does not take account of the fact that a significant percentage of real chess games are draws; i.e. neither player wins. Indeed, the fact that player A beat player B in one game does not mean A is a better player than B. To determine who is the better of any two players they need to play a number of games and tally the wins and losses. In short, the notion that there is a "better than" relation for chess players is TOTALLY unrealistic.
Not withstanding the points above, knock-out is NOT a practical way to organize a chess tournament. Everyone will be camped out on the tournament organizer's desk complaining about having to play games against players much better (or worse) than themselves.
The way a real chess (or similar) tournament works is that you decide on the number of rounds you want to play first. Then in a "round-robin" tournament, you select the top N players by ranking. and arrange that each player plays each other player. The player with the best win / draw score is the winner, and in the event of a tie you use (say) "sum of opponents scores" as a tie breaker. There are other styles of tournament as well that cater for more players / less rounds.
As far as I know there is no algorithm to solve your problem without any additional outside information to rank the players (such as seeding). If you could seed the players appropriately you can find the best player in less rounds than the worst case suggested by J. Wong.
Example of the results of 2 rounds of 10 players: A is the best, ceil(log 10) = 4
A > B; C > D; E > F; G > H; I > J
A > C; B > E; F > G; D > I
Instead of building an Abstract Data Structure such as a binary tree and resolving a tournament, you could re-interpret your goal in a different light:
Eliminate all the elements on the list that are not the largest
You will find that doing this may be much more algorithmically expedient than building a tree and seeding a "tournament".
I can demonstrate that eliminating all elements on a list that are not the largest can be done with a worst-case scenario of log n calls/comparisons per element.
Work on a copy of your original list if possible.
Pair off consecutive elements and remove from the list the lower-valued of the two. Ignore the unpaired element, if there is one.
This can be done by iterating from 0 <= i < int(n/2) and comparing indices 2i and 2i+1.
i.e., for n=7, int(n/2) = 3, i = 0,1,2; compare indices 0 and 1, 2 and 3, 4 and 5.
There should be a total of int(n/2) indices eliminated. Subtract that count from n. Then, repeat 1 until there is only one index remaining. This will be your largest.
Here is an implementation in Ruby:
def find_largest(list)
n = list.size
working_list = list.clone()
while n > 1
temp_list = Array.new()
for i in (0...n/2) # remember to cast n/2 to integer if not automatic
if working_list[2*i] > working_list[2*i+1]
new_list.push(working_list[2*i])
else
new_list.push(working_list[2*i+1])
end
end
working_list = temp_list
n -= n/2 # remember to cast n/2 to integer if not automatic
end
return working_list[0]
end

Resources