How to resolve the algorithm Diversity prediction theorem step by step in the Python programming language
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