Chi squared goodness of fit for a geometric distribution

5k views Asked by At

As an assignment I had to develop and algorithm and generate a samples for a given geometric distribution with PMF

enter image description here

Using the inverse transform method, I came up with the following expression for generating the values:

enter image description here

Where U represents a value, or n values depending on the size of the sample, drawn from a Unif(0,1) distribution and p is 0.3 as stated in the PMF above.

I have the algorithm, the implementation in R and I already generated QQ Plots to visually assess the adjustment of the empirical values to the theoretical ones (generated with R), i.e., if the generated sample follows indeed the geometric distribution.

Now I wanted to submit the generated sample to a goodness of fit test, namely the Chi-square, yet I'm having trouble doing this in R.

3

There are 3 answers

1
jbowman On BEST ANSWER

Let us assume you've got your randomly-generated variates in a vector x. You can do the following:

x <- rgeom(1000,0.2)

x_tbl <- table(x)
x_val <- as.numeric(names(x_tbl))
x_df <- data.frame(count=as.numeric(x_tbl), value=x_val)

# Expand to fill in "gaps" in the values caused by 0 counts
all_x_val <- data.frame(value = 0:max(x_val))
x_df <- merge(all_x_val, x_df, by="value", all.x=TRUE)
x_df$count[is.na(x_df$count)] <- 0

# Get theoretical probabilities 
x_df$eprob <- dgeom(x_df$val, 0.2)

# Chi-square test: once with asymptotic dist'n, 
# once with bootstrap evaluation of chi-sq test statistic
chisq.test(x=x_df$count, p=x_df$eprob, rescale.p=TRUE)
chisq.test(x=x_df$count, p=x_df$eprob, rescale.p=TRUE, 
   simulate.p.value=TRUE, B=10000)
0
Glen_b On

[I think this was moved a little hastily, in spite of your response to whuber's question, since I think before solving the 'how do I write this algorithm in R' problem, it's probably more important to deal with the 'what you're doing is not the best approach to your problem' issue (which certainly belongs where you posted it). Since it's here, I will deal with the 'doing it in R' aspect, but I would urge to you go back an ask about the second question (as a new post).]

Firstly the chi-square test is a little different depending on whether you test

H0: the data come from a geometric distribution with parameter p

or

H0: the data come from a geometric distribution with parameter 0.3

If you want the second, it's quite straightforward. First, with the geometric, if you want to use the chi-square approximation to the distribution of the test statistic, you will need to group adjacent cells in the tail. The 'usual' rule - much too conservative - suggests that you need an expected count in every bin of at least 5.

I'll assume you have a nice large sample size. In that case, you'll have many bins with substantial expected counts and you don't need to worry so much about keeping it so high, but you will still need to choose how you will bin the tail (whether you just choose a single cut-off above which all values are grouped, for example).

I'll proceed as if n were say 1000 (though if you're testing your geometric random number generation, that's pretty low).

First, compute your expected counts:

 dgeom(0:20,.3)*1000
 [1] 300.0000000 210.0000000 147.0000000 102.9000000  72.0300000  50.4210000
 [7]  35.2947000  24.7062900  17.2944030  12.1060821   8.4742575   5.9319802
[13]   4.1523862   2.9066703   2.0346692   1.4242685   0.9969879   0.6978915
[19]   0.4885241   0.3419669   0.2393768

Warning, dgeom and friends goes from x=0, not x=1; while you can shift the inputs and outputs to the R functions, it's much easier if you subtract 1 from all your geometric values and test that. I will proceed as if your sample has had 1 subtracted so that it goes from 0.

I'll cut that off at the 15th term (x=14), and group 15+ into its own group (a single group in this case). If you wanted to follow the 'greater than five' rule of thumb, you'd cut it off after the 12th term (x=11). In some cases (such as smaller p), you might want to split the tail across several bins rather than one.

> expec <- dgeom(0:14,.3)*1000
> expec <- c(expec, 1000-sum(expec))
> expec
 [1] 300.000000 210.000000 147.000000 102.900000  72.030000  50.421000
 [7]  35.294700  24.706290  17.294403  12.106082   8.474257   5.931980
[13]   4.152386   2.906670   2.034669   4.747562

The last cell is the "15+" category. We also need the probabilities.

Now we don't yet have a sample; I'll just generate one:

y <- rgeom(1000,0.3)

but now we want a table of observed counts:

 (x <- table(factor(y,levels=0:14),exclude=NULL))

   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14 <NA> 
 292  203  150   96   79   59   47   25   16   10    6    7    0    2    5    3 

Now you could compute the chi-square directly and then calculate the p-value:

> (chisqstat <- sum((x-expec)^2/expec))
[1] 17.76835
(pval <- pchisq(chisqstat,15,lower.tail=FALSE))
[1] 0.2750401

but you can also get R to do it:

> chisq.test(x,p=expec/1000)

        Chi-squared test for given probabilities

data:  x 
X-squared = 17.7683, df = 15, p-value = 0.275

Warning message:
In chisq.test(x, p = expec/1000) :
  Chi-squared approximation may be incorrect

Now the case for unspecified p is similar, but (to my knowledge) you can no longer get chisq.test to do it directly, you have to do it the first way, but you have to estimate the parameter from the data (by maximum likelihood or minimum chi-square), and then test as above but you have one fewer degree of freedom for estimating the parameter.

See the example of doing a chi-square for a Poisson with estimated parameter here; the geometric follows the much same approach as above, with the adjustments as at the link (dealing with the unknown parameter, including the loss of 1 degree of freedom).

0
IRTFM On

There's a "goodfit" function described as "Goodness-of-fit Tests for Discrete Data" in package "vcd".

G.fit <- goodfit(x, type = "nbinomial", par = list(size = 1))

I was going to use the code you had posted in an earlier question, but it now appears that you have deleted that code. I find that offensive. Are you using this forum to gather homework answers and then defacing it to remove the evidence? (Deleted questions can still be seen by those of us with sufficient rep, and the interface prevents deletion of question with upvoted answers so you should not be able to delete this one.)

Generate a QQ Plot for testing a geometrically distributed sample

--- question---

I have a sample of n elements generated in R with

sim.geometric <- function(nvals)
{
    p <- 0.3
    u <- runif(nvals)
    ceiling(log(u)/log(1-p))
}

for which i want to test its distribution, specifically if it indeed follows a geometric distribution. I want to generate a QQ PLot but have no idea how to.

--------reposted answer----------

A QQ-plot should be a straight line when compared to a "true" sample drawn from a geometric distribution with the same probability parameter. One gives two vectors to the functions which essentially compares their inverse ECDF's at each quantile. (Your attempt is not particularly successful:)

sim.res <- sim.geometric(100) sim.rgeom <- rgeom(100, 0.3) qqplot(sim.res, sim.rgeom)

Here I follow the lead of the authors of qqplot's help page (which results in flipping that upper curve around the line of identity):

png("QQ.png")
qqplot(qgeom(ppoints(100),prob=0.3), sim.res,
       main = expression("Q-Q plot for" ~~ {G}[n == 100]))
dev.off()

---image not included---

You can add a "line of good fit" by plotting a line through through the 25th and 75th percentile points for each distribution. (I added a jittering feature to this to get a better idea where the "probability mass" was located:)

sim.res <- sim.geometric(500)
qqplot(jitter(qgeom(ppoints(500),prob=0.3)), jitter(sim.res),
       main = expression("Q-Q plot for" ~~ {G}[n == 100]), ylim=c(0,max( qgeom(ppoints(500),prob=0.3),sim.res )),
xlim=c(0,max( qgeom(ppoints(500),prob=0.3),sim.res )))
 qqline(sim.res, distribution = function(p) qgeom(p, 0.3),
       prob = c(0.25, 0.75), col = "red")