import lesterScaling
lesterScaling.scaling_functions[<function lesterScaling.hyperbolic(x, p)>,
<function lesterScaling.skewSymmetric(x, p)>,
<function lesterScaling.skewTopHinged(x, p)>,
<function lesterScaling.skewBottomHinged(x, p)>,
<function lesterScaling.cappedLinearBottomHinged(x, p)>,
<function lesterScaling.cappedLinearTopHinged(x, p)>]
import lesterScaling
raw_marks = [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ]
max_mark = 100 # The maximum possible mark, not the largest mark obtained.
p_value = 0.05 # Parameter to choose how strong the mark scaling should be.
# Scale the above raw marks and round to one decimal place using the "hyperbolic" scaling function:
scaled_marks_1 = [ round(lesterScaling.hyperbolic(raw_mark/max_mark, p_value)*max_mark, 1) \
for raw_mark in raw_marks ]
print("The hyperbolic scaling option with strength p="+str(p_value)+" scales these raw marks:\n")
print(" "+str(raw_marks))
print("")
print("to these scaled marks:\n")
print(" "+str(scaled_marks_1)+".")
# Scale the above raw marks and round to one decimal place using the "skewMean" scaling function:
scaled_marks_2 = [ round(lesterScaling.skewSymmetric(raw_mark/max_mark, p_value)*max_mark, 1) \
for raw_mark in raw_marks ]
print("")
print("Alternatively, for the same scaling strength the skewSymmetric scaling function would generate:\n")
print(" "+str(scaled_marks_2)+".\n")
The hyperbolic scaling option with strength p=0.05 scales these raw marks:
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
to these scaled marks:
[0.0, 11.9, 23.4, 34.4, 44.9, 55.0, 64.7, 74.0, 83.0, 91.6, 100.0].
Alternatively, for the same scaling strength the skewSymmetric scaling function would generate:
[0.0, 11.7, 22.6, 33.1, 43.4, 53.5, 63.3, 73.0, 82.4, 91.5, 100.0].
lesterScaling has no dependencies if you use only the skew scaling functions.
lesterScaling depends on numpy if you use the hyperbolic or capped linear scaling functions.
lesterScaling depends on matplitlib if you use its built-in scaling function drawing methods.
Each of the scaling functions provided in this library is is a function
-
$f(x,p)\in[0,1]\qquad$ (i.e. marks stay in-range), -
$f(x,0) = x\qquad$ (i.e.$p=0$ always leads to the trivial mapping$f : x \mapsto x$ ), -
$\lim_{p\rightarrow+1} f(x,p) = 1$ for all$x\in (0,1]\qquad$ (i.e.$p\rightarrow+1$ corresponds to maximal up-scaling), -
$\lim_{p\rightarrow-1} f(x,p) = 0$ for all$x \in [0,1)\qquad$ (i.e.$p\rightarrow-1$ corresponds to maximal down-scaling), and -
$f(x,p) < f(y,p) \implies x < y\qquad$ (i.e. a candidate who looks worse (or better) than another after scaling was worse (or better) before scaling).
If the scaling function
$f(x,p) < f(y,p) \iff x < y\qquad$
then the scaling function is said to be strictly rank preserving. The rank preserving Property 6 is is a stronger version of Property 5 (and in fact implies 5). Property 6 only creates post-scaling ties where those ties existed before scaling, whereas Property 5 does not prevent students becoming tied post-scaling who were not tied before.
Other users need not agree, but the author takes the view that property 6 is much to be favoured over property 5, as nothing makes an examinee more angry than discoving that their work counted for nothing.
If the scaling function
$f(1,p) = 1\qquad$ $f(0,p) = 0\qquad$
then it is said to be endpoint preserving (i.e. people who get 0% or 100% before scaling get the same mark after scaling).
A scaling function,
scaled_mark = max_mark * f(raw_mark/max_mark, p)
where max_mark is the largest mark possible (usually 100), and "$p$" is a strength of the scaling.
Note that the non-linear nature of these scaling functions means that the value of
- This scaling function is strictly rank preserving and endpoint preserving.
- Very symmetric and easy to define conceptually.
- Conceptual definition has impartiality (not favouring/disfavouring any particular class of student) at its core.
- Implementation must consider and work around instability at
$p=0$ . - Algebraic forumla looks opaque.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
These are the UNIQUELY determined family of hyperbolae (in
- each hyperbola passes through the top right and bottom left corners of the unit square with corners (0,0) amd (1,1),
- each hyperbola is symmetric about the diagonal running from top-left to bottom right of that unit square,
- the location of the midpoint of each hyperbola,
$\text{mid}(p)$ , satisfies:$\text{mid}(p) = (1/2 - p/2, 1/2 + p/2)$ ... i.e. the diagonal mentioned in the last bullet point is traversed at uniform speed if "$p$" is varied at constant speed, and - they hyperbolae are assymptotic to the boundaries of the unit square at as
$p$ tends to$\pm1$ .
The above requirements force:
where
A naive implementation of above function would be susecptible to numerical instability for
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.hyperbolic,))- This scaling function is strictly rank preserving and endpoint preserving.
- Simple algebraic formula.
- No numerical instability.
- Good if you want approximately a linear stretch centered on 100%.
- Easily invertible (is self inverse under
$p\rightarrow -p$ ).
- Formula is totally arbitrary (i.e. it is not constructed with any particular ideas of fairness in mind).
- It rescales low marks very differently to high marks. It may therfore not be percieved as impartial.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
The top hinged skew scaling functioins are the bottom hinged ones rotated by 180 degrees about the centre of the unit square.
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.skewTopHinged,))- This scaling function is strictly rank preserving and endpoint preserving.
- Simple algebraic formula.
- No numerical instability.
- Good if you want approximately a linear stretch centered on 0%.
- Easily invertible (is self inverse under
$p\rightarrow -p$ ).
- Formula is totally arbitrary (i.e. it is not constructed with any particular ideas of fairness in mind).
- It rescales low marks very differently to high marks. It may therfore not be percieved as impartial.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
The bottom hinged skew scaling functioins are the top hinged ones rotated by 180 degrees about the centre of the unit square.
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.skewBottomHinged,))- This scaling function is strictly rank preserving and endpoint preserving.
- Simple algebraic formula.
- No numerical instability.
- Formula is marginally less arbitrary than the other skew scaling functions, as it at least attempts to treat people in the top x% of the mark range symmetrically to how it treats the people in the bottom x% of the mark range.
- Formula is still fairly arbitrary.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.skewSymmetric,))- Simple algebraic formula.
- No numerical instability.
- Good if you want approximately a linear stretch centered on 0%.
- This scaling function is not strictly rank preserving when
$p>0$ , i.e. it can create ties where ties did not exist before scaling - meaning that some students' work is effectively "ignored". - This scaling function is not endpoint preserving when
$p<0$ as people with 100% are given less after scaling. - When
$p>0$ it rescales low marks very differently to high marks. It may therfore not be percieved as impartial. - This scaling function is not smooth (although it is continuous) so its use can lead to artefacts appearing in derived distributions.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
The bottom hinged capped linear scaling functions are the top hinged ones rotated by 180 degrees about the centre of the unit square.
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.cappedLinearBottomHinged,))- Simple algebraic formula.
- No numerical instability.
- Good if you want approximately a linear stretch centered on 100%.
- This scaling function is not strictly rank preserving when
$p<0$ , i.e. it can create ties where ties did not exist before scaling - meaning that some students' work is effectively "ignored". - This scaling function is not endpoint preserving when
$p>0$ as people with 0% are given more after scaling. - When
$p<0$ it rescales low marks very differently to high marks. It may therfore not be percieved as impartial. - This scaling function is not smooth (although it is continuous) so its use can lead to artefacts appearing in derived distributions.
- No scaling function is ever truly impartial. Each is arbitrary it its own way.
The bottom hinged capped linear scaling functions are the top hinged ones rotated by 180 degrees about the centre of the unit square.
lesterScaling.plot_scaling_function_curves(functions=(lesterScaling.cappedLinearTopHinged,))




