Package 'multpois'

Title: Analyze Nominal Response Data with the Multinomial-Poisson Trick
Description: Dichotomous responses having two categories can be analyzed with stats::glm() or lme4::glmer() using the family=binomial option. Unfortunately, polytomous responses with three or more unordered categories cannot be analyzed similarly because there is no analogous family=multinomial option. For between-subjects data, nnet::multinom() can address this need, but it cannot handle random factors and therefore cannot handle repeated measures. To address this gap, we transform nominal response data into counts for each categorical alternative. These counts are then analyzed using (mixed) Poisson regression as per Baker (1994) <doi:10.2307/2348134>. Omnibus analyses of variance can be run along with post hoc pairwise comparisons. For users wishing to analyze nominal responses from surveys or experiments, the functions in this package essentially act as though stats::glm() or lme4::glmer() had a family=multinomial option.
Authors: Jacob O. Wobbrock [aut, cre, cph]
Maintainer: Jacob O. Wobbrock <[email protected]>
License: GPL (>= 2)
Version: 0.2.0
Built: 2024-10-22 21:18:39 UTC
Source: https://github.com/wobbrock/multpois

Help Index


Get ANOVA-style results for a multinomial-Poisson model

Description

Get ANOVA-style results for a model returned by glm.mp or glmer.mp. The output table contains chi-square results for the main effects and interactions indicated by the given model.

Usage

Anova.mp(model, type = c(3, 2, 1, "III", "II", "I"))

Arguments

model

A model built by glm.mp or glmer.mp. (The underlying model will have been built by glm or glmer, with family=poisson.)

type

In the case of a type II or type III ANOVA, this value will be the type parameter passed to Anova. In the case of a type I ANOVA, for models built with glm.mp, the anova.glm function will be called; for models built with glmer.mp, the anova.merMod function will be called. The default is type 3. See the Details section for Anova.

Details

For type II or III ANOVAs, the Anova.mp function uses Anova behind the scenes to produce an ANOVA-style table with chi-square results. For type I ANOVAs, it uses anova.glm or anova.merMod.

Users wishing to verify the correctness of these results can compare Anova results for dichotomous response models built with glm or glmer (using family=binomial) to Anova.mp results for models built with glm.mp or glmer.mp, respectively. The results should generally match, or be very similar.

Users can also compare Anova results for polytomous response models built with multinom to Anova.mp results for models built with glm.mp. Again, the results should generally match, or be very similar.

There is no similarly easy comparison for polytomous response models with repeated measures. The lack of options was a key motivation for developing glmer.mp in the first place.

Value

An ANOVA-style table of chi-square results for models built by glm.mp or glmer.mp. See the return values for Anova, anova.glm, or anova.merMod.

Author(s)

Jacob O. Wobbrock

References

Baker, S.G. (1994). The multinomial-Poisson transformation. The Statistician 43 (4), pp. 495-504. doi:10.2307/2348134

Chen, Z. and Kuo, L. (2001). A note on the estimation of the multinomial logit model with random effects. The American Statistician 55 (2), pp. 89-95. https://www.jstor.org/stable/2685993

Guimaraes, P. (2004). Understanding the multinomial-Poisson transformation. The Stata Journal 4 (3), pp. 265-273. https://www.stata-journal.com/article.html?article=st0069

Lee, J.Y.L., Green, P.J.,and Ryan, L.M. (2017). On the “Poisson trick” and its extensions for fitting multinomial regression models. arXiv preprint available at doi:10.48550/arXiv.1707.08538

See Also

glm.mp(), glm.mp.con(), glmer.mp(), glmer.mp.con(), car::Anova()

Examples

## between-subjects factors (X1,X2) with polytomous response (Y)
data(bs3, package="multpois")

bs3$PId = factor(bs3$PId)
bs3$Y = factor(bs3$Y)
bs3$X1 = factor(bs3$X1)
bs3$X2 = factor(bs3$X2)
contrasts(bs3$X1) <- "contr.sum"
contrasts(bs3$X2) <- "contr.sum"

m1 = glm.mp(Y ~ X1*X2, data=bs3)
Anova.mp(m1, type=3)

## within-subjects factors (X1,X2) with polytomous response (Y)
data(ws3, package="multpois")

ws3$PId = factor(ws3$PId)
ws3$Y = factor(ws3$Y)
ws3$X1 = factor(ws3$X1)
ws3$X2 = factor(ws3$X2)
contrasts(ws3$X1) <- "contr.sum"
contrasts(ws3$X2) <- "contr.sum"

m2 = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws3)
Anova.mp(m2, type=3)

Between-subjects 2×2 design with dichotomous response

Description

This generic synthetic dataset has a dichotomous response Y and two factors X1 and X2. The response has categories {yes,no}. Factor X1 has levels {a,b}, and factor X2 has levels {c,d}. It also has a PId column for participant identifier. Each participant is on only one row.

Format

A data frame with 60 observations on the following 4 variables:

PId

a subject identifier with levels "1" ... "40"

X1

a between-subjects factor with levels "a", "b"

X2

a between-subjects factor with levels "c", "d"

Y

a dichotomous response with categories "yes", "no"

See Also

See glm.mp and glm.mp.con for complete examples.

Examples

data(bs2, package="multpois")

bs2$PId = factor(bs2$PId)
bs2$Y = factor(bs2$Y)
bs2$X1 = factor(bs2$X1)
bs2$X2 = factor(bs2$X2)
contrasts(bs2$X1) <- "contr.sum"
contrasts(bs2$X2) <- "contr.sum"

m = glm.mp(Y ~ X1*X2, data=bs2)
Anova.mp(m, type=3)
glm.mp.con(m, pairwise ~ X1*X2, adjust="holm")

Between-subjects 2×2 design with polytomous response

Description

This generic synthetic dataset has a polytomous response Y and two factors X1 and X2. The response has categories {yes,no,maybe}. Factor X1 has levels {a,b}, and factor X2 has levels {c,d}. It also has a PId column for participant identifier. Each participant is on only one row.

Format

A data frame with 60 observations on the following 4 variables:

PId

a subject identifier with levels "1" ... "60"

X1

a between-subjects factor with levels "a", "b"

X2

a between-subjects factor with levels "c", "d"

Y

a polytomous response with categories "yes", "no", and "maybe"

See Also

See glm.mp and glm.mp.con for complete examples.

Examples

data(bs3, package="multpois")

bs3$PId = factor(bs3$PId)
bs3$Y = factor(bs3$Y)
bs3$X1 = factor(bs3$X1)
bs3$X2 = factor(bs3$X2)
contrasts(bs3$X1) <- "contr.sum"
contrasts(bs3$X2) <- "contr.sum"

m = glm.mp(Y ~ X1*X2, data=bs3)
Anova.mp(m, type=3)
glm.mp.con(m, pairwise ~ X1*X2, adjust="holm")

Build a multinomial-Poisson GLM for nominal response data

Description

This function uses the multinomial-Poisson trick to analyze nominal response data using a Poisson generalized linear model (GLM). The nominal response should be a factor with two or more unordered categories. The independent variables should be between-subjects factors and/or numeric predictors.

Usage

glm.mp(formula, data, ...)

Arguments

formula

A formula object in the style of, e.g., Y ~ X1*X2, where X1 and X2 are factors or predictors. The response Y must be of type factor. See the formula entry for glm.

data

A data frame in long-format. See the data entry for glm.

...

Additional arguments to be passed to glm. Generally, these are unnecessary but are provided for advanced users. They should not specify formula, data, or family arguments. See glm for valid arguments.

Details

This function should be used for nominal response data with only between-subjects factors or predictors. In essence, it provides for the equivalent of glm with family=multinomial, were that option to exist. (That option does not exist, but multinom serves the same purpose.)

For data with repeated measures, use glmer.mp, which can take random factors and thus handle correlated responses.

Users wishing to verify the correctness of glm.mp should compare its Anova.mp results to Anova results for models built with glm using family=binomial (for dichotomous responses) or multinom (for polytomous responses). The results should generally match, or be very similar.

Value

A Poisson regression model of type glm. See the return value for glm.

Author(s)

Jacob O. Wobbrock

References

Baker, S.G. (1994). The multinomial-Poisson transformation. The Statistician 43 (4), pp. 495-504. doi:10.2307/2348134

Guimaraes, P. (2004). Understanding the multinomial-Poisson transformation. The Stata Journal 4 (3), pp. 265-273. https://www.stata-journal.com/article.html?article=st0069

Lee, J.Y.L., Green, P.J.,and Ryan, L.M. (2017). On the “Poisson trick” and its extensions for fitting multinomial regression models. arXiv preprint available at doi:10.48550/arXiv.1707.08538

See Also

Anova.mp(), glm.mp.con(), glmer.mp(), glmer.mp.con(), stats::glm(), nnet::multinom()

Examples

library(car)
library(nnet)

## between-subjects factors (X1,X2) with dichotomous response (Y)
data(bs2, package="multpois")

bs2$PId = factor(bs2$PId)
bs2$Y = factor(bs2$Y)
bs2$X1 = factor(bs2$X1)
bs2$X2 = factor(bs2$X2)
contrasts(bs2$X1) <- "contr.sum"
contrasts(bs2$X2) <- "contr.sum"

m1 = glm(Y ~ X1*X2, data=bs2, family=binomial)
Anova(m1, type=3)

m2 = glm.mp(Y ~ X1*X2, data=bs2) # compare
Anova.mp(m2, type=3)

## between-subjects factors (X1,X2) with polytomous response (Y)
data(bs3, package="multpois")

bs3$PId = factor(bs3$PId)
bs3$Y = factor(bs3$Y)
bs3$X1 = factor(bs3$X1)
bs3$X2 = factor(bs3$X2)
contrasts(bs3$X1) <- "contr.sum"
contrasts(bs3$X2) <- "contr.sum"

m3 = multinom(Y ~ X1*X2, data=bs3, trace=FALSE)
Anova(m3, type=3)

m4 = glm.mp(Y ~ X1*X2, data=bs3) # compare
Anova.mp(m4, type=3)

Contrast tests for multinomial-Poisson GLMs

Description

This function conducts post hoc pairwise comparisons on generalized linear models (GLMs) built with glm.mp. Such models have nominal response types, i.e., factors with unordered categories.

Usage

glm.mp.con(
  model,
  formula,
  adjust = c("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none"),
  ...
)

Arguments

model

A multinomial-Poisson generalized linear model created by glm.mp.

formula

A formula object in the style of, e.g., pairwise ~ X1*X2, where X1 and X2 are factors in model. The pairwise keyword must be used on the left-hand side of the formula. See the specs entry for emmeans.

adjust

A string indicating the p-value adjustment to use. Defaults to "holm". See the Details section for p.adjust.

...

Additional arguments to be passed to glm. Generally, these are unnecessary but are provided for advanced users. They should not specify formula, data, or family arguments. See glm for valid arguments.

Details

Post hoc pairwise comparisons should be conducted only after a statistically significant omnibus test using Anova.mp. Comparisons are conducted in the style of emmeans but not using this function; rather, the multinomial-Poisson trick is used on a subset of the data relevant to each pairwise comparison.

Users wishing to verify the correctness of glm.mp.con should compare its results to emmeans results for models built with glm using family=binomial for dichotomous responses. The results should be similar.

Value

Pairwise comparisons for all levels indicated by the factors in formula.

Author(s)

Jacob O. Wobbrock

References

Baker, S.G. (1994). The multinomial-Poisson transformation. The Statistician 43 (4), pp. 495-504. doi:10.2307/2348134

Guimaraes, P. (2004). Understanding the multinomial-Poisson transformation. The Stata Journal 4 (3), pp. 265-273. https://www.stata-journal.com/article.html?article=st0069

Lee, J.Y.L., Green, P.J.,and Ryan, L.M. (2017). On the “Poisson trick” and its extensions for fitting multinomial regression models. arXiv preprint available at doi:10.48550/arXiv.1707.08538

See Also

Anova.mp(), glm.mp(), glmer.mp(), glmer.mp.con(), emmeans::emmeans()

Examples

library(car)
library(nnet)
library(emmeans)

## between-subjects factors (X1,X2) with dichotomous response (Y)
data(bs2, package="multpois")

bs2$PId = factor(bs2$PId)
bs2$Y = factor(bs2$Y)
bs2$X1 = factor(bs2$X1)
bs2$X2 = factor(bs2$X2)
contrasts(bs2$X1) <- "contr.sum"
contrasts(bs2$X2) <- "contr.sum"

m1 = glm(Y ~ X1*X2, data=bs2, family=binomial)
Anova(m1, type=3)
emmeans(m1, pairwise ~ X1*X2, adjust="holm")

m2 = glm.mp(Y ~ X1*X2, data=bs2)
Anova.mp(m2, type=3)
glm.mp.con(m2, pairwise ~ X1*X2, adjust="holm") # compare

## between-subjects factors (X1,X2) with polytomous response (Y)
data(bs3, package="multpois")

bs3$PId = factor(bs3$PId)
bs3$Y = factor(bs3$Y)
bs3$X1 = factor(bs3$X1)
bs3$X2 = factor(bs3$X2)
contrasts(bs3$X1) <- "contr.sum"
contrasts(bs3$X2) <- "contr.sum"

m3 = multinom(Y ~ X1*X2, data=bs3, trace=FALSE)
Anova(m3, type=3)
e0 = emmeans(m3, ~ X1*X2 | Y, mode="latent")
c0 = contrast(e0, method="pairwise", ref=1)
test(c0, joint=TRUE, by="contrast")

m4 = glm.mp(Y ~ X1*X2, data=bs3)
Anova.mp(m4, type=3)
glm.mp.con(m4, pairwise ~ X1*X2, adjust="holm") # compare

Build a multinomial-Poisson GLMM for nominal response data

Description

This function uses the multinomial-Poisson trick to analyze nominal response data using a Poisson generalized linear mixed model (GLMM). The nominal response should be a factor with two or more unordered categories. The independent variables should have at least one within-subjects factor or numeric predictor. There also must be a repeated subject identifier to be used as a random factor.

Usage

glmer.mp(formula, data, ...)

Arguments

formula

A formula object in the style of, e.g., Y ~ X1*X2 + (1|PId), where X1 and X2 are factors or predictors and PId is a factor serving as a subject identifier. The response Y must be of type factor. See the formula entry for glmer.

data

A data frame in long-format. See the data entry for glmer.

...

Additional arguments to be passed to glmer. Generally, these are unnecessary but are provided for advanced users. They should not specify formula, data, or family arguments. See glmer for valid arguments.

Details

This function should be used for nominal response data with repeated measures. In essence, it provides for the equivalent of glmer with family=multinomial, were that option to exist. (That option does not exist, which was a key motivation for developing this function.)

For polytomous response data with only between-subjects factors, use glm.mp or multinom.

Users wishing to verify the correctness of glmer.mp should compare its Anova.mp results to Anova results for models built with glmer using family=binomial for dichotomous responses. The results should generally match, or be very similar.

Value

A mixed-effects Poisson regression model of type merMod, specifically of subclass glmerMod. See the return value for glmer.

Note

It is common to receive a boundary (singular) fit message. This generally can be ignored provided the test output looks sensible. Less commonly, the procedure can fail to converge, which can happen when counts of one or more categories are very small or zero in some conditions. In such cases, any results should be regarded with caution.

Author(s)

Jacob O. Wobbrock

References

Baker, S.G. (1994). The multinomial-Poisson transformation. The Statistician 43 (4), pp. 495-504. doi:10.2307/2348134

Chen, Z. and Kuo, L. (2001). A note on the estimation of the multinomial logit model with random effects. The American Statistician 55 (2), pp. 89-95. https://www.jstor.org/stable/2685993

Guimaraes, P. (2004). Understanding the multinomial-Poisson transformation. The Stata Journal 4 (3), pp. 265-273. https://www.stata-journal.com/article.html?article=st0069

Lee, J.Y.L., Green, P.J.,and Ryan, L.M. (2017). On the “Poisson trick” and its extensions for fitting multinomial regression models. arXiv preprint available at doi:10.48550/arXiv.1707.08538

See Also

Anova.mp(), glmer.mp.con(), glm.mp(), glm.mp.con(), lme4::glmer()

Examples

library(car)
library(lme4)
library(lmerTest)

## within-subjects factors (x1,X2) with dichotomous response (Y)
data(ws2, package="multpois")

ws2$PId = factor(ws2$PId)
ws2$Y = factor(ws2$Y)
ws2$X1 = factor(ws2$X1)
ws2$X2 = factor(ws2$X2)
contrasts(ws2$X1) <- "contr.sum"
contrasts(ws2$X2) <- "contr.sum"

m1 = glmer(Y ~ X1*X2 + (1|PId), data=ws2, family=binomial)
Anova(m1, type=3)

m2 = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws2) # compare
Anova.mp(m2, type=3)

## within-subjects factors (x1,X2) with polytomous response (Y)
data(ws3, package="multpois")

ws3$PId = factor(ws3$PId)
ws3$Y = factor(ws3$Y)
ws3$X1 = factor(ws3$X1)
ws3$X2 = factor(ws3$X2)
contrasts(ws3$X1) <- "contr.sum"
contrasts(ws3$X2) <- "contr.sum"

m3 = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws3)
Anova.mp(m3, type=3)

Contrast tests for multinomial-Poisson GLMMs

Description

This function conducts post hoc pairwise comparisons on generalized linear mixed models (GLMMs) built with glmer.mp. Such models have nominal response types, i.e., factors with unordered categories.

Usage

glmer.mp.con(
  model,
  formula,
  adjust = c("holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none"),
  ...
)

Arguments

model

A multinomial-Poisson generalized linear mixed model created by glmer.mp.

formula

A formula object in the style of, e.g., pairwise ~ X1*X2, where X1 and X2 are factors in model. The pairwise keyword must be used on the left-hand side of the formula. See the specs entry for emmeans.

adjust

A string indicating the p-value adjustment to use. Defaults to "holm". See the Details section for p.adjust.

...

Additional arguments to be passed to glmer. Generally, these are unnecessary but are provided for advanced users. They should not specify formula, data, or family arguments. See glmer for valid arguments.

Details

Post hoc pairwise comparisons should be conducted only after a statistically significant omnibus test using Anova.mp. Comparisons are conducted in the style of emmeans but not using this function; rather, the multinomial-Poisson trick is used on a subset of the data relevant to each pairwise comparison.

Users wishing to verify the correctness of glmer.mp.con should compare its results to emmeans results for models built with glmer using family=binomial for dichotomous responses. The results should be similar.

Value

Pairwise comparisons for all levels indicated by the factors in formula.

Note

It is common to receive boundary (singular) fit messages. These generally can be ignored provided the test outputs look sensible. Less commonly, the procedures can fail to converge, which can happen when counts of one or more categories are very small or zero in some conditions. In such cases, any results should be regarded with caution.

Author(s)

Jacob O. Wobbrock

References

Baker, S.G. (1994). The multinomial-Poisson transformation. The Statistician 43 (4), pp. 495-504. doi:10.2307/2348134

Chen, Z. and Kuo, L. (2001). A note on the estimation of the multinomial logit model with random effects. The American Statistician 55 (2), pp. 89-95. https://www.jstor.org/stable/2685993

Guimaraes, P. (2004). Understanding the multinomial-Poisson transformation. The Stata Journal 4 (3), pp. 265-273. https://www.stata-journal.com/article.html?article=st0069

Lee, J.Y.L., Green, P.J.,and Ryan, L.M. (2017). On the “Poisson trick” and its extensions for fitting multinomial regression models. arXiv preprint available at doi:10.48550/arXiv.1707.08538

See Also

Anova.mp(), glmer.mp(), glm.mp(), glm.mp.con(), emmeans::emmeans()

Examples

library(car)
library(lme4)
library(lmerTest)
library(emmeans)

## within-subjects factors (x1,X2) with dichotomous response (Y)
data(ws2, package="multpois")

ws2$PId = factor(ws2$PId)
ws2$Y = factor(ws2$Y)
ws2$X1 = factor(ws2$X1)
ws2$X2 = factor(ws2$X2)
contrasts(ws2$X1) <- "contr.sum"
contrasts(ws2$X2) <- "contr.sum"

m1 = glmer(Y ~ X1*X2 + (1|PId), data=ws2, family=binomial)
Anova(m1, type=3)
emmeans(m1, pairwise ~ X1*X2, adjust="holm")

m2 = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws2)
Anova.mp(m2, type=3)
glmer.mp.con(m2, pairwise ~ X1*X2, adjust="holm") # compare

## within-subjects factors (x1,X2) with polytomous response (Y)
data(ws3, package="multpois")

ws3$PId = factor(ws3$PId)
ws3$Y = factor(ws3$Y)
ws3$X1 = factor(ws3$X1)
ws3$X2 = factor(ws3$X2)
contrasts(ws3$X1) <- "contr.sum"
contrasts(ws3$X2) <- "contr.sum"

m3 = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws3)
Anova.mp(m3, type=3)
glmer.mp.con(m3, pairwise ~ X1*X2, adjust="holm")

Mixed factorial 2×2 design with polytomous response

Description

This synthetic dataset represents a survey of 40 respondents about their favorite ice cream flavor. Twenty of the respondents were adults and 20 were children. They were queried four times over the course of a year, once in the middle of each season (fall, winter, spring, summer).

This dataset has a polytomous response Pref and two factors, Age and Season. The response has the unordered categories {vanilla, chocolate, strawberry, other}. Factor Age has levels {adult, child}, and factor Season has levels {fall, winter, spring, summer}. It also has a PId column for participant identifier. Each participant identifier is repeated four times, once per season.

Format

A data frame with 160 observations on the following 4 variables:

PId

a subject identifier with levels "1" ... "40"

Age

a between-subjects factor with levels "adult", "child"

Season

a within-subjects factor with levels "fall", "winter", "spring", "summer"

Pref

a polytomous response with categories "vanilla", "chocolate", "strawberry", "other"

See Also

See vignette("multpois", package="multpois") for a complete analysis of this data set.

Examples

data(icecream, package="multpois")

icecream$PId = factor(icecream$PId)
icecream$Pref = factor(icecream$Pref)
icecream$Age = factor(icecream$Age)
icecream$Season = factor(icecream$Season)
contrasts(icecream$Age) <- "contr.sum"
contrasts(icecream$Season) <- "contr.sum"

m = glmer.mp(Pref ~ Age*Season + (1|PId), data=icecream)
Anova.mp(m, type=3)
glmer.mp.con(m, pairwise ~ Age*Season, adjust="holm")

Within-subjects 2×2 design with dichotomous response

Description

This generic synthetic dataset has a dichotomous response Y and two factors X1 and X2. The response has categories {yes,no}. Factor X1 has levels {a,b}, and factor X2 has levels {c,d}. It also has a PId column for participant identifier. Participant identifiers are repeated across rows.

Format

A data frame with 60 observations on the following 4 variables:

PId

a subject identifier with levels "1" ... "10"

X1

a within-subjects factor with levels "a", "b"

X2

a within-subjects factor with levels "c", "d"

Y

a dichotomous response with categories "yes", "no"

See Also

See glmer.mp and glmer.mp.con for complete examples.

Examples

data(ws2, package="multpois")

ws2$PId = factor(ws2$PId)
ws2$Y = factor(ws2$Y)
ws2$X1 = factor(ws2$X1)
ws2$X2 = factor(ws2$X2)
contrasts(ws2$X1) <- "contr.sum"
contrasts(ws2$X2) <- "contr.sum"

m = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws2)
Anova.mp(m, type=3)
glmer.mp.con(m, pairwise ~ X1*X2, adjust="holm")

Within-subjects 2×2 design with polytomous response

Description

This generic synthetic dataset has a polytomous response Y and two factors X1 and X2. The response has categories {yes,no,maybe}. Factor X1 has levels {a,b}, and factor X2 has levels {c,d}. It also has a PId column for participant identifier. Participant identifiers are repeated across rows.

Format

A data frame with 60 observations on the following 4 variables:

PId

a subject identifier with levels "1" ... "15"

X1

a within-subjects factor with levels "a", "b"

X2

a within-subjects factor with levels "c", "d"

Y

a polytomous response with categories "yes", "no", "maybe"

See Also

See glmer.mp and glmer.mp.con for complete examples.

Examples

data(ws3, package="multpois")

ws3$PId = factor(ws3$PId)
ws3$Y = factor(ws3$Y)
ws3$X1 = factor(ws3$X1)
ws3$X2 = factor(ws3$X2)
contrasts(ws3$X1) <- "contr.sum"
contrasts(ws3$X2) <- "contr.sum"

m = glmer.mp(Y ~ X1*X2 + (1|PId), data=ws3)
Anova.mp(m, type=3)
glmer.mp.con(m, pairwise ~ X1*X2, adjust="holm")