--- title: "Introduction to the Topic Testlet Model" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introduction to the Topic Testlet Model} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 4 ) ``` The Topic Testlet Model (TTM) integrates topic modeling (Latent Dirichlet Allocation) with psychometric models (Partial Credit Model) to calibrate testlet-based assessments. This approach uses the textual content of student responses to account for local item dependence (LID) caused by shared stimuli. This vignette demonstrates how to: Pre-process item scores and textual responses. Determine the optimal number of latent topics. Extract person-specific topic proportions (delta). Calibrate the TTM to estimate student ability (theta), topic penalties (lambda), and testlet effects (gamma). 1. Setup First, we load the package. We also set a seed for reproducibility. ```{r} library(TopicTestlet) set.seed(1234) ``` 1. Simulating Data For this tutorial, we will simulate a dataset representing 100 students responding to a testlet with 4 items. Scores: Polytomous scores (0, 1, 2). Essays: Textual responses generated from two distinct vocabularies (representing 2 latent topics). ```{r} # Simulation parameters N_students <- 100 J_items <- 4 K_topics_true <- 2 # A. Simulate Numeric Scores (0-2) score_matrix <- matrix( sample(0:2, N_students * J_items, replace = TRUE), nrow = N_students, ncol = J_items ) # B. Simulate Textual Essays # Define vocabularies for two topics vocab_topic1 <- c("logic", "reasoning", "evidence", "fact", "analysis", "data") vocab_topic2 <- c("feeling", "story", "character", "plot", "narrative", "mood") # Helper function to generate a random essay generate_essay <- function() { words <- sample(c(vocab_topic1, vocab_topic2), size = 20, replace = TRUE) paste(words, collapse = " ") } # Create matrix of essays essay_matrix <- matrix( replicate(N_students * J_items, generate_essay()), nrow = N_students, ncol = J_items ) # Preview the data head(score_matrix, 3) substr(essay_matrix[1,1], 1, 50) # First 50 chars of first essay ``` 2. Aggregating Responses The TTM treats the collection of responses within a testlet as a single "document" for each student. We use aggregate_responses() to combine the text from all items. ```{r} text_vector <- aggregate_responses(essay_matrix) # Check the first student's aggregated text substr(text_vector[1], 1, 60) ``` 3. Determining the Number of Topics We use Perplexity to determine the optimal number of latent topics (K). A lower perplexity indicates a better model fit. We will test K=2 and K=3. ```{r} # In a real analysis, you might check a wider range (e.g., 2:10) perp_results <- ttm_perplexity(text_vector, k_range = 2:3) print(perp_results) # Select the K with the lowest perplexity best_k <- perp_results$k[which.min(perp_results$perplexity)] cat("Optimal number of topics:", best_k) ``` 4. Extracting Topic Proportions Using the optimal K, we fit the Latent Dirichlet Allocation (LDA) model to extract the topic proportion matrix (delta). This matrix represents the probability of each topic in a student's response. ```{r} delta_matrix <- ttm_lda(text_vector, k = best_k) # The result is an N x K matrix head(delta_matrix) ``` 5. Estimating the TTM Finally, we calibrate the Topic Testlet Model using the scores and the extracted topic proportions. This estimates: Theta: Student latent ability. Gamma: Person-specific testlet effect (calculated as the inner product of lambda and delta. Item Parameters: Step difficulties. ```{r} # We use max_iter = 50 for speed in this vignette. # For operational use, allow more iterations for convergence. ttm_results <- ttm_est( scores = score_matrix, delta = delta_matrix, max_iter = 50 ) # Model Fit Statistics print(paste("AIC:", round(ttm_results$AIC, 2))) print(paste("BIC:", round(ttm_results$BIC, 2))) ``` 6. Visualizing Results The TTM allows us to analyze the relationship between student ability and the testlet effect. In many empirical applications, we observe an interaction where students with different ability levels interact with the testlet content differently. ```{r} plot(ttm_results$theta, ttm_results$gamma, xlab = "Student Ability (Theta)", ylab = "Testlet Effect (Gamma)", main = "Relationship between Ability and Testlet Effect", pch = 19, col = rgb(0, 0, 1, 0.6)) grid() abline(lm(ttm_results$gamma ~ ttm_results$theta), col = "red", lwd = 2) ``` In this simulated example, we can examine the distribution of the estimated abilities: ```{r} hist(ttm_results$theta, main = "Distribution of Estimated Abilities", xlab = "Theta", col = "lightblue", border = "white") ``` References Xiong, J., Kuang, H., Tang, C., Liu, Q., Wang, B., Engelhard, G., Cohen, A. S., Xiong, X., & Sheng, R. (2025). A Topic Testlet Model for Calibrating Testlet Constructed Responses. Journal of Educational Measurement.