5
$\begingroup$

My data consists of 3 variables, one is a numerical variable of the number of flower visits that I have counted on certain locations and on certain shrub species. My other 2 variables are categorical variables: Category ID (location), which can be either "RA", "RN" or "UN" and Species, which can be either "Common hawthorn", "Blackberry" or "Rose". See below for the data and ggplot of the data:

> visits_df
# A tibble: 74 × 3
   Category_ID Species         Total_visits
   <fct>       <fct>                  <dbl>
 1 UN          Common hawthorn           22
 2 UN          Common hawthorn           42
 3 UN          Common hawthorn            3
 4 UN          Common hawthorn           13
 5 UN          Common hawthorn           76
 6 UN          Common hawthorn           95
 7 UN          Common hawthorn           53
 8 RN          Common hawthorn           50
 9 RN          Common hawthorn           18
10 UN          Common hawthorn            6
11 UN          Common hawthorn           16
12 RA          Common hawthorn           48
13 RA          Common hawthorn           63
14 RA          Common hawthorn           35
15 RA          Common hawthorn           40
16 RN          Common hawthorn           49
17 RA          Common hawthorn           25
18 RA          Common hawthorn           73
19 RN          Common hawthorn           107
20 UN          Common hawthorn           62
21 UN          Common hawthorn           60
22 RN          Common hawthorn           66
23 RN          Common hawthorn           29
24 RN          Common hawthorn           33
25 RN          Common hawthorn           79
26 UN          Common hawthorn           19
27 UN          Common hawthorn           16
28 UN          Common hawthorn           35
29 UN          Common hawthorn           43
30 RN          Common hawthorn           30
31 RN          Common hawthorn           27
32 UN          Common hawthorn           94
33 UN          Common hawthorn           54
34 RN          Blackberry                126
35 RN          Blackberry                145
36 RN          Blackberry                145
37 UN          Blackberry                93
38 UN          Blackberry                173
39 RA          Rose                      17
40 RA          Rose                      26
41 RA          Rose                      44
42 RA          Rose                      9
43 RA          Rose                      18
44 UN          Blackberry                144
45 RN          Blackberry                129
46 RN          Blackberry                168
47 RN          Blackberry                334
48 RN          Blackberry                342
49 RN          Blackberry                306
50 RN          Blackberry                283
51 UN          Blackberry                308
52 RN          Blackberry                266
53 RN          Blackberry                244
54 RA          Rose                      44
55 RA          Rose                      36
56 RA          Rose                      62
57 RA          Rose                      85
58 UN          Blackberry                106
59 RN          Blackberry                123
60 RN          Blackberry                153
61 RN          Blackberry                198
62 UN          Blackberry                181
63 RA          Rose                      58
64 UN          Blackberry                64
65 RN          Blackberry                150
66 RN          Blackberry                85
67 RN          Blackberry                114
68 RN          Blackberry                137
69 UN          Blackberry                84
70 RN          Blackberry                121
71 RN          Blackberry                148
72 RN          Blackberry                104
73 RN          Blackberry                117
74 UN          Blackberry                93

enter image description here

I tested if my data to see if its fits a Poisson distribution, as it is count data, using the following code (I found this code online):

obs_freq <- table(visits_df$Total_visits)
lambda <- mean(visits_df$Total_visits)
exp_freq <- dpois(as.numeric(names(obs_freq)), lambda) * length(visits_df$Total_visits)

chisq.test(obs_freq, p = exp_freq, rescale.p = TRUE) 
# not a poission distribution: p-value = 2.2e-16

Does anybody know how to proceed? As I would like to test if there are differences between the boxplots. Can I still use a Poisson regression even though my data does not seem to follow a Poisson distribution?

Comparing the mean and variance of the number of flower visits gave me these results:

> mean_data <- mean(visits_df$Total_visits)
> var_data <- var(visits_df$Total_visits)
> cat("Mean:", mean_data, "\nVariance:", var_data)
Mean: 95.45946 
Variance: 6703.128
$\endgroup$
5
  • 4
    $\begingroup$ Some of the detail in your SO question should be copied here. Even better, I get the impression that your entire dataset could be copied here so that people can make concrete suggestions. On top of that, the question here reminds me of the X-Y problem. xyproblem.info The fundamental question here is , it seems, comparing statistically the number of flower visits given 3 different locations and 3 different species. That being so the answer is which model(s) might work well, not why a Friedman test can't be applied and even less how to use a Wilcoxon test (which isn't relevant at all). $\endgroup$
    – Nick Cox
    Commented Jul 18 at 15:01
  • 3
    $\begingroup$ In short, the strategy is not to seek a test but to apply a model, which allows estimates as well as the decoration of significance results. From what you have said, my inclination would be to start with a Poisson regression. $\endgroup$
    – Nick Cox
    Commented Jul 18 at 15:01
  • 2
    $\begingroup$ Welcome to CV! Please edit your question using the input from the comments. Questions should be self-contained. If your question on StackOverflow is ever deleted, future readers can no longer understand the context. $\endgroup$ Commented Jul 18 at 15:53
  • 5
    $\begingroup$ The Poisson model assumption is that the data have Poisson distributions at the mean values associated with the predictor variables. You shouldn't expect the overall counts to have a Poisson distribution (which is what I think you evaluated) if there are differences in mean count values as a function of predictor variables. $\endgroup$
    – EdM
    Commented Jul 19 at 15:24
  • 1
    $\begingroup$ Are you computing the marginal mean and variance of the counts (across groups rather than conditionally, within groups)? That wouldn't be Poisson, and you'd expect higher variance than mean because it has the additional variance term due to variation in group means $\endgroup$
    – Glen_b
    Commented Jul 20 at 4:32

3 Answers 3

3
$\begingroup$

Here's a rough analysis. Using a Poisson model doesn't depend really on anything being Poisson distributed. The main idea is just $y = \exp(Xb)$. I stopped short of wondering about interaction terms, an exercise for braver souls.

Broadly speaking, visits are distinctly higher for blackberry. Otherwise being any other species or being a particular hedgerow category isn't a big deal.

I used Stata. There will be ways of doing this in R.

The box plots you showed are better than nothing, but their focus on median and quartiles is not relevant to modelling means, and the details of data points are not very clear. Further, it seems to me that logarithmic scale is natural here.

Biology: Common hawthorn appears to be a species Crataegus monogyna. Rose is a genus Rosa. Blackberry appears to be a confused category, at least several species. I didn't know most of that before I looked it up.

I would have decoded the categories on the graph if I knew what they meant.

enter image description here

Stata code:

* Example generated by -dataex-. For more info, type help dataex
clear
input str2 Category str15 Species int visits long(category species)
"RA" "Common hawthorn"  25 1 2
"RA" "Common hawthorn"  35 1 2
"RA" "Common hawthorn"  40 1 2
"RA" "Common hawthorn"  48 1 2
"RA" "Common hawthorn"  63 1 2
"RA" "Common hawthorn"  73 1 2
"RA" "Rose"              9 1 3
"RA" "Rose"             17 1 3
"RA" "Rose"             18 1 3
"RA" "Rose"             26 1 3
"RA" "Rose"             36 1 3
"RA" "Rose"             44 1 3
"RA" "Rose"             44 1 3
"RA" "Rose"             58 1 3
"RA" "Rose"             62 1 3
"RA" "Rose"             85 1 3
"RN" "Blackberry"       85 2 1
"RN" "Blackberry"      104 2 1
"RN" "Blackberry"      114 2 1
"RN" "Blackberry"      117 2 1
"RN" "Blackberry"      121 2 1
"RN" "Blackberry"      123 2 1
"RN" "Blackberry"      126 2 1
"RN" "Blackberry"      129 2 1
"RN" "Blackberry"      137 2 1
"RN" "Blackberry"      145 2 1
"RN" "Blackberry"      145 2 1
"RN" "Blackberry"      148 2 1
"RN" "Blackberry"      150 2 1
"RN" "Blackberry"      153 2 1
"RN" "Blackberry"      168 2 1
"RN" "Blackberry"      198 2 1
"RN" "Blackberry"      244 2 1
"RN" "Blackberry"      266 2 1
"RN" "Blackberry"      283 2 1
"RN" "Blackberry"      306 2 1
"RN" "Blackberry"      334 2 1
"RN" "Blackberry"      342 2 1
"RN" "Common hawthorn"  18 2 2
"RN" "Common hawthorn"  27 2 2
"RN" "Common hawthorn"  29 2 2
"RN" "Common hawthorn"  30 2 2
"RN" "Common hawthorn"  33 2 2
"RN" "Common hawthorn"  49 2 2
"RN" "Common hawthorn"  50 2 2
"RN" "Common hawthorn"  66 2 2
"RN" "Common hawthorn"  79 2 2
"RN" "Common hawthorn" 107 2 2
"UN" "Blackberry"       64 3 1
"UN" "Blackberry"       84 3 1
"UN" "Blackberry"       93 3 1
"UN" "Blackberry"       93 3 1
"UN" "Blackberry"      106 3 1
"UN" "Blackberry"      144 3 1
"UN" "Blackberry"      173 3 1
"UN" "Blackberry"      181 3 1
"UN" "Blackberry"      308 3 1
"UN" "Common hawthorn"   3 3 2
"UN" "Common hawthorn"   6 3 2
"UN" "Common hawthorn"  13 3 2
"UN" "Common hawthorn"  16 3 2
"UN" "Common hawthorn"  16 3 2
"UN" "Common hawthorn"  19 3 2
"UN" "Common hawthorn"  22 3 2
"UN" "Common hawthorn"  35 3 2
"UN" "Common hawthorn"  42 3 2
"UN" "Common hawthorn"  43 3 2
"UN" "Common hawthorn"  53 3 2
"UN" "Common hawthorn"  54 3 2
"UN" "Common hawthorn"  60 3 2
"UN" "Common hawthorn"  62 3 2
"UN" "Common hawthorn"  76 3 2
"UN" "Common hawthorn"  94 3 2
"UN" "Common hawthorn"  95 3 2
end
label values category category
label def category 1 "RA", modify
label def category 2 "RN", modify
label def category 3 "UN", modify
label values species species
label def species 1 "Blackberry", modify
label def species 2 "Common hawthorn", modify
label def species 3 "Rose", modify

glm visits i.category ib3.species, link(log) family(poisson) vce(robust)

predict fitted 

sort category species visits

gen axis = 1 in 1
replace axis = axis[_n-1] + 1 + (species != species[_n-1]) + 2 * (category != category[_n-1]) in 2/L

scatter visits fitted axis , ms(O +) ysc(log) xla(3.5 `" "Common""hawthorn""' 12.5 "Rose" 31.5 "Blackberry" 48.5 `""Common""hawthorn""' 61 "Blackberry" 75 `""Common" "hawthorn""', nogrid noticks) legend(order(1 "observed" 2 "fitted") row(1) pos(12)) yla(300 100 30 10 3) ytitle(Flower visits) xtitle("") xaxis(1 2) xla(9.5 "RA" 36.5 "RN" 70.5 "UN", axis(2) noticks) xtitle("", axis(2)) xline(19 55)

Results of Poisson regression:

. glm visits i.category ib3.species, link(log) family(poisson) vce(robust)

Iteration 0:  Log pseudolikelihood = -1054.0538  
Iteration 1:  Log pseudolikelihood = -1028.4796  
Iteration 2:  Log pseudolikelihood = -1028.4258  
Iteration 3:  Log pseudolikelihood = -1028.4258  

Generalized linear models                         Number of obs   =         74
Optimization     : ML                             Residual df     =         69
                                                  Scale parameter =          1
Deviance         =  1611.922089                   (1/df) Deviance =   23.36119
Pearson          =  1695.139285                   (1/df) Pearson  =   24.56724

Variance function: V(u) = u                       [Poisson]
Link function    : g(u) = ln(u)                   [Log]

                                                  AIC             =   27.93043
Log pseudolikelihood = -1028.425837               BIC             =   1314.942

----------------------------------------------------------------------------------
                 |               Robust
          visits | Coefficient  std. err.      z    P>|z|     [95% conf. interval]
-----------------+----------------------------------------------------------------
        category |
             RN  |   .0750975    .204343     0.37   0.713    -.3254073    .4756024
             UN  |  -.1584553   .2011745    -0.79   0.431      -.55275    .2358395
                 |
         species |
     Blackberry  |   1.420246    .275455     5.16   0.000     .8803644    1.960128
Common hawthorn  |   .1708384   .2288833     0.75   0.455    -.2777645    .6194414
                 |
           _cons |   3.686376   .1793354    20.56   0.000     3.334885    4.037867
----------------------------------------------------------------------------------
$\endgroup$
4
  • $\begingroup$ I fear that incorrect predictions (other than the mean) will arise from the lack of fit, and incorrect standard errors, p-values, and especially confidence limits. $\endgroup$ Commented Jul 20 at 11:52
  • 1
    $\begingroup$ That's as may be. The real problem is that neither the design nor the sample size allows much to be inferred here of scientific interest beyond some gross differences. Over-elaborate analysis of inadequate data is problematic too. $\endgroup$
    – Nick Cox
    Commented Jul 20 at 12:18
  • $\begingroup$ So if I understand it correctly, I run into the problem of overfitting a model since I try to explain a lot of relationships from just 74 observations? But that would still be the case if I would use a negative binomial model, right? So even though the negative binomial model would probably be the best fit, I would still have to be careful with drawing conclusions on the relationships since there are simply too little datapoints to properly fit the model. Would that the conclusion of the analysis? $\endgroup$
    – Geertje
    Commented Jul 22 at 10:58
  • $\begingroup$ A researcher should always be careful. My interpretation is that a more elaborate negative binomial model points to the same scientific indications and conclusions as my rougher analysis. $\endgroup$
    – Nick Cox
    Commented Jul 22 at 11:56
2
$\begingroup$

First, as @NickCox points out in another answer, a main idea in a Poisson count model is that you are modeling the log of the mean counts as a function of predictors. You can always try such a model.

Second, to trust the standard errors of the regression coefficients, you do have to meet the Poisson model assumption well enough. The standard errors are based on the mean=variance assumption of a Poisson distribution around the model estimates. As noted in comments, that isn't for the overall distribution of counts, just for the distribution of counts around the mean values estimated by the model.

Third, even if the Poisson assumption doesn't hold around the model estimates, there are related alternatives.

To illustrate with your data, in R you can use an interaction between Species and Category_ID to get estimates of all the combinations for which you have data.

poiInteract <- glm(Total_visits ~ Species*Category_ID,
                        data=visits_df, family=poisson)

If you call summary(poiInteract) you will see that there are "NA" values for interactions that lack observations. The problem is that if you do even simple quality control with plot(poiInteract) you will find that the model doesn't work very well (not shown here).

In this case, the Poisson assumption doesn't hold very well even around the modeled mean predictions. One way to show that is to use a "quasi-Poisson" model; that gives the same regression coefficients as the Poisson model but estimates a dispersion factor that indicates how far beyond the mean=variance assumption you need to go to explain the data. The dispersion factor is identically 1 for a pure Poisson model.

qpInteract <- glm(Total_visits ~ Species*Category_ID,
                   data=visits_df, family=quasipoisson)
summary(poiInteract)$dispersion
## [1] 1
summary(qpInteract)$dispersion
## [1] 24.85609

That's pretty far from a Poisson. If you call summary(qpInteract) you will see that the coefficient standard errors are much greater than for the poiInteract model, even thought the point estimates are the same. You were correct to be worried about the Poisson assumption (even if, at first, it might have been for the wrong reason).

In this type of situation people often move to a "negative binomial" model. That includes an extra term so that the mean and the excess dispersion are modeled together. In R, there's an implementation in the MASS package.

library(MASS)
nbInteract <- glm.nb(Total_visits ~ Species*Category_ID,
                        data=visits_df)

The quality-control plots look much better with this (not shown here).

You then can make comparisons among the combinations for which you have data. The emmeans package is one source of useful tools for this; it's a good package to learn if you will continue to do this type of work. You first set up a "grid" of predictor values at which you want to get model estimates of outcomes, via the specs argument.

library(emmeans)
nbIntEMM <- emmeans(nbInteract, specs=~Species+Category_ID)
nbIntEMM
#  Species         Category_ID emmean    SE  df asymp.LCL asymp.UCL
#  Blackberry      RA          nonEst    NA  NA        NA        NA
#  Common hawthorn RA            3.86 0.224 Inf      3.42      4.30
#  Rose            RA            3.69 0.174 Inf      3.34      4.03
#  Blackberry      RN            5.19 0.114 Inf      4.96      5.41
#  Common hawthorn RN            3.89 0.173 Inf      3.55      4.23
#  Rose            RN          nonEst    NA  NA        NA        NA
#  Blackberry      UN            4.93 0.178 Inf      4.58      5.28
#  Common hawthorn UN            3.73 0.133 Inf      3.47      3.99
#  Rose            UN          nonEst    NA  NA        NA        NA
#
# Results are given on the log (not the response) scale. 
# Confidence level used: 0.95 

The reported values by default are in terms of log(mean counts). There are NA values for combinations lacking observations.

You can then specify comparisons that you want to make among the model predictions. The package provides many ways to do this. Here's an example for pairwise comparisons.

contrast(nbIntEMM,method="pairwise",simple="each")

It's a pretty long output that I won't copy here. It shows tests for all species differences within locations and all location differences within species for which you had observations. The calculations adjust for multiple comparisons. The overall result is essentially what @RobertLong reported in the Poisson model without interactions: Blackberry is higher than Common hawthorn (no comparison possible of Blackberry against Rose), but otherwise nothing significant. The coefficient point estimates are the same for all 3 models, but the standard errors are probably most reliable for the negative binomial model.

$\endgroup$
2
  • $\begingroup$ These more elaborate analyses complement and don't contradict the much simpler and more direct analysis in my answer. It's important scientifically and statistically that blackberry and rose don't occur together, but the main conclusions are as given in my graph. Note that I used so-called robust standard errors. so was agnostic as I could be in my framework. $\endgroup$
    – Nick Cox
    Commented Jul 20 at 9:39
  • 1
    $\begingroup$ Sorry, which post of @RobertLong are you referring to? $\endgroup$
    – Nick Cox
    Commented Jul 20 at 11:23
1
$\begingroup$

Poisson, negative binomial, and binomial distribution models are highly parametric, and model assumptions often do not hold. I would use a semiparametric model that does not assume a specific distribution. Resources are here. You’ll see there that the Wilcoxon rank test is a special case, but ordinal regression allows for multiple predictors.

$\endgroup$
3
  • 5
    $\begingroup$ It would be most interesting to see an analysis along these lines and how much different are the scientific indications or conclusions. $\endgroup$
    – Nick Cox
    Commented Jul 20 at 12:20
  • $\begingroup$ Does your suggestion mean that the outcome variable is treated as ordinal, rather than a count ? $\endgroup$
    – Lynchian
    Commented Jul 20 at 17:00
  • 1
    $\begingroup$ A count variable is also ordinal so yes. The numeric spacings are not used until you use the model to estimate means. $\endgroup$ Commented Jul 20 at 21:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.