Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding majority votes on -1s, 1s and 0s in list - python

How to find the majority votes for a list that can contain -1s, 1s and 0s?

For example, given a list of:

x = [-1, -1, -1, -1, 0]

The majority is -1 , so the output should return -1

Another example, given a list of:

x = [1, 1, 1, 0, 0, -1]

The majority vote would be 1

And when we have a tie, the majority vote should return 0, e.g.:

x = [1, 1, 1, -1, -1, -1]

This should also return zero:

x = [1, 1, 0, 0, -1, -1]

The simplest case to get the majority vote seem to sum the list up and check whether it's negative, positive or 0.

>>> x = [-1, -1, -1, -1, 0]
>>> sum(x) # So majority -> 0
-4
>>> x = [-1, 1, 1, 1, 0]
>>> sum(x) # So majority -> 1
2
>>> x = [-1, -1, 1, 1, 0]
>>> sum(x) # So majority is tied, i.e. -> 0
0

After the sum, I could do this check to get the majority vote, i.e.:

>>> x = [-1, 1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
1
>>> x = [-1, -1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
0

But as noted previously, it's ugly: Python putting an if-elif-else statement on one line and not pythonic.

So the solution seems to be

>>> x = [-1, -1, 1, 1, 0]
>>> if sum(x) == 0:
...     majority = 0
... else:
...     majority = -1 if sum(x) < 0 else 1
... 
>>> majority
0

EDITED

But there are cases that sum() won't work, @RobertB's e.g.

>>> x = [-1, -1, 0, 0, 0, 0]
>>> sum(x) 
-2

But in this case the majority vote should be 0!!

like image 547
alvas Avatar asked Nov 03 '15 23:11

alvas


1 Answers

You could use statistics.mode if you were using python >= 3.4 ,catching a StatisticsError for when you have no unique mode:

from statistics import mode, StatisticsError

def majority(l):
    try:
        return mode(l)
    except StatisticsError:
        return 0

The statistics implementation itself uses a Counter dict:

import  collections
def _counts(data):
    # Generate a table of sorted (value, frequency) pairs.
    table = collections.Counter(iter(data)).most_common()
    if not table:
        return table
    # Extract the values with the highest frequency.
    maxfreq = table[0][1]
    for i in range(1, len(table)):
        if table[i][1] != maxfreq:
            table = table[:i]
            break
    return table

def mode(data):
    """Return the most common data point from discrete or nominal data.

    ``mode`` assumes discrete data, and returns a single value. This is the
    standard treatment of the mode as commonly taught in schools:

    >>> mode([1, 1, 2, 3, 3, 3, 3, 4])
    3

    This also works with nominal (non-numeric) data:

    >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
    'red'

    If there is not exactly one most common value, ``mode`` will raise
    StatisticsError.
    """
    # Generate a table of sorted (value, frequency) pairs.
    table = _counts(data)
    if len(table) == 1:
        return table[0][0]
    elif table:
        raise StatisticsError(
                'no unique mode; found %d equally common values' % len(table)
                )
    else:
        raise StatisticsError('no mode for empty data')

Another way using a Counter and catching an empty list:

def majority(l):
    cn = Counter(l).most_common(2)
    return 0 if len(cn) > 1 and cn[0][1] == cn[1][1] else next(iter(cn),[0])[0]
like image 167
Padraic Cunningham Avatar answered Oct 25 '22 11:10

Padraic Cunningham