Practical Business Decision-Making

Bill Molchan

The Sales Funnel

How impressions get converted to Sales

Assumption:

Every time a customer is called or required to perform an action, there is a chance that the customer advances one level down the funnel, otherwise they drop out

Example

The Sales Funnel (Numeric)

Adding some numbers:
Using 100 potential customers,
60% that are called book a rep
2/3 that book a rep keep the appointment
1/2 that keep the appointment buy something

Sample Insight

Q) How many calls to make 100 sales
A) Exactly 500

Thought Experiment

1000:1 that 100 coin flips results in exactly 50 heads

Do you not trust my coin?

What if you bring the coin?

Exploring the results

Even if the coin is fair, the concept of random prevents us from being certain about the outcome of repeated trials.

The coin doesn’t necessarily have 50% chance of landing on heads.

Your CONFIDENCE in the outcome affects the risk/reward payoff

A better Model

DiscretePlot[
	PDF[BinomialDistribution[100,.5],k],{k,100},
	PlotRange->All,PlotMarkers->Automatic,
	PlotLabel->"Number of Heads in 100 flips of fair coin\n Given by Binomial Distribution"]

CDF[BinomialDistribution[100,.5],.001] (*1000:1 that there are less than 35 heads*)

myCdf=CDF[BinomialDistribution[100,.5],#]&;
myCdf[60]-myCdf[40]
myCdf[70]-myCdf[30]

Probabilistic Funnel

Applying the coin concept to the sales funnel, at every stage, with the help of (Markov Chain) Monte Carlo

Concept

DiscretePlot[
	PDF[BinomialDistribution[100,.6],k],{k,100},
	PlotRange->All,PlotMarkers->Automatic,
	PlotLabel->"Number of Cold Calls that Booked\n Given by Binomial Distribution"]

Result

Using the same population of 100, but running 5000 samples to satisfy the statistics.

numSamples=5000;
numBooks=RandomVariate[BinomialDistribution[100,.6],numSamples];
numAppts=Map[RandomVariate[BinomialDistribution[#,.66]]&,numBooks];
numSales=Map[RandomVariate[BinomialDistribution[#,.5]]&,numAppts];

imagesize=420;
numBoxes=80;
Column[{Histogram[{numBooks,numAppts,numSales},numBoxes,ImageSize->imagesize*1.3,PlotLabel->"Sales Funnel",ChartLegends->{"Booked Appt","Kept Appt","Sales"}], "     ",
Row[Reverse@{Histogram[numBooks,numBoxes,PlotLabel->"50-70 Reps Booked",PlotRange->{Automatic,{0,550}},ImageSize->imagesize,AxesLabel->Reverse@{"Simulations","Reps"}],
	Histogram[numAppts,numBoxes,PlotLabel->"25-50 Appts Kept",PlotRange->{Automatic,{0,550}},ChartStyle->Blue,ImageSize->imagesize,AxesLabel->{"Appts","Simulations"}],
	Histogram[numSales,numBoxes,PlotLabel->"10-30 Sales",PlotRange->{Automatic,{0,550}},ChartStyle->Green,ImageSize->imagesize,AxesLabel->{"Sales","Simulations"}]} ,"     "]},Alignment->Center]

A Tool For Decision-Making

Dynamic Sales Funnel

And a reconsideration of the previous question

Manipulate[Module[{numSamples,numBooks,numAppts,numSales},
	numSamples=5000; (*Increase for more flush histograms*)
	(*These can be loop-fused together, but are seperated for readability*)
	numBooks=RandomVariate[BinomialDistribution[numCalls,.6],numSamples];
	numAppts=Map[RandomVariate[BinomialDistribution[#,.66]]&,numBooks];
	numSales=Map[RandomVariate[BinomialDistribution[#,.5]]&,numAppts];
	(*Output Formatting*)
	imagesize=340;
	numboxes=40;
	Row[{Histogram[numBooks,numboxes,PlotLabel->"Reps Booked",ImageSize->imagesize],
		Histogram[numAppts,numboxes,PlotLabel->"Appts Kept",ImageSize->imagesize],
		Histogram[numSales,numboxes,PlotLabel->"Sales",ImageSize->imagesize],
		Column@{"Chance of 100 Sales: \n"<>ToString[1-N@CDF[HistogramDistribution[numSales],100]]}},"   "]] ,
	{{numCalls,500,"Number of Calls"},400,650,50}]

But what if we aren’t clairvoyant?

Even the probabilistic sales funnel assumed that the coin was fair and that we knew the chances of success.

Introducing the Beta Distribution

Conjugate Prior to Bernoulli/Binomial distributions
2 parameter input: #successes and #failures

imagesize=500;
Row@{
	Plot[PDF[ BetaDistribution[10,10],x],{x,0,1},
		PlotLabel->"Weak Confidence\n20 coin flips",PlotRange->{0,8},ImageSize->imagesize],   "              ",
	Plot[PDF[ BetaDistribution[50,50],x],{x,0,1},
		PlotLabel->"Strong Confidence\n100 coin flips",PlotRange->{0,8},ImageSize->imagesize]}

Real Application

What should the sales commission rate be?

Assumptions

Higher commissions results in better sale conversion rates (id est funnel values) with diminishing returns

Some fraction of the population are repeat customers that would return anyways.

Representation

Plot[{
	PDF[ BetaDistribution[12,38],x],
	PDF[ BetaDistribution[20,30],x]},
	{x,0,1},PlotLabel->"Sales Conversion with different comission rules\n Dramatized for effect",PlotRange->{0,8},PlotLegends->{"Low Comission","High Commission"}]

Sample Results

Creating a Tool

(*Transformed Distribution and/or ParallelTable work here*)
Manipulate[Module[{initPop,numSamples,ticketPrice,natReturn,comReturn,salesSamples,natReturnNumerical,comReturnNumerical,natReturnNumbers,comReturnNumbers,natReturnNet,comReturnNet,takeSamples,pairedDifference,upQuant,upMidQuant,lowQuant,lowMidQuant,mean},
	
	numSamples=2000;
	initPop=1000;
	ticketPrice=30;
	
(*Represents speculation about sales rates with/without commission, for easier results a term can be added to the comRate to make it scale with commission size*)
	natReturn=BetaDistribution[10,90]; (*10/100 successes*)
	comReturn=BetaDistribution[s,s+f];  (*s/(s+f) successes *)
	
(*Sampling sales rates*)
takeSamples=RandomVariate[#,numSamples]&;
	natReturnNumerical=takeSamples@natReturn;
	comReturnNumerical=takeSamples@comReturn;

(*Sampling number of sales for each rate sample*)
salesSamples=takeSamples[BinomialDistribution[initPop,#]]&;
	natReturnNumbers=salesSamples/@natReturnNumerical;
	comReturnNumbers=salesSamples/@comReturnNumerical;

(* Add profits*)
	natReturnNet=ticketPrice*Flatten@natReturnNumbers;
	comReturnNet=(1-comSize)*ticketPrice*Flatten@comReturnNumbers;

(*Pairwise Differences*)
	pairedDifference=comReturnNet-natReturnNet;

(*Quantiles*)
	upQuant=Quantile[pairedDifference,.95];
	upMidQuant=Quantile[pairedDifference,.9];
	lowQuant=Quantile[pairedDifference,.05];
	lowMidQuant=Quantile[pairedDifference,.1];
	mean=Mean@pairedDifference;
imagesize=500;
Column[{Histogram[pairedDifference,60,PlotLabel->"Profit Gained from:\n"<> ToString[Round[100*comSize]] <>"% Commission",
		PlotRange->{{-5000,5000},{0,260000}},ImageSize->imagesize,AxesLabel->{"$","Simulations"}],
	"\n\tExpected Value: "<>ToString@mean<>
	"\n\t5% Worst Case: "<>ToString@lowQuant<>
	"\n\t10% Worst Case: "<>ToString@lowMidQuant<>
	"\n\t10% Best Case: "<>ToString@upMidQuant<>
	"\n\t5% Best Case: "<>ToString@upQuant},Alignment->Center]],{{comSize,.15,"Commission rate"},0,1,.05},{{s,8,"Commission Successes"},0,100},{{f,42,"Commission Failures"},0,100}]

Bonus Content

Fun Example for anyone working with programmers.

Project Planning Solution

The PERT distribution has an intuitive fitting,
	Parameters are Min, Max, Mode

Manipulate[Module[{min,max,mode},
	min=2;
	max=240;
	mode=20;
	Plot[
		PDF[PERTDistribution[{2,120},20,certainty],x],
		{x,0,240},
		PlotLabel->"When Programmers say 20 minutes",
		AxesLabel->{"Minutes","Probabiltiy"},
		ImageSize->500,
		PlotRange->{{0,140},{0,.023}}]],
	{{certainty,3,"Certainty"},0,5,.1}]

Applied Distribution

Dataset

4 ‘10 minute tasks’
4 ‘20’ minute tasks’

taskSet=Dataset[Association[Thread[
	{"Dream Doodads","Discuss Doodads", "Design Doodads", "Transfer Specs", "Write Doodad UML", "Implement Programming", "Design User Interface", "Implement User Interface"}->
		Association/@(
			{"Min"->#[[1]],"Max"->#[[2]],"Mode"->#[[3]]}&/@{{2,40,10},{5,30,10},{5,25,10},{1,100,10},{10,50,20},{10,80,20},{3,40,20},{5,120,20}})]]];
Rasterize[taskSet,ImageSize->500,RasterSize->1000] (*Presentation Aid*)

Total@taskSet[All,#]&/@{"Min","Max","Mode"}

UnitConvert[(Quantity[485, "min", minutes, "Minutes"]), "Hours"]//N

Applying Distributions

distTasks=taskSet[All,PERTDistribution[{#Min,#Max},#Mode]&];
Rasterize[distTasks,ImageSize->1000,RasterSize->2000] (*Presentation Aid*)

Simulations

simulations=Total/@Transpose[RandomVariate[#,500000]&/@Values@Normal@distTasks];

Histogram[simulations,60,PlotLabel->"Average Project Length:\n"<>ToString[Mean@simulations]<>" Minutes\n About 3 hours",ImageSize->800]

Questions?