The bootstrap (alone) will not help you identify the mean in the presence of censoring, and will not be much use with the median given a dataset like the one you supplied; you may be able to get some kind of lower bound on the median in this case with a bootstrap, but you can do that nonparametrically without the need for bootstrapping.
To estimate the mean would require some kind of parametric assumption*.
If you observe fewer than half the times to completion then the median would have a similar problem.
This is a standard kind of problem in survival analysis; once a suitable parametric distributional model is chosen, estimation is relatively easy with canned routines. I've done this in R; it provides a number of distributions by default but it's possible to add further distributions.
First we create a dataset with time under observation and a column to denote the censoring status (first few rows shown below). Here I fit an intercept-only Weibull model to the times
subject time completed
1 Aaron 34 1
2 Betty 50 0
3 Cecil 50 0
4 Dave 18 1
5 Elias 47 1
6 Fredric 39 1
(weib.fit <- survreg(Surv.puz~1,puzzle,dist="weibull"))
Call:
survreg(formula = Surv.puz ~ 1, data = puzzle, dist = "weibull")
Coefficients:
(Intercept)
3.879441
Scale= 0.3010924
Loglik(model)= -40.8 Loglik(intercept only)= -40.8
n= 14
Here's the Kaplan-Meier survival curve (nonparametric), along with 95% CI, and the fit from the above model:

The sample median is 39.5, the fitted median is 43.34, the fitted mean is 43.43. You can see from the nonparametric CI that we can get a lower bound on the median without a parametric assumption (where the horizontal green dots hit the vertical black dashes) but there's not a large enough proportion of complete times to get an upper bound on the median. The parametric fit can provide CI-type bounds on both the mean and median (though I haven't given any here).
You could try a variety of parametric assumptions if you don't want to be too reliant on any one assumption, but you're still reliant on whatever set of distributions you consider -- there's no way to avoid some assumption about the upper tail beyond what you observed.
* well it might be possible to proceed with some assumption that sufficiently regularizes the problem without being fully parametric (obtaining some set of bounds, presumably), though I am not sure right now what form that assumption might take.
Here's the code that I used. First read in and set up data:
puzzle <- read.table(stdin(),colClasses=c("character","numeric"),
na.strings="X",sep=":",col.names=c("subject","time"))
Aaron: 34
Betty: X
Cecil: X
Dave: 18
Elias: 47
Fredric: 39
Greta: 37
Howard: X
Ingrid: X
Joy: 29
Kristine: 34
Lou: 32
Margret: X
Nigel: 40
puzzle$completed <- as.numeric(!is.na(puzzle$time))
puzzle$time <- with(puzzle,ifelse(is.na(time),50,time))
Then load the survival library and create the required survival object,
fit the Weibull and plot the curves etc
require(survival)
(Surv.puz <- with(puzzle,Surv(time,event=completed)))
(weib.fit <- survreg(Surv.puz~1,puzzle,dist="weibull"))
plot(survfit(Surv.puz~1),xlim=c(0,100))
lambda <- exp(weib.fit$coefficients)
k <- 1/weib.fit$scale
f <- function(x) pweibull(x,k,lambda,lower.tail=FALSE)
curve(f,0,100,col="blue",add=TRUE)
weib.mean <- lambda*gamma(1+1/k)
weib.median <- lambda*log(2)^(1/k)
puz.median <- median(puzzle$time)
abline(h=c(0,1),col="darkred",lty=3)
segments(0,.5,max(weib.median,puz.median),.5,col="green4",lty=2)
segments(weib.median,0,weib.median,.5,col="green4",lty=2)
segments(puz.median,0,puz.median,.5,col="green4",lty=2)
arrows(weib.mean,-.03,weib.mean,0,length=0.05,col="green4")
c(data.median=puz.median,weib.median=weib.median,weib.mean=weib.mean)
X
. Just replaxeX
with a very large number (if you are doing this inR
I suggestInf
) and compute the median. Depending on the number ofX
you might also consider a trimmed mean. $\endgroup$