How to resolve the algorithm Diversity prediction theorem step by step in the Python programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Diversity prediction theorem step by step in the Python programming language

Table of Contents

Problem Statement

The   wisdom of the crowd   is the collective opinion of a group of individuals rather than that of a single expert. Wisdom-of-the-crowds research routinely attributes the superiority of crowd averages over individual judgments to the elimination of individual noise,   an explanation that assumes independence of the individual judgments from each other. Thus the crowd tends to make its best decisions if it is made up of diverse opinions and ideologies.

Scott E. Page introduced the diversity prediction theorem:

Therefore,   when the diversity in a group is large,   the error of the crowd is small.

For a given   true   value and a number of number of estimates (from a crowd),   show   (here on this page):

Use   (at least)   these two examples:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Diversity prediction theorem step by step in the Python programming language

Source Code Overview

This Python code implements the diversity prediction theorem, which assesses the performance of multiple predictions for a given observation. It calculates metrics like mean error, crowd error, and diversity based on deviations between the predictions and the observed value.

Key Functions:

diversityValues

Calculates the mean error, crowd error, and diversity for an observation x and a list of predictions ps. These metrics quantify the deviation between the predictions and the actual value, as well as the consensus among the predictions.

meanErrorSquared

Computes the mean of the squared differences between the observed value x and a list of predictions ps. This metric measures the overall error in the predictions.

Test Function:

main

Runs unit tests to demonstrate the calculations for various scenarios, including numeric and non-numeric predictions and missing values.

Formatting Functions:

showDiversityValues

Formats the diversity values for an observation and its predictions into a human-readable string representation.

showList

Converts a list into a compact string representation.

showPrecision

Formats a floating-point number with a specified degree of precision.

Generic Functions:

Left, Right

Constructors for the Either data type, used to represent optional values (either a value or an error message).

bindLR

Composes two computations in the Either monad, passing the result of the first computation to the second.

compose

Composes a series of functions from right to left.

concatMap

Maps a function over a list and concatenates the results.

either

Applies a function to the Either value depending on whether it contains a Left or Right value.

identity

The identity function that returns the input unchanged.

indented

Indents a string by a specified number of spaces.

mean

Calculates the arithmetic mean of a list of numeric values.

numLR

Converts a value to either a Right containing the numeric value or a Left containing an error message if the value is not numeric.

numsLR

Converts a list of values to either a Right containing a list of numeric values or a Left containing an error message if any value is not numeric.

partitionEithers

Partitions a list of Either values into two lists, one containing the Left values and the other containing the Right values.

showPrecision

Formats a floating-point number with a specified degree of precision.

unlines

Concatenates a list of strings into a single string separated by newlines.

Usage:

The code can be run from the command line to perform unit tests, demonstrating the calculation of diversity values for various scenarios.

Source code in the python programming language

'''Diversity prediction theorem'''

from itertools import chain
from functools import reduce


#  diversityValues :: Num a => a -> [a] ->
#  { mean-Error :: a, crowd-error :: a, diversity :: a }
def diversityValues(x):
    '''The mean error, crowd error and
       diversity, for a given observation x
       and a non-empty list of predictions ps.
    '''
    def go(ps):
        mp = mean(ps)
        return {
            'mean-error': meanErrorSquared(x)(ps),
            'crowd-error': pow(x - mp, 2),
            'diversity': meanErrorSquared(mp)(ps)
        }
    return go


# meanErrorSquared :: Num -> [Num] -> Num
def meanErrorSquared(x):
    '''The mean of the squared differences
       between the observed value x and
       a non-empty list of predictions ps.
    '''
    def go(ps):
        return mean([
            pow(p - x, 2) for p in ps
        ])
    return go


# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Observed value: 49,
       prediction lists: various.
    '''

    print(unlines(map(
        showDiversityValues(49),
        [
            [48, 47, 51],
            [48, 47, 51, 42],
            [50, '?', 50, {}, 50],  # Non-numeric values.
            []                      # Missing predictions.
        ]
    )))
    print(unlines(map(
        showDiversityValues('49'),  # String in place of number.
        [
            [50, 50, 50],
            [40, 35, 40],
        ]
    )))


# ---------------------- FORMATTING ----------------------

# showDiversityValues :: Num -> [Num] -> Either String String
def showDiversityValues(x):
    '''Formatted string representation
       of diversity values for a given
       observation x and a non-empty
       list of predictions p.
    '''
    def go(ps):
        def showDict(dct):
            w = 4 + max(map(len, dct.keys()))

            def showKV(a, kv):
                k, v = kv
                return a + k.rjust(w, ' ') + (
                    ' : ' + showPrecision(3)(v) + '\n'
                )
            return 'Predictions: ' + showList(ps) + ' ->\n' + (
                reduce(showKV, dct.items(), '')
            )

        def showProblem(e):
            return (
                unlines(map(indented(1), e)) if (
                    isinstance(e, list)
                ) else indented(1)(repr(e))
            ) + '\n'

        return 'Observation:  ' + repr(x) + '\n' + (
            either(showProblem)(showDict)(
                bindLR(numLR(x))(
                    lambda n: bindLR(numsLR(ps))(
                        compose(Right, diversityValues(n))
                    )
                )
            )
        )
    return go


# ------------------ GENERIC FUNCTIONS -------------------

# Left :: a -> Either a b
def Left(x):
    '''Constructor for an empty Either (option type) value
       with an associated string.
    '''
    return {'type': 'Either', 'Right': None, 'Left': x}


# Right :: b -> Either a b
def Right(x):
    '''Constructor for a populated Either (option type) value'''
    return {'type': 'Either', 'Left': None, 'Right': x}


# bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
def bindLR(m):
    '''Either monad injection operator.
       Two computations sequentially composed,
       with any value produced by the first
       passed as an argument to the second.
    '''
    def go(mf):
        return (
            mf(m.get('Right')) if None is m.get('Left') else m
        )
    return go


# compose :: ((a -> a), ...) -> (a -> a)
def compose(*fs):
    '''Composition, from right to left,
       of a series of functions.
    '''
    def go(f, g):
        def fg(x):
            return f(g(x))
        return fg
    return reduce(go, fs, identity)


# concatMap :: (a -> [b]) -> [a] -> [b]
def concatMap(f):
    '''A concatenated list over which a function has been mapped.
       The list monad can be derived by using a function f which
       wraps its output in a list,
       (using an empty list to represent computational failure).
    '''
    def go(xs):
        return chain.from_iterable(map(f, xs))
    return go


# either :: (a -> c) -> (b -> c) -> Either a b -> c
def either(fl):
    '''The application of fl to e if e is a Left value,
       or the application of fr to e if e is a Right value.
    '''
    return lambda fr: lambda e: fl(e['Left']) if (
        None is e['Right']
    ) else fr(e['Right'])


# identity :: a -> a
def identity(x):
    '''The identity function.'''
    return x


# indented :: Int -> String -> String
def indented(n):
    '''String indented by n multiples
       of four spaces.
    '''
    return lambda s: (4 * ' ' * n) + s

# mean :: [Num] -> Float
def mean(xs):
    '''Arithmetic mean of a list
       of numeric values.
    '''
    return sum(xs) / float(len(xs))


# numLR :: a -> Either String Num
def numLR(x):
    '''Either Right x if x is a float or int,
       or a Left explanatory message.'''
    return Right(x) if (
        isinstance(x, (float, int))
    ) else Left(
        'Expected number, saw: ' + (
            str(type(x)) + ' ' + repr(x)
        )
    )


# numsLR :: [a] -> Either String [Num]
def numsLR(xs):
    '''Either Right xs if all xs are float or int,
       or a Left explanatory message.'''
    def go(ns):
        ls, rs = partitionEithers(map(numLR, ns))
        return Left(ls) if ls else Right(rs)
    return bindLR(
        Right(xs) if (
            bool(xs) and isinstance(xs, list)
        ) else Left(
            'Expected a non-empty list, saw: ' + (
                str(type(xs)) + ' ' + repr(xs)
            )
        )
    )(go)


# partitionEithers :: [Either a b] -> ([a],[b])
def partitionEithers(lrs):
    '''A list of Either values partitioned into a tuple
       of two lists, with all Left elements extracted
       into the first list, and Right elements
       extracted into the second list.
    '''
    def go(a, x):
        ls, rs = a
        r = x.get('Right')
        return (ls + [x.get('Left')], rs) if None is r else (
            ls, rs + [r]
        )
    return reduce(go, lrs, ([], []))


# showList :: [a] -> String
def showList(xs):
    '''Compact string representation of a list'''
    return '[' + ','.join(str(x) for x in xs) + ']'


# showPrecision :: Int -> Float -> String
def showPrecision(n):
    '''A string showing a floating point number
       at a given degree of precision.'''
    def go(x):
        return str(round(x, n))
    return go


# unlines :: [String] -> String
def unlines(xs):
    '''A single string derived by the intercalation
       of a list of strings with the newline character.'''
    return '\n'.join(xs)


# MAIN ---
if __name__ == '__main__':
    main()


  

You may also check:How to resolve the algorithm Named parameters step by step in the Mathematica/Wolfram Language programming language
You may also check:How to resolve the algorithm Elementary cellular automaton step by step in the Racket programming language
You may also check:How to resolve the algorithm Aliquot sequence classifications step by step in the Elixir programming language
You may also check:How to resolve the algorithm Classes step by step in the VBA programming language
You may also check:How to resolve the algorithm Singly-linked list/Traversal step by step in the Rust programming language