Blog

Introducing the Kernelheaping Package

In this blog article I'd like to introduce the univariate kernel density estimation for heaped (i.e. rounded or interval censored) data with the Kernelheaping package.

It is not unusual to have interval censored data such as in income surveys due to anonymisation or simplification issues. However, a simple task like plotting a density may fail completely for rounded or interval censored data. When using class centers as input, the density estimate might get bumpy or spiky around the center points. This problem gets even worse for larger sample sizes with decreasing bandwidth. One might try to manually increase the bandwidth until one obtains a sufficiently smooth estimate. However, this will result in oversmoothing as we will see in our example. The Kernelheaping package, available on CRAN, delivers an algorithm to obtain nonparametric density estimates for interval censored data.

Example: Kernel density estimation for interval data without correction

In the following chunk, I'll simulate 5000 observations from a log-normal distribution. Then I plot the histogram together with a conventional kernel density estimate.

library("ggplot2")
library("dplyr")
set.seed(0)

dat <- data.frame(x = rlnorm(5000, meanlog = 7.5, sdlog = 0.5))

ggplot(dat, aes(x, y = ..density..)) +
  geom_histogram(position = "identity", color = "black", fill = "white") +
  geom_density(fill = "blue", alpha = 0.7, linetype = 0) +
  ylim(c(0, 0.00055)) +
  xlim(c(0, 10000))

Kernelheaping Plot 1

Now let's split our data into 14 classes imitating a typical income survey.

classes <- c(0, 500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000, 8000,
             10000, 15000, Inf)
dat$xclass <- cut(dat$x, breaks = classes)

If I now use the class centers as input, the result is a very unrealistic, spiky density.

classCenters <- (classes[-1] - classes[-length(classes)]) /
  2 + classes[-length(classes)]
classCenters[length(classCenters)] <- 2 * classCenters[length(classCenters) - 1]
levels(dat$xclass) <- classCenters
dat$xclassCenter <- as.numeric(as.character(dat$xclass))

ggplot(dat, aes(xclassCenter, y = ..density..)) +
  geom_histogram(breaks = classes, color = "black", fill = "white") +
  geom_density(fill = "blue", alpha = 0.7, linetype = 0)

Kernelheaping Plot 2

I've got the option to adjust the density by manipulating the adjusting parameter. But getting a nice and smooth density shape requires manipulation to such an extent that we end up with serious oversmoothing.

ggplot(dat, aes(xclassCenter, y = ..density..)) +
  geom_histogram(breaks = classes, color = "black", fill = "white") +
  geom_density(adjust = 2.5, fill = "blue", alpha = 0.7, linetype = 0) +
  ylim(c(0, 0.00055)) +
  xlim(c(0, 10000))

Kernelheaping Plot 3

Kernel density estimation for interval data with the Kernelheaping package

Now, we install and load the Kernelheaping pack age. Its dclass function implements an iterative SEM (Stochastic Expectation Maximization) algorithm.

install.packages("Kernelheaping")
library("Kernelheaping")

It can be called with any bandwidth selector available to the density function in the stats package and also provides optional boundary correction for positive only data.

densityEst <- dclass(xclass = dat$xclass, classes = classes, burnin = 50,
                     samples = 100, evalpoints = 1000)
classes <- data.frame(xclass = densityEst$xclass)
estimates <- data.frame(Mestimates = densityEst$Mestimates, gridx = densityEst$gridx)


ggplot() +
  geom_histogram(data = classes, aes(xclass, y = ..density..), 
                 breaks = densityEst$classes, color = "black", fill = "white") +
  geom_area(data = estimates, aes(gridx, Mestimates), 
            fill = "blue", alpha = 0.7, size = 1) +
  ylim(c(0, 0.00055)) +
  xlim(c(0, 10000)) 

Kernelheaping Plot 4

The resulting density estimate is smooth and very close to the estimate on the original unclassed data. The package is also able to handle the case of survey participants rounding values on their own, each with a different level of coarseness. Please check out the dheaping function with given examples.

Soon there will be a second part to this article, where I'll show how to compute bivariate densities given area-level data with the Kernelheaping package.

Further parts of the article series:

by Marcus Groß

Introducing the Kernel Heaping Package III

by Marcus Groß

Introducing the Kernelheaping Package II