--- title: "Examples: Model Interface" author: "Philip I. Pavlik Jr." date: "2026-06-08" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Examples: Model Interface} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r setup} source("lkt-vignette-setup.R") ``` # Load data ```{r bundled-data} val <- prepare_largeraw_sample() small_val <- val[seq_len(600), ] ``` # Custom model using shared feature input ```{r model-feature-input} model_seen <- list() feature_input_model_adapter <- LKTCustomModel( name = "feature-input-smoke", fit = function(request, verbose = FALSE) { model_seen$request_names <<- names(request) model_seen$feature_input_names <<- names(request$feature_input) model_seen$feature_input_class <<- class(request$feature_input) model_seen$column_names <<- request$feature_input$column_names model_seen$response_length <<- length(request$feature_input$response) model_seen$feature_count <<- length(request$feature_input$feature_spec) LibLinearModel()$fit(request, verbose = verbose) } ) feature_input_model <- LKT( data = small_val, interc = FALSE, components = c("Anon.Student.Id", "KC..Default.", "KC..Default."), features = c("intercept", "intercept", "lineafm"), model = feature_input_model_adapter, verbose = FALSE ) check_true("model request includes feature_input", "feature_input" %in% model_seen$request_names) check_true("feature_input has LKTFeatureInput class", "LKTFeatureInput" %in% model_seen$feature_input_class) check_true("feature_input exposes formula", "formula" %in% model_seen$feature_input_names) check_true("feature_input exposes design matrix", "design_matrix" %in% model_seen$feature_input_names) check_true("feature_input exposes column names", length(model_seen$column_names) > 0) check_true("feature_input response length matches data", model_seen$response_length == nrow(small_val)) check_true("feature_input feature spec length", model_seen$feature_count == 3) check_true("custom model preserves common outputs", all(c( "model", "coefs", "model_specification", "r2", "prediction", "loglike", "model_name" ) %in% names(feature_input_model))) check_true("custom model reports its name", feature_input_model$model_name == "feature-input-smoke") check_true("custom model predictions align", length(feature_input_model$prediction) == nrow(small_val)) ``` # Prediction-only model ```{r prediction-only-model} prediction_only_model_adapter <- LKTCustomModel( name = "prediction-only", fit = function(request, verbose = FALSE) { p <- mean(request$response, na.rm = TRUE) p <- pmin(pmax(p, .00001), .99999) LKTModelFit( model = list(kind = "constant-probability", probability = p), pred = rep(p, length(request$response)) ) } ) prediction_only_model <- LKT( data = small_val, interc = FALSE, components = c("KC..Default."), features = c("intercept"), model = prediction_only_model_adapter, verbose = FALSE ) check_true("prediction-only model returns model", !is.null(prediction_only_model$model)) check_true("prediction-only model has finite loglike", is.finite(prediction_only_model$loglike)) check_true("prediction-only model has finite r2", is.finite(prediction_only_model$r2)) check_true("prediction-only model reports its name", prediction_only_model$model_name == "prediction-only") check_true("prediction-only model can omit coefficients", nrow(prediction_only_model$model_specification[[1]]) == 0) check_true("prediction-only model uses helper constructor", inherits(prediction_only_model_adapter, "LKTModel")) ``` # Model contract failures ```{r model-contract-failures} wrong_length_model <- LKTCustomModel( name = "wrong-length", fit = function(request, verbose = FALSE) { list( model = list(kind = "bad-model"), pred = rep(.5, max(0, length(request$response) - 1)) ) } ) wrong_length_error <- tryCatch( { LKT( data = small_val, interc = FALSE, components = c("KC..Default."), features = c("intercept"), model = wrong_length_model, verbose = FALSE ) FALSE }, error = function(err) grepl("returned predictions with length", conditionMessage(err), fixed = TRUE) ) check_true("wrong-length model fails clearly", wrong_length_error) bad_probability_model <- LKTCustomModel( name = "bad-probability", fit = function(request, verbose = FALSE) { list( model = list(kind = "bad-model"), pred = rep(1, length(request$response)) ) } ) bad_probability_error <- tryCatch( { LKT( data = small_val, interc = FALSE, components = c("KC..Default."), features = c("intercept"), model = bad_probability_model, verbose = FALSE ) FALSE }, error = function(err) grepl("finite probabilities", conditionMessage(err), fixed = TRUE) ) check_true("non-probability model predictions fail clearly", bad_probability_error) ```