funnelPlot | R Documentation |
Funnel plots for proportional data with confidence interval based on sample size. Introduced by Stephen Few, 2013
funnelPlot(
x,
n,
labels = NULL,
method = "classic",
add = FALSE,
xlim = range(n, finite = TRUE),
ylim = range(x/n * 100, finite = TRUE),
las = 1,
xlab = "Sample size n",
ylab = "Success rate [%]",
main = "Funnel plot for Proportions",
a3 = NULL,
a2 = NULL,
am = NULL,
ap = NULL,
at = NULL,
al = NULL,
...
)
x |
Numeric vector with number of successes (cases). |
n |
Numeric vector with number of trials (population). |
labels |
Labels for points. DEFAULT: NULL |
method |
Method to calculate Confidence interval, see "note" below. Can also be "wilson". DEFAULT: "classic" |
add |
Add to existing plot instead of drawing new plot? DEFAULT: FALSE |
xlim |
Graphical parameters, see |
ylim |
y limit in [0:1] DEFAULT: range(x/n*100, finite=TRUE) |
las |
DEFAULT: 1 |
xlab |
DEFAULT: "Sample size n" |
ylab |
DEFAULT: "Success rate [%]" |
main |
DEFAULT: "Funnel plot for Proportions" |
a3 |
List with arguments for CI lines at 3*sd (eg: col, lty, lwd, lend, etc.). Overwrites defaults that are defined within the function (if contentually possible). DEFAULT: NULL |
a2 |
Arguments for line of 2 sd. DEFAULT: NULL |
am |
Arguments for mean line. DEFAULT: NULL |
ap |
Arguments for the data points (cex, etc.). DEFAULT: NULL |
at |
Arguments for text (labels of each point). DEFAULT: NULL |
al |
Arguments for |
... |
further arguments passed to plot only! |
Nothing - the function just plots
Salesman A (new to the job) has had 3 customers and sold 1 car. So his success rate is 0.33. Salesman B sold 1372 customers 632 cars, thus having a success rate of 0.46 Promoting B solely because of the higher rate fails to take experience and opportunity (n) into account! This dilemma is what the funnel plot with the confidence interval (ci) solves. See Stephen Few and Katherine Rowel's PDF for details on the interpretation.
the default for lty is not taken from par("lty"). This would yield "solid".
Overwriting lty for one of the three line categories then produces
eg c("2", "solid", "solid"), which cannot be processed by legend.
Wilson's Method: algebraic approximation to the binomial distribution, very accurate, even for very small numbers.
https://webarchive.nationalarchives.gov.uk/20170106081156/http://www.apho.org.uk/resource/item.aspx?RID=39445 see "contains".
classic = Stephen Few's Method = the way I knew it: sqrt( mu*(1-mu) / n )
http://www.jerrydallal.com/LHSP/psd.htm
https://commons.wikimedia.org/wiki/File:ComparisonConfidenceIntervals.png
The apho Wilson method first yielded wrong upper limits in my translation (it needs 0:1 instead of %). Thus I added the wikipedia formula:
https://de.wikipedia.org/wiki/Konfidenzintervall_einer_unbekannten_Wahrscheinlichkeit#Wilson-Intervall
https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval
Which other methods should I include? (That's not the hard part anymore)
Berry Boessenkool, berry-b@gmx.de, Oct 2013
https://www.perceptualedge.com/articles/visual_business_intelligence/variation_and_its_discontents.pdf
Excellent explanation of bayesian take on proportions: http://varianceexplained.org/r/empirical_bayes_baseball/
# Taken directly from Stephen Few's PDF:
funnel <- read.table(header=TRUE, text="
Name SampleSize Incidents
Tony 2 2
Mike 400 224
Jan 100 54
Bob 1000 505
Sheila 2 1
Jeff 10 5
Sandy 500 236
Mitch 200 92
Mary 10 3
John 2 0")
str(funnel)
X <- funnel$Incidents
N <- funnel$SampleSize
barplot(X/N, names=funnel$Name, main="success rate")
# not showing n!
funnelPlot(X,N)
# arguments for subfunctions as text may be given this way:
funnelPlot(x=X, n=N, labels=funnel$Name, at=list(cex=0.7, col="red"))
# Labeling many points is not very clear...
funnelPlot(X,N)
sel <- c(1,4,10) # selection
text(N[sel], (X/N*100)[sel], funnel$Name[sel], cex=0.7)
# You could also pass a vector with partly empty strings to funnelPlot
funnelPlot(x=X, n=N, labels=replace(funnel$Name, c(2,3,5:9), ""), at=list(adj=0.5))
# Even though Jan is more successfull than Mary in succes rate terms, both are
# easily within random variation. Mary may just have had a bad start.
# That Mike is doing better than average is not random, but (with 95% confidence)
# actually due to him being a very good seller.
# one more interesting option:
funnelPlot(X,N, a3=list(lty=2))
funnelPlot(X,N, a3=list(col=2, lwd=5))
# changing round line ends in legend _and_ plot is easiest with
par(lend=1)
funnelPlot(X,N, a3=list(col=2, lwd=5))
# The Wilson method yields slighty different (supposedly better) limits for small n:
funnelPlot(X,N, method="classic", al=list(title="Standard Method"))
funnelPlot(X,N, add=TRUE, method="wilson", a3=list(lty=2, col="red"),
a2=list(lty=2, col="blue"), al=list(x="bottomright", title="Wilson Method"))
# Both Wilson method implementations yield the same result:
funnelPlot(X,N, method="wilson")
funnelPlot(X,N, add=TRUE, method="wilsonapho",
a3=list(lty=2, col="red"), a2=list(lty=2, col="blue"))
# Note on nl used in the function, the n values for the ci lines:
plot( seq( 10 , 300 , len=50), rep( 1, 50) )
points(10^seq(log10(10), log10(300), len=50), rep(0.8, 50) )
abline(v=10)
# CI values change rapidly at small n, then later slowly.
# more x-resolution is needed in the first region, so it gets more of the points
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.