Search code examples
pythonscoring

python - scoring based on multiple data points


need guidance on easiest way to do this. i have multiple assets, each with multiple data points. I’m looking to assign a value to each asset based on decisions on each of these data points. As an example, each asset being a house, and data points including number of windows, garage door, broken fence, etc., each house would have a score.

Is there a recommended way of coding this besides the hundreds of if statements and adding/subtracting from a score?

Example of how I plan to do this

def score_house(house):
    # score house
    score = 0
    if (house.windows > 2): score += 10
    if (house.garage): score += 10
    if (house.fence == 'broken'): score += 80
    return score

Solution

  • I think you can also use the "chain of responsibility" pattern here:

    The pattern allows multiple objects to handle the request without coupling sender class to the concrete classes of the receivers. The chain can be composed dynamically at runtime with any handler that follows a standard handler interface.

    What is good about using this pattern is that you can define and extend different scorers in separate modules and combine them dynamically at runtime based on problem conditions. Here is how you can do it. First, define a parent scorer class:

    from functools import reduce
    
    
    class BaseScorer(object):
    
        def __init__(self):
            self._next_scorer = None
    
        def set_next(self, scorer):
            self._next_scorer = scorer
    
            return scorer
    
        def _call_next(self, house, score):
    
            if self._next_scorer is None:
                return score
    
            return self._next_scorer.score(house, score)
    
        def score(self, house, score=0):
            raise NotImplementedError
    
        @staticmethod
        def chain(scorers):
            reduce(lambda x, y: x.set_next(y), scorers)
    
            return scorers[0]
    

    Then, define various scorer classes, for example:

    class WindowScorer(BaseScorer):
    
        def score(self, house, score=0):
    
            if house.windows > 2:
                score = score + 10
    
            return self._call_next(house, score)
    
    
    class GarageScorer(BaseScorer):
    
        def score(self, house, score=0):
    
            if house.garage:
                score = score + 10
    
            return self._call_next(house, score)
    
    
    class FenceScorer(BaseScorer):
    
        def score(self, house, score=0):
    
            if house.fence == 'broken':
                score = score - 5
    
            return self._call_next(house, score)
    

    And this is how it can be used:

    scorer = BaseScorer.chain([
        WindowScorer(),
        GarageScorer(),
        FenceScorer()
    ])
    
    house = House(windows=4, garage=True, fence='nice')
    score = scorer.score(house)