I am attempting to produce a KDE based PDF estimate on a series of distributions that may not be normally distributed.
I like the way ggplot's stat_density in R seems to recognize every incremental bump in frequency, but cannot replicate this via Python's scipy-stats-gaussian_kde method, which seems to oversmooth.
I have set up my R code as follows:
ggplot(test, aes(x=Val, color = as.factor(Class), group=as.factor(Class))) +
stat_density(geom='line',kernel='gaussian',bw='nrd0'
#nrd0='Silverman'
,size=1,position='identity')
And my python code is:
kde = stats.gaussian_kde(data.ravel())
kde.set_bandwidth(bw_method='silverman')
Stats docs show here that nrd0 is the silverman method for bw adjust.
Based on the code above, I am using the same kernals (gaussian) and bandwidth methods (Silverman).
Can anyone explain why the results are so different?
There seems to be disagreement about what Silverman's Rule is.
The scipy docs say that Silverman's rule is implemented as:
Where
d
is the number of dimensions (1, in your case) andneff
is the effective sample size (number of points, assuming no weights). So the scipy bandwidth is(n * 3 / 4) ^ (-1 / 5)
(times the standard deviation, computed in a different method).By contrast, R's
stats
package docs describe Silverman's method as "0.9 times the minimum of the standard deviation and the interquartile range divided by 1.34 times the sample size to the negative one-fifth power", which can also be verified in R code, typingbw.nrd0
in the console gives:Wikipedia, on the other hand, gives "Silverman's Rule of Thumb" as one of many possible names for the estimator:
The wikipedia version is equivalent to the scipy version.
All three sources cite the same reference: Silverman, B.W. (1986). Density Estimation for Statistics and Data Analysis. London: Chapman & Hall/CRC. p. 48. ISBN 978-0-412-24620-3. Wikipedia and R specifically cite page 48, whereas scipy's docs do not mention a page number. (I have submitted an edit to Wikipedia to update its page reference to p.45, see below.)
Addendum
I found a PDF of the Silverman reference.
On page 45, equation 3.28 is what is used in the Wikipedia article:
(4 / 3) ^ (1 / 5) * sigma * n ^ (-1 / 5) ~= 1.06 * sigma * n ^ (-1 / 5)
. Scipy uses the same method, rewriting(3 / 4) ^ (-1 / 5)
as the equivalent(4 / 3) ^ (1 / 5)
. Silverman describes this method as:The scipy docs reference this weakness, stating:
The Silverman article continues to motivate the method used by R and Stata. On page 48, we get the equation 3.31:
Silverman describes this method as:
So, it seems Wikipedia and Scipy use a simple estimator proposed by Silverman. R and Stata use a more refined version.