tests/testthat/test-admm.R

## artificial example in ?PlackettLuce
M <- matrix(c(1, 2, 0, 0,
              3, 1, 4, 0,
              1, 4, 0, 0,
              2, 1, 4, 3,
              2, 3, 4, 0,
              1, 2, 3, 0), nrow = 6, byrow = TRUE)
R <- as.rankings(M, "ordering")
colnames(R) <- c("apple", "banana", "orange", "pear")

coef_tol <- 1e-4

test_that("PLADMM works for partial rankings [fruits]", {
    ## create design matrix for separate worths for each fruit
    dat <- data.frame(fruit = factor(colnames(R), levels = colnames(R)))
    ## setting rho ~ 10% log-lik gives good results (not extensively tested!)
    partial_PLADMM <- pladmm(R, ~ fruit, dat, rho = 1, rtol = 1e-5)
    partial_PL <- PlackettLuce(rankings = R, npseudo = 0)
    ## expect that log-worths are equal, PLADMM and PlackettLuce
    expect_equal(log(partial_PLADMM[["pi"]]),
                 c(log(coef(partial_PL, log = FALSE))),
                 tolerance = coef_tol)
    ## expect log-worths predicted by linear predictor equal,
    ## PLADMM and PlackettLuce
    expect_equal(log(partial_PLADMM[["tilde_pi"]]),
                 c(log(coef(partial_PL, log = FALSE))),
                 tolerance = coef_tol)
    ## expect beta coef from PLADMM equal non-zero (differences in) log-worth
    ## from PlackettLuce
    expect_equal(coef(partial_PLADMM)[-1],
                 as.vector(coef(partial_PL)[-1]),
                 tolerance = coef_tol, ignore_attr = TRUE)
    ## expect log-likelihood equal, PLADMM and PlackettLuce
    expect_equal(logLik(partial_PLADMM),
                 logLik(partial_PL),
                 tolerance = coef_tol)
    ## expect residual df equal, PLADMM and PlackettLuce
    expect_equal(df.residual(partial_PLADMM),
                 df.residual(partial_PL),
                 tolerance = coef_tol)
})

if (requireNamespace("prefmod", quietly = TRUE) &&
    require("survival", quietly = TRUE)) {
    test_that("PLADMM worth estimates match PlackettLuce and rologit [salad]", {
        ## model with separate worths for each dressing
        ## setting rho ~ 10% log-lik gives good results (not extensively tested!)
        res0_PLADMM <- pladmm(salad_rankings, ~ salad, data = features, rho = 8)
        res0_PL <- PlackettLuce(salad_rankings, npseudo = 0)
        res0_RO <- coxph(Surv(ranking, status) ~ salad + strata(chid),
                         data = cbind(salad_long_rankings, status = 1))
        ## expect that log-worths are equal, PLADMM and PlackettLuce
        expect_equal(log(res0_PLADMM[["pi"]]),
                     c(log(coef(res0_PL, log = FALSE))),
                     tolerance = coef_tol)
        ## expect that log-worths are equal, PLADMM and rank-ordered logit
        lambda <- c(itemA = 0, coef(res0_RO))
        log_worth <- log(exp(lambda)/sum(exp(lambda))) # normalized to sum to 1
        expect_equal(unname(log(res0_PLADMM[["pi"]])),
                     unname(log_worth),
                     tolerance = coef_tol)
        ## expect log-worths predicted by linear predictor equal,
        ## PLADMM and PlackettLuce
        expect_equal(c(res0_PLADMM$x %*% coef(res0_PLADMM)),
                     unname(as.vector(log(coef(res0_PL, log = FALSE)))),
                     tolerance = coef_tol)
        ## expect coef from PLADMM equal non-zero (differences in) log-worth
        ## from PlackettLuce
        ## TRUE to lower tolerance
        expect_equal(coef(res0_PLADMM)[-1],
                     as.vector(coef(res0_PL)[-1]),
                     tolerance = 10*coef_tol, ignore_attr = TRUE)
        ## expect log-likelihood equal, PLADMM andPlackettLuce
        expect_equal(logLik(res0_PLADMM),
                     logLik(res0_PL),
                     tolerance = coef_tol)
    })

    if (require("survival", quietly = TRUE)){
        test_that("PLADMM worth estimates match rank ordered logit model [salad]", {
            ## setting rho ~ 10% log-lik gives good results (not extensively tested!)
            res_PLADMM <- pladmm(salad_rankings, ~ acetic + gluconic,
                                 data = features, rho = 8)
            ## expect log-worths equal to those predicted by linear predictor
            lambda <- c(res_PLADMM$x %*% matrix(coef(res_PLADMM)))
            expect_equal(unname(log(res_PLADMM[["pi"]])),
                         lambda,
                         tolerance = coef_tol)
            ## rank-ordered logit
            res_RO <- coxph(Surv(ranking, status) ~ acetic + gluconic +
                                strata(chid),
                            data = cbind(salad_long_rankings, status = 1))
            beta <- c(0, coef(res_RO))
            lambda <- as.vector(res_PLADMM$x %*% matrix(beta))
            log_worth <- log(exp(lambda)/sum(exp(lambda))) # norm to sum to 1
            ## expect log-worths predicted by linear predictor from PLADMM
            ## equal to log-worths based on rank-orded logit.
            expect_equal(unname(log(res_PLADMM[["pi"]])),
                         log_worth,
                         tolerance = coef_tol)
            ## expect two approaches to give same coefficients
            ## (different intercept)
            expect_equal(coef(res_PLADMM)[-1],
                         beta[-1],
                         tolerance = coef_tol)
            ## expect log-likelihood equal
            ## (survival returns extra `nobs` attribute)
            expect_equal(logLik(res_PLADMM),
                         logLik(res_RO),
                         tolerance = coef_tol, ignore_attr = TRUE)
            ## expect vcov equal
            expect_equal(vcov(res_PLADMM),
                         vcov(res_RO),
                         tolerance = coef_tol)
        })
    }
}

test_that("PLADMM works with weights [salad]", {
    salad_agg_rankings <- aggregate.rankings(salad_rankings)
    ## setting rho ~ 10% log-lik gives good results (not extensively tested!)
    res0_PLADMM <- pladmm(salad_rankings, ~ salad, data = features, rho = 8)
    res1_PLADMM <- pladmm(salad_agg_rankings$ranking, ~ salad, data = features,
                          weights = salad_agg_rankings$freq, rho = 8)
    keep <- setdiff(names(res0_PLADMM),
                    c("call", "time", "orderings", "weights"))
    expect_equal(res0_PLADMM[keep], res1_PLADMM[keep])
    expect_equal(vcov(res0_PLADMM), vcov(res1_PLADMM))
    expect_equal(anova(res0_PLADMM), anova(res1_PLADMM))
    expect_equal(deviance(res0_PLADMM), deviance(res1_PLADMM))
    wt <- salad_agg_rankings$freq
    expect_equal(rowsum(estfun(res0_PLADMM), rep(seq_along(wt), wt)),
                 estfun(res1_PLADMM), ignore_attr = TRUE)
    expect_equal(colSums(estfun(res0_PLADMM)), colSums(estfun(res1_PLADMM)))
    expect_equal(fitted(res0_PLADMM), fitted(res1_PLADMM))
    expect_equal(itempar(res0_PLADMM), itempar(res1_PLADMM))
    expect_equal(logLik(res0_PLADMM), logLik(res1_PLADMM))
})

Try the PlackettLuce package in your browser

Any scripts or data that you put into this service are public.

PlackettLuce documentation built on July 9, 2023, 7:12 p.m.