akben2
akben2

Reputation: 39

How to get ranks from a sample in a list of values?

I'm new with Python and have a quite simple problem on paper but difficult to me in Python.

I have two samples of values (which are lists) :

X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]

I have a concatenated list which is sorted as

  Z = [ 1 , 2 , 2 , 3 , 4 , 4 , 5 , 6]
 #rank: 1    2.5    4    5.5    7   8

I would like to get the sum of ranks of X values in Z. For this example, the ranks of 2, 2, 4 and 6 in Z are 2.5 + 2.5 + 5.5 + 8 = 18.5

(ranks of Y values in Z are 1 + 4 + 5.5 + 7 = 17.5)

Here is what I've done but it doesn't work with these lists X and Y (it works if each value appears only one time)

def funct(X, Z):
    rank = []
    for i in range(len(Z)):
        for j in range(len(X)):
            if Z[i] == X[j]:
                rank = rank + [(i+1)]
    print(sum(rank))
    return

I would like to solve my problem with not too much complicated functions (only loops and quite easy ways to get a solution).

Upvotes: 2

Views: 882

Answers (3)

Chris Sears
Chris Sears

Reputation: 6802

Here's another option where you build a dictionary of the rank indexes and then create a rank dictionary from there:

from collections import defaultdict

X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]
Z = sorted(X + Y)

rank_indexes = defaultdict(lambda: [])
for i,v in enumerate(Z):
    rank_indexes[v].append(i+1)
ranks = {k:(sum(v)/len(v)) for (k,v) in rank_indexes.items()}

print("Sum of X ranks:", sum([ranks[v] for v in X]))
print("Sum of Y ranks:", sum([ranks[v] for v in Y]))

Output:

Sum of X ranks: 18.5
Sum of Y ranks: 17.5

You can do the same thing without defaultdict, but it's slightly slower and I'd argue less Pythonic:

rank_indexes = {}
for i,v in enumerate(Z):
    rank_indexes.setdefault(v, []).append(i+1)
ranks = {k:(sum(v)/len(v)) for (k,v) in rank_indexes.items()}

Upvotes: 1

pho
pho

Reputation: 25489

You can use a dictionary to keep track of the rank sums and counts once you've sorted the combined list.

X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]

Z = sorted(X + Y)

ranksum = {}
counts = {}

for i, v in enumerate(Z):
    ranksum[v] = ranksum.get(v, 0) + (i + 1) # Add
    counts[v] = counts.get(v, 0) + 1 # Increment count

Then, when you want to look up the rank of an element, you need ranksum[v] / count[v].

r = [ranksum[x] / counts[x] for x in X]
print(r)
# Out: [2.5, 2.5, 5.5, 8]

Upvotes: 2

Mad Physicist
Mad Physicist

Reputation: 114468

Here's a solution for how to build the list of ranks:

X = ...
Y = ...
Z = sorted(X + Y)

rank = [1]
z = Z[:1]
for i, e in enumerate(Z[1:], start=2):
    if e == z[-1]:
        rank[-1] += 0.5
    else:
        rank.append(i)
        z.append(e)

Now you can convert that into a dictionary:

ranks = dict(zip(z, rank))

That will make lookup easier:

sum(ranks[e] for e in X)

Upvotes: 1

Related Questions