R/revealPrefModel.R

Defines functions print.ramchoiceRevealPrefModel summary.ramchoiceRevealPrefModel revealPrefModel

Documented in print.ramchoiceRevealPrefModel revealPrefModel summary.ramchoiceRevealPrefModel

################################################################################
#' @title Model Falsification with Random Limited Attention
#'
#' @description Given a collection of choice problems and corresponding
#' choice probabilities, \code{revealPrefModel} determines if they are compatible with
#' the Random Attention Model (RAM) of
#' \href{https://arxiv.org/abs/1712.03448}{Cattaneo, Ma, Masatlioglu, and Suleymanov (2020)}
#' and/or the Attention Overload Model (AOM) of
#' \href{https://arxiv.org/abs/2110.10650}{Cattaneo, Cheung, Ma, and Masatlioglu (2022)}.
#'
#' See \code{\link{revealPref}} for revealed preference analysis with empirical choice data.
#'
#' @param menu Numeric matrix of 0s and 1s, the collection of choice problems.
#' @param prob Numeric matrix, the collection of choice probabilities
#' @param pref_list Numeric matrix, each row corresponds to one preference. For example, \code{c(2, 3, 1)} means
#'   2 is preferred to 3 and to 1. When set to \code{NULL}, the default, \code{c(1, 2, 3, ...)},
#'   will be used.
#' @param RAM Boolean, whether the restrictions implied by the RAM of
#'   \href{https://arxiv.org/abs/1712.03448}{Cattaneo et al. (2020)} should be incorporated, that is, their monotonic attention assumption (default is \code{TRUE}).
#' @param AOM Boolean, whether the restrictions implied by the AOM of
#'   \href{https://arxiv.org/abs/2110.10650}{Cattaneo et al. (2022)} should be incorporated, that is, their attention overload assumption (default is \code{TRUE}).
#' @param limDataCorr Boolean, whether assuming limited data (default is \code{TRUE}). When set to
#'   \code{FALSE}, will assume all choice problems are observed. This option only applies when \code{RAM} is set to \code{TRUE}.
#' @param attBinary Numeric, between 1/2 and 1 (default is \code{1}), whether additional restrictions (on the attention rule)
#'   should be imposed for binary choice problems (i.e., attentive at binaries).
#'
#' @return
#' \item{constraints}{Matrices of constraints, generated by \code{\link{genMat}}. \code{R}: a matrix containing all constraints. \code{ConstN}: number of constraints for each preference.}
#' \item{inequalities}{The moment inequalities. Positive numbers indicate that the RAM/AOM restrictions are rejected by the given choice probabilities. \code{R}: a vector containing all moment inequalities. \code{ConstN}: number of constraints for each preference.}
#'
#' @references
#' M. D. Cattaneo, X. Ma, Y. Masatlioglu, and E. Suleymanov (2020). \href{https://arxiv.org/abs/1712.03448}{A Random Attention Model}. \emph{Journal of Political Economy} 128(7): 2796-2836. \doi{10.1086/706861}
#'
#' M. D. Cattaneo, P. Cheung, X. Ma, and Y. Masatlioglu (2022). \href{https://arxiv.org/abs/2110.10650}{Attention Overload}. Working paper.
#'
#' @author
#' Matias D. Cattaneo, Princeton University. \email{cattaneo@princeton.edu}.
#'
#' Paul Cheung, University of Maryland. \email{hycheung@umd.edu}
#'
#' Xinwei Ma (maintainer), University of California San Diego. \email{x1ma@ucsd.edu}
#'
#' Yusufcan Masatlioglu, University of Maryland. \email{yusufcan@umd.edu}
#'
#' Elchin Suleymanov, Purdue University. \email{esuleyma@purdue.edu}
#'
#' @examples
#' # Logit attention with parameter 2
#' # True preference: 1 2 3 4 5 6
#' menu <- prob <- matrix(c(1, 1, 1, 1, 1, 1,
#'                          0, 1, 1, 1, 1, 1,
#'                          1, 0, 1, 1, 1, 1,
#'                          1, 1, 0, 1, 1, 1,
#'                          1, 1, 1, 0, 1, 1,
#'                          1, 1, 1, 1, 0, 1,
#'                          1, 1, 1, 1, 1, 0), ncol=6, byrow=TRUE)
#' for (i in 1:nrow(prob)) prob[i, menu[i, ]==1] <- logitAtte(sum(menu[i, ]), 2)$choiceProb
#'
#' # List of preferences to be tested
#' pref_list <- matrix(c(1, 2, 3, 4, 5, 6,
#'                       2, 3, 4, 5, 6, 1), ncol=6, byrow=TRUE)
#' # RAM only
#' result1 <- revealPrefModel(menu = menu, prob = prob, pref_list = pref_list, RAM = TRUE, AOM = FALSE)
#' summary(result1)
#'
#' # AOM only
#' result2 <- revealPrefModel(menu = menu, prob = prob, pref_list = pref_list, RAM = FALSE, AOM = TRUE)
#' summary(result2)
#'
#' # Both RAM and AOM
#' result3 <- revealPrefModel(menu = menu, prob = prob, pref_list = pref_list, RAM = TRUE, AOM = TRUE)
#' summary(result3)
#'
#' @export
revealPrefModel <- function(menu, prob, pref_list = NULL,
                  RAM = TRUE, AOM = TRUE,
                  limDataCorr = TRUE,
                  attBinary = 1) {

  ################################################################################
  # Error Check
  ################################################################################

  # menu
  if (!is.matrix(menu)) {
    stop("Input 'menu' has to be a matrix.\n")
  } else if (min(dim(menu)) == 0) {
    stop("Input 'menu' has at least one dimension 0.\n")
  } else if (!all((menu == 0) | (menu == 1))) {
    stop("Input 'menu' can only contain 0 (FALSE) and 1 (TRUE).\n")
  } else {
    # nothing
  }

  # prob
  if (!is.matrix(prob)) {
    stop("Input 'prob' has to be a matrix.\n")
  } else if (min(dim(prob)) == 0) {
    stop("Input 'prob' has at least one dimension 0.\n")
  } else if (!all((prob >= 0) & (prob <= 1))) {
    stop("Input 'prob' can only contain values between 0 and 1.\n")
  } else {
  #} else if (!all(rowSums(prob) == 1)) {
  #  stop("Input 'prob' should contain rows that sum to 1.\n")
  #} else {
    # nothing
  }

  # menu and prob
  if (!all(dim(menu) == dim(prob))) {
    stop("Input 'menu' and 'prob' have to have the same dimensions.\n")
  }
  else if (any(as.integer(rowSums((menu == 0) & (prob > 0))))) {
    stop("Input 'prob' cannot be positive when the corresponding entry in 'menu' is zero.\n")
  } else {
    # nothing
  }

  # preference
  if (length(as.vector(pref_list)) == 0) {
    pref_list <- matrix(1:ncol(menu), nrow=1)
  } else if (!is.matrix(pref_list)) {
    stop("Input 'pref_list' has to be a matrix.\n")
  } else if (min(dim(pref_list)) == 0) {
    stop("Input 'pref_list' has at least one dimension 0.\n")
  } else if (ncol(pref_list) != ncol(menu)) {
    stop("Input 'pref_list' has to have the same number of columns as 'menu'.\n")
  } else if (!all(apply(pref_list, MARGIN=1, FUN=function(x) all(sort(x)==1:ncol(menu))))) {
    stop("Input 'pref_list' incorrectly specified.\n")
  } else {
    # nothing
  }

  ################################################################################
  # Initialization
  ################################################################################
  # generate matrices of constraints
  constraints <- genMat(menu, rowSums(menu), pref_list, RAM, AOM, limDataCorr, attBinary)
  # generate the vector of probabilities
  probVec <- matrix(t(prob)[t(menu) == 1], ncol=1)

  Result <- list(constraints=constraints,
                 probVec = probVec,
                 inequalities=list(R=constraints$R%*%probVec, ConstN=constraints$ConstN),
                 pref=pref_list,
                 opt=list(RAM=RAM, AOM=AOM, limDataCorr=limDataCorr, attBinary=attBinary),
                 sumStats=list(nAlt=ncol(menu), maxMsize=max(rowSums(menu)), minMsize=min(rowSums(menu)), nChoiceProb=nrow(menu)))

  class(Result) <- "ramchoiceRevealPrefModel"
  return(Result)
}

################################################################################
#' Internal function.
#'
#' @param object Class \code{ramchoiceRevealPrefModel} objects.
#'
#' @keywords internal
#' @export
summary.ramchoiceRevealPrefModel <- function(object, ...) {
  x <- object
  cat("\n Model Falsification with Random Limited Attention.\n")
  cat("\n")

  cat(paste(format("# of alternatives",    width=25), toString(x$sumStats$nAlt), sep="")); cat("\n")
  cat(paste(format("# of choice problems", width=25), toString(x$sumStats$nChoiceProb), sep="")); cat("\n")
  cat("\n")

  cat(paste(format("Min # of alternatives", width=25), toString(x$sumStats$minMsize), sep="")); cat("\n")
  cat(paste(format("Max # of alternatives", width=25), toString(x$sumStats$maxMsize), sep="")); cat("\n")
  cat("\n")

  if (x$opt$RAM) {
    if (x$opt$limDataCorr) {
      cat(format("RAM restrictions employed.", width=100)); cat("\n")
    } else {
      cat(format("RAM restrictions employed.", width=100)); cat("\n")
    }
  }

  if (x$opt$AOM) {
    cat(format("AOM restrictions employed.", width=100)); cat("\n")
  }

  if (x$opt$attBinary < 1) {
    cat(paste(format("Attentive-at-binaries restrictions employed with threshold ", width=59), toString(round(x$opt$attBinary, 3)), sep="")); cat("\n")
  }
  cat("\n")

  cat(paste(rep("=", 60), collapse="")); cat("\n")
  cat(paste(format("Moment Inequalities", width=15), sep="")); cat("\n")
  cat(paste(format(" ", width=15), format("Max", width=15), format("Min", width=15), format("# Violations", width=15), sep="")); cat("\n")
  cat(paste(rep("=", 60), collapse="")); cat("\n")

  for (i in 1:nrow(x$pref)) {
    cat(paste("Preference[", toString(i), "]",": ", sep=""))
    cat(x$pref[i, ]); cat("\n")
    inequalTemp <- x$inequalities$R[(sum(x$inequalities$ConstN[1:i]) - x$inequalities$ConstN[i] + 1):(sum(x$inequalities$ConstN[1:i]))]
    cat(paste(format(" "       , width=15),
              format(toString(round(max(inequalTemp), 5)), width=15),
              format(toString(round(min(inequalTemp), 5)), width=15),
              format(toString(round(sum(inequalTemp > 0), 4)), width=15), sep="")); cat("\n")
    cat(paste(rep("=", 60), collapse="")); cat("\n")
    }
}


################################################################################
#' Internal function.
#'
#' @param object Class \code{ramchoiceRevealPrefModel} objects.
#'
#' @keywords internal
#' @export
print.ramchoiceRevealPrefModel <- function(x, ...) {
  cat("\n Model Falsification with Random Limited Attention.\n")
  cat("\n")

  cat(paste(format("# of alternatives",    width=25), toString(x$sumStats$nAlt), sep="")); cat("\n")
  cat(paste(format("# of choice problems", width=25), toString(x$sumStats$nChoiceProb), sep="")); cat("\n")
  cat("\n")

  cat(paste(format("Min # of alternatives", width=25), toString(x$sumStats$minMsize), sep="")); cat("\n")
  cat(paste(format("Max # of alternatives", width=25), toString(x$sumStats$maxMsize), sep="")); cat("\n")
  cat("\n")

  if (x$opt$RAM) {
    if (x$opt$limDataCorr) {
      cat(format("RAM restrictions employed.", width=100)); cat("\n")
    } else {
      cat(format("RAM restrictions employed.", width=100)); cat("\n")
    }
  }

  if (x$opt$AOM) {
    cat(format("AOM restrictions employed.", width=100)); cat("\n")
  }

  if (x$opt$attBinary < 1) {
    cat(paste(format("Attentive-at-binaries restrictions employed with threshold ", width=59), toString(round(x$opt$attBinary, 3)), sep="")); cat("\n")
  }
  cat("\n")

  cat(paste(rep("=", 60), collapse="")); cat("\n")
  cat(paste(format("Moment Inequalities", width=15), sep="")); cat("\n")
  cat(paste(format(" ", width=15), format("Max", width=15), format("Min", width=15), format("# Violations", width=15), sep="")); cat("\n")
  cat(paste(rep("=", 60), collapse="")); cat("\n")

  for (i in 1:nrow(x$pref)) {
    cat(paste("Preference[", toString(i), "]",": ", sep=""))
    cat(x$pref[i, ]); cat("\n")
    inequalTemp <- x$inequalities$R[(sum(x$inequalities$ConstN[1:i]) - x$inequalities$ConstN[i] + 1):(sum(x$inequalities$ConstN[1:i]))]
    cat(paste(format(" "       , width=15),
              format(toString(round(max(inequalTemp), 5)), width=15),
              format(toString(round(min(inequalTemp), 5)), width=15),
              format(toString(round(sum(inequalTemp > 0), 4)), width=15), sep="")); cat("\n")
    cat(paste(rep("=", 60), collapse="")); cat("\n")
  }
}

Try the ramchoice package in your browser

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

ramchoice documentation built on May 24, 2022, 1:06 a.m.