Created
November 27, 2011 12:01
-
-
Save davidrichards/1397470 to your computer and use it in GitHub Desktop.
The Learning Curve
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=begin | |
One of my favorite equations from business school: the learning curve. | |
Human experience has shown that every time our experience with a single | |
task doubles, our efficiency increases by 20%. Our learning curve is | |
actually around 20%, with a 95% confidence rate around 10% and 30%. | |
This was the equation that founded BCG as they measured everything | |
related to the then-new aviation industry. It's been used to measure | |
all sorts of human tasks and has proven pretty resilient for people of | |
all kinds of backgrounds and aptitudes. | |
One interesting extension to this little class would be to calculate | |
the actual learning curve, given two measurements, but I did this little | |
exercise to deal with insomnia, and I'm finally feeling sleepy again. | |
=end | |
class LearningCurve | |
RATE = 0.2 | |
attr_accessor :initial_cost | |
def initialize(initial_cost=1) | |
@initial_cost = initial_cost | |
end | |
attr_writer :n | |
def n | |
@n ||= 1 | |
end | |
def times_doubled | |
Math.log2(n) | |
end | |
def unit_cost | |
((1 - RATE) ** times_doubled) * initial_cost | |
end | |
def assert_initial_cost_assuming_unit_cost_of(unit_cost) | |
@initial_cost = unit_cost / ((1 - RATE) ** times_doubled) | |
end | |
# Had to break out the algebra for this one. | |
# unit_cost = ((1 -rate)^log base 2(n)) * initial_cost | |
# unit_cost / initial_cost = (1-rate)^log base 2(n) | |
# log base(1-rate)(unit_cost / initial_cost) = log base 2(n) | |
# 2^(log base(1-rate)(unit_cost / initial_cost)) = n | |
# since log base(1-rate)(unit_cost / initial_cost) = log(unit_cost / initial_cost) / log(1-rate) | |
# I get this final form, rounded up (since the experience must be finished) | |
def experience_needed_for_unit_cost_under(unit_cost) | |
(2**(Math.log(unit_cost.to_f / initial_cost) / Math.log(1 - RATE))).ceil | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require File.expand_path('../spec_helper', __FILE__) | |
describe LearningCurve do | |
before do | |
@curve = LearningCurve.new | |
end | |
it "should return 1.0 unit_cost and 0.0 times_doubled at n == 1" do | |
@curve.n = 1 | |
@curve.unit_cost.should be_within(1.0e-05).of(1.0) | |
@curve.times_doubled.should eql(0.0) | |
end | |
it "should return 0.8 unit_cost and 1.0 times_doubled at n == 2" do | |
@curve.n = 2 | |
@curve.unit_cost.should be_within(1.0e-05).of(0.8) | |
@curve.times_doubled.should eql(1.0) | |
end | |
it "should return 0.64 unit_cost and 2.0 times_doubled at n == 4" do | |
@curve.n = 4 | |
@curve.unit_cost.should be_within(1.0e-05).of(0.64) | |
@curve.times_doubled.should eql(2.0) | |
end | |
it "should return 0.512 unit_cost and 3.0 times_doubled at n == 8" do | |
@curve.n = 8 | |
@curve.unit_cost.should be_within(1.0e-05).of(0.512) | |
@curve.times_doubled.should eql(3.0) | |
end | |
it "should take into account the initial cost" do | |
initial_cost = 15 | |
unit_rate = 0.64 | |
@curve = LearningCurve.new(initial_cost) | |
@curve.n = 4 | |
@curve.unit_cost.should be_within(1.0e-05).of(initial_cost * unit_rate) | |
@curve.times_doubled.should eql(2.0) | |
end | |
it "should be able to recompute the initial_cost" do | |
@curve.n = 10 | |
@curve.assert_initial_cost_assuming_unit_cost_of(2) | |
# A little algebra to solve for the initial cost | |
expected = 2 / ((1 - LearningCurve::RATE) ** Math.log2(10)) | |
@curve.initial_cost.should be_within(1.0e-05).of(expected) | |
end | |
it "should be able to calculate the number of experiences needed to have a specific unit cost" do | |
@curve.n = 10 | |
initial_cost = 2 / ((1 - LearningCurve::RATE) ** Math.log2(10)) | |
@curve.initial_cost = initial_cost | |
# Had to break out the algebra for this one. | |
expected = (2**(Math.log(1.0 / initial_cost) / Math.log(1 - LearningCurve::RATE))).ceil | |
@curve.experience_needed_for_unit_cost_under(1).should be_within(1.0e-05).of(expected) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@curve = LearningCurve.new | |
@curve.n = 10 # Assuming 10 bowties have been made | |
@curve.assert_initial_cost_assuming_unit_cost_of(2) # Gives us 4.197184791733325 | |
@curve.experience_needed_for_unit_cost_under(1) # Gives us 87, or 77 more bowties |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment