[Rsiena-commits] r328 - pkg/RSienaTest/R

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Tue Dec 26 02:15:31 CET 2017


Author: fschoenen
Date: 2017-12-26 02:15:31 +0100 (Tue, 26 Dec 2017)
New Revision: 328

Added:
   pkg/RSienaTest/R/formula.R
Log:
formula draft


Added: pkg/RSienaTest/R/formula.R
===================================================================
--- pkg/RSienaTest/R/formula.R	                        (rev 0)
+++ pkg/RSienaTest/R/formula.R	2017-12-26 01:15:31 UTC (rev 328)
@@ -0,0 +1,168 @@
+#' Environment with effect definitions.
+#'
+#' Each effect is a function modifying the siena effects object.
+#'
+#' Effect aguments:
+#' - eff: siena effects object
+#' - var: dependent variable name
+#'
+#' Effect return value: The modified effects object.
+local({
+	# define a bunch of effects
+	for (e in c('density', 'transTrip')) {
+		assign(e, function(eff, var) {
+			setEffect(eff, e, name=var, character=T)
+		})
+	}
+	avAlt <- function(eff, var, ...) {
+		arg <- as.list(sys.call())[-1]  # arguments as called
+		unnamed <- arg[which(names(arg) == '')]  # unnamed arguments
+		net <- as.character(unnamed[[1]]) # original object name
+		setEffect(eff, avAlt, name=var, interaction1=net)
+	}
+}, envir=effectsenv <- new.env())
+
+#' Constructs a siena model specification.
+#'
+#' @param ... list of formulas
+#' @return object of class 'siena_formula'
+siena_formula <- function(...) {
+	# add term attributes
+	m <- sapply(list(...), function(f) terms(f))
+	# assert formula
+	if (!all(sapply(m, function(f) attr(f, 'response') == 1))) {
+		stop('formula without response')
+	}
+	# take response variable as name
+	names(m) <- as.character(sapply(m, function(f) f[[2]]))
+	structure(m, class='siena_formula')
+}
+
+print.siena_formula <- function(sformula) {
+	for (f in sformula) {
+		s <- as.character(f)
+		cat(s[[2]], '~', s[-c(1, 2)], '\n')
+	}
+	invisible(f)
+}
+
+is.siena_formula <- function(f) {
+	'siena_formula' %in% class(f)
+}
+
+#' Concatenates formulas for the same response variable.
+#'
+#' @param lhs object of class 'siena_formula'
+#' @param rhs object of class 'siena_formula'
+#' @return object of class 'siena_formula'
+`+.siena_spec` <- function(lhs, rhs) {
+	vars <- unique(c(names(lhs), names(rhs)))
+	stop('formula concatenation not implemented')
+}
+
+#' Constructs a siena data object from a model specification.
+#'
+#' NOTE: this is seems all a bit hacky right now.  which argument is a data
+#' object.  should be clearer which environment is used.  lots of error
+#' checking to be added
+#'
+#' @param sformula a model specification
+#' @return result of sienaDataCreate
+extract_data <- function(sformula, allowOnly=F) {
+	# assert class
+	if (!is.siena_formula(sformula)) stop('not a model formula')
+	# collect data objects
+	dat <- list()
+	for (f in sformula) {
+		# add response variable
+		response <- as.character(f[[2]])
+		dat[[response]] <- get(response, envir=attr(f, '.Environment'))
+		# other variables can appear as argument to calls
+		vars <- as.list(attr(f, 'variables'))[-1]
+		for (cal in vars) {
+			if (is.call(cal)) {
+				for (i in 2:length(cal)) {
+					arg <- cal[[i]]
+					dat[[as.character(arg)]] <- eval(arg)
+				}
+			}
+		}
+	}
+	# convert common types to siena types
+	for (n in names(dat)) {
+		x <- dat[[n]]
+		if (class(x) == 'array') {
+			if (length(dim(x)) == 3) {
+				dat[[n]] <- sienaDependent(x, allowOnly=allowOnly)
+			}
+		} else if (class(x) == 'matrix') {
+			dat[[n]] <- sienaDependent(x, type='behavior', allowOnly=allowOnly)
+		}
+	}
+	do.call(sienaDataCreate, dat)
+}
+
+#' Runs the effect definitions.
+#'
+#' NOTE: think about the arguments of effects, named/unnamed, quoted/raw
+#'
+#' @param sformula a model specification
+#' @param eff siena effects object
+#' @return siena effects object
+run_effects <- function(sformula, eff) {
+	if (!is.siena_formula(sformula)) stop('not a model formula')
+	#
+	for (f in sformula) {
+		factors <- attr(f, 'factors')
+		vars <- attr(f, 'variables')
+		response <- as.character(f[[2]])
+		for (col in 1:ncol(factors)) {
+			# index of variables in this factor
+			factor_col <- 1 + which(factors[,col] == 1)
+			if (length(factor_col) == 1) {
+				active <- vars[[factor_col]]
+				# convert shorthand symbols to call form
+				if (is.symbol(active)) active <- as.call(list(active))
+				# add mandatory dependent variable and effects object
+				active$var <- response
+				active$eff <- eff
+				# evaluate
+				eff <- eval(active, envir=effectsenv)
+			} else {
+				stop('interaction not yet implemented')
+			}
+		}
+	}
+	eff
+}
+
+#' Conveniece wrapper to siena07.
+#'
+#' @param sformula a model specification as produced by `siena_formula`
+#' @param control algorithm specification as produced by `model.create`
+#' @return result of the siena07 call
+siena17 <- function(sformula, control, dat=NULL) {
+	if (!is.siena_formula(sformula)) stop('not a model formula')
+
+	# auto detect data from the formulas
+	if (is.null(dat)) {
+		dat <- extract_data(sformula)
+	}
+
+	eff <- getEffects(dat)
+	eff <- run_effects(sformula, eff)
+	siena07(control, data=dat, effects=eff, batch=TRUE)
+}
+
+library(RSienaTest)
+siena_control <- model.create
+
+x <- array(c(s501, s502, s503), dim=c(50, 50, 3))
+z <- s50a
+
+sformula <- siena_formula(
+	x ~ transTrip,
+	z ~ avAlt(x))
+print(sformula)
+siena17(sformula, control=siena_control(nsub=2, n3=50))
+



More information about the Rsiena-commits mailing list