| # File src/library/stats/R/loglin.R |
| # Part of the R package, https://www.R-project.org |
| # |
| # Copyright (C) 1995-2013 The R Core Team |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # A copy of the GNU General Public License is available at |
| # https://www.R-project.org/Licenses/ |
| |
| loglin <- function(table, margin, start = rep(1, length(table)), fit = |
| FALSE, eps = 0.1, iter = 20L, param = FALSE, print = |
| TRUE) { |
| rfit <- fit |
| |
| dtab <- dim(table) |
| nvar <- length(dtab) |
| |
| ncon <- length(margin) |
| conf <- matrix(0L, nrow = nvar, ncol = ncon) |
| nmar <- 0 |
| varnames <- names(dimnames(table)) |
| for (k in seq_along(margin)) { |
| tmp <- margin[[k]] |
| if (is.character(tmp)) { |
| ## Rewrite margin names to numbers |
| tmp <- match(tmp, varnames) |
| margin[[k]] <- tmp |
| } |
| if (!is.numeric(tmp) || any(is.na(tmp) | tmp <= 0)) |
| stop("'margin' must contain names or numbers corresponding to 'table'") |
| conf[seq_along(tmp), k] <- tmp |
| nmar <- nmar + prod(dtab[tmp]) |
| } |
| |
| ntab <- length(table) |
| if (length(start) != ntab ) stop("'start' and 'table' must be same length") |
| |
| z <- .Call(C_LogLin, dtab, conf, table, start, nmar, eps, iter) |
| |
| if (print) |
| cat(z$nlast, "iterations: deviation", z$dev[z$nlast], "\n") |
| |
| fit <- z$fit |
| attributes(fit) <- attributes(table) |
| |
| ## Pearson chi-sq test statistic |
| observed <- as.vector(table[start > 0]) |
| expected <- as.vector(fit[start > 0]) |
| pearson <- sum((observed - expected)^2 / expected) |
| |
| ## Likelihood Ratio Test statistic |
| observed <- as.vector(table[table * fit > 0]) |
| expected <- as.vector(fit[table * fit > 0]) |
| lrt <- 2 * sum(observed * log(observed / expected)) |
| |
| ## Compute degrees of freedom. |
| ## Use a dyadic-style representation for the (possible) subsets B. |
| ## Let u_i(B) = 1 if i is contained in B and 0 otherwise. Then B |
| ## <-> u(B) = (u_1(B),...,u_N(B)) <-> \sum_{i=1}^N u_i(B) 2^{i-1}. |
| ## See also the code for 'dyadic' below which computes the u_i(B). |
| subsets <- function(x) { |
| y <- list(vector(mode(x), length = 0)) |
| for (i in seq_along(x)) { |
| y <- c(y, lapply(y, "c", x[i])) |
| } |
| y[-1L] |
| } |
| df <- rep.int(0, 2^nvar) |
| for (k in seq_along(margin)) { |
| terms <- subsets(margin[[k]]) |
| for (j in seq_along(terms)) |
| df[sum(2 ^ (terms[[j]] - 1))] <- prod(dtab[terms[[j]]] - 1) |
| } |
| |
| ## Rewrite margin numbers to names if possible |
| if (!is.null(varnames) && all(nzchar(varnames))) { |
| for (k in seq_along(margin)) |
| margin[[k]] <- varnames[margin[[k]]] |
| } else { |
| varnames <- as.character(1 : ntab) |
| } |
| |
| y <- list(lrt = lrt, |
| pearson = pearson, |
| df = ntab - sum(df) - 1, |
| margin = margin) |
| |
| if (rfit) |
| y$fit <- fit |
| |
| if (param) { |
| fit <- log(fit) |
| terms <- seq_along(df)[df > 0] |
| |
| parlen <- length(terms) + 1 |
| parval <- list(parlen) |
| parnam <- character(parlen) |
| |
| parval[[1L]] <- mean(fit) |
| parnam[1L] <- "(Intercept)" |
| fit <- fit - parval[[1L]] |
| |
| ## Get the u_i(B) in the rows of 'dyadic', see above. |
| dyadic <- NULL |
| while(any(terms > 0)) { |
| dyadic <- cbind(dyadic, terms %% 2) |
| terms <- terms %/% 2 |
| } |
| dyadic <- dyadic[order(rowSums(dyadic)), , drop = FALSE] |
| |
| for (i in 2 : parlen) { |
| vars <- which(dyadic[i - 1, ] > 0) |
| parval[[i]] <- apply(fit, vars, mean) |
| parnam[i] <- paste(varnames[vars], collapse = ".") |
| fit <- sweep(fit, vars, parval[[i]], check.margin=FALSE) |
| } |
| |
| names(parval) <- parnam |
| y$param <- parval |
| } |
| |
| return(y) |
| } |