Individual Psychometrics

An Assessment Toolkit With Applications in R

Author
Affiliation

W. Joel Schneider

Published

Last Updated on October 22, 2024

Preface

I have ambitious goals for this book, but it is not nearly complete. I have been working on it off and on since 2012. It is accompanied by the R package psycheval (Schneider, 2023), which is also in a preliminary state of development.

Schneider, W. J. (2023). Psycheval: A psychological evaluation toolkit. https://github.com/wjschne/psycheval

Most of the figures for this book were created in R (via ggplot2, rgl, or base R), \small\LaTeX (via TikZ), or Observable. To make the content as accessible and transparent as possible, I have included buttons that will reveal the code used to make each figure or table. For example, the initial setup code used for this book can be seen by expanding the note below:

# Load packages
library(conflicted)
conflicts_prefer(dplyr::select, 
                 dplyr::filter, 
                 scales::alpha, 
                 dplyr::lag,
                 tibble::add_case)
library(extrafont)
loadfonts("win", quiet = TRUE)
library(knitr)
library(sn)
library(fMultivar)
library(IDPmisc)
library(psych)
library(tidyverse)
library(scales)
library(rmarkdown)
library(gganimate)
library(ggforce)
library(sjmisc)
library(WJSmisc)
# library(tippy)
library(tikzDevice)
library(patchwork)
library(qualvar)
library(modeest)
library(tinter)
library(ggfx)
library(ggtext)
library(lemon)
library(signs)

library(psycheval)
library(bezier)
library(DescTools)
library(ggh4x)
library(ggthemes)
library(rsvg)
library(ggarrow)
library(arrowheadr)
library(rgl)
knitr::knit_hooks$set(webgl = hook_webgl)
arrow_head_deltoid <- purrr::partial(arrowheadr::arrow_head_deltoid, d = 2.3)
# Set options
options(knitr.kable.digits = 2, knitr.kable.na = '')
knitr::opts_template$set(marginfigure = list(fig.column = "margin", fig.cap.location = "top", out.width = "100%", fig.align = "left"),
                         bodyfigure = list(fig.column = "body", fig.cap.location = "margin"))

# Default fonts and colors
bfont = "Equity Text A Tab"
bsize = 16
myfills <- c("royalblue4", "firebrick4", "#51315E")
txt_color <- "gray20"

btxt_size = ggtext_size(bsize)

# Default geoms and themes
ggplot2::update_geom_defaults(
  "text",
  list(family = bfont, 
       size = btxt_size,
       color = txt_color))
ggplot2::update_geom_defaults(
  "label",
  list(
    family = bfont,
    size = btxt_size,
    label.padding = unit(0, "lines"),
    label.size = 0,
    color = txt_color))

ggplot2::update_geom_defaults(
  "richtext",
  list(family = bfont, 
       size = btxt_size,
       color = txt_color))

ggplot2::update_geom_defaults("density", list(fill = myfills[1]))

theme_set(theme_minimal(base_size = bsize, base_family = bfont))


# font family
span_style <- function(x, style = "font-family:serif") {
  paste0('<span style=\"',
         style,
         '\">',
         x,
         "</span>")
}


# Set table column width
# https://github.com/rstudio/bookdown/issues/122#issuecomment-221101375
html_table_width <- function(kable_output, width, tag = "</caption>"){
  width_html <- paste0(
    paste0('<col width="',
           width,
           '">'),
    collapse = "\n")
  sub(tag,
      paste0(tag,
             "\n",
             width_html),
      kable_output)
}

# Make a matrix with braces
bmatrix <- function(M, brace = "bmatrix", includenames=TRUE) {
  if (includenames) {
    M <- cbind(rownames(M),M)
    M <- rbind(colnames(M), M)
  }
  M <-  paste(apply(M,
                    MARGIN = 1,
                    FUN = paste0,
                    collapse = " & "),
              collapse = "\\\\\n")


  if (!is.null(brace)) {
    M <- paste0("\\begin{",brace,"}\n", M, "\n\\end{", brace , "}")
    }
  M
}

# Hooks -------

# # Enclose collapsible r chunk in  button
# knitr::opts_hooks$set(button_r = function(options) {
#   if (isTRUE(options$button_r)) {
#     options$button_before_r <- TRUE
#     options$button_after <- TRUE
#     options$echo = TRUE
#     options$eval = FALSE
#   }
# 
#   options
# })
# 
# # Enclose collapsible latex chunk in  button
# knitr::opts_hooks$set(button_latex = function(options) {
#   if (isTRUE(options$button_latex)) {
#     options$button_before_latex <- TRUE
#     options$button_after <- TRUE
#     options$echo = TRUE
#     options$eval = FALSE
#   }
# 
#   options
# })

# before button for collapsible r chunk
knit_hooks$set(
  button_before = function(before, options, envir) {
    if (before) {
      if (is.null(options$figlabel)) {
        l <- options$label %>% 
          str_remove("^coder\\-") %>% 
          str_remove("^codelatex\\-") %>% 
          str_remove("^codeojs\\-") 
        if (str_detect(l, "^fig\\-") | str_detect(l, "^tbl\\-")) {
          options$figlabel <- l
        }
        
      } 
      
      codetype <- options$codelabel
      if (!is.null(options$figlabel)) {
        codetype <- paste0(codetype, " for @", options$figlabel)
      } 
      return(
        paste0(
          # '<div class="wrap-collapsible" style="margin-top: 1em">',
          # "\n",
          # '<input id="collapsible-',
          # options$label,
          # '" class="toggle" type="checkbox">',
          # "\n",
          # '<label for="collapsible-',
          # options$label,
          # '" class="lbl-toggle">', codetype,'</label>',
          # '<div class="collapsible-content">',
          # "\n",
          # '<div class="content-inner">'
          ':::{.callout-note collapse="true" appearance="minimal"}\n## ',codetype
        )
      )
    }
  }
)


# After button for collapsible chunks
knit_hooks$set(button_after = function(before, options, envir) {
  # if (!before) return('</div></div></div>')
  if (!before) return('\n:::\n')
})


# Solution chunk
# knitr::opts_hooks$set(solution = function(options) {
#   options$echo <- TRUE
#   options$solutionsetter <- TRUE
#   return(options)
# })

knitr::knit_hooks$set(solutionsetter = function(before,options, envir) {
  
  if (before) {
    
    "\n\n<details><summary>Suggested Solution</summary>\n\n"
  } else {
    
    "\n\n</details>\n\n"
  }
})


# Make all chunks with demo-prefix echo = TRUE

knitr::opts_hooks$set(label = function(options) {
  if (startsWith(options$label, "demo-")) {
    options$echo <- TRUE
  }
  if (startsWith(options$label, "ex-")) {
    options$echo <- TRUE
  }
  if (startsWith(options$label, "solution-")) {
    options$echo <- TRUE
    options$solutionsetter <- TRUE
  }
  if (str_starts(options$label, "code")) {
    options$button_before <- TRUE
    options$button_after <- TRUE
    options$echo = TRUE
    options$eval = FALSE
    codelanguages <- c(r = "R Code", 
                       latex = "$\\small\\rm\\LaTeX$ Code",
                       ojs = "Observable Code")
    mycode <- str_match(options$label, "^code(.*?)\\-")
    if (length(mycode) == 2) {
      options$codelabel = codelanguages[mycode[2]]
    }
  }
  return(options)
})

In addition, all the files and code used to create this book can be found in its Github repository.

To avoid repeated citation, I must note that in preparing this book, I have drawn heavily—and no doubt unconsciously—from many authoritative sources on psychometrics, statistical analysis, and linear algebra (Cohen et al., 2003; Crocker & Algina, 2006; Eaton, 2007; Furr, 2017; Nunnally, 1967; Raykov & Marcoulides, 2011; Strang, 2016). I also owe a debt of gratitude to the many unsung authors at Wikipedia and Mathematica who maintain wonderfully comprehensive, up-to-date, and well-referenced documentation of all things mathematical and statistical.

Cohen, J., Cohen, P., West, S. G., & Aiken, L. S. (2003). Applied multiple regression/correlation analysis for the behavioral sciences. L. Erlbaum Associates.
Crocker, L., & Algina, J. (2006). Introduction to classical and modern test theory. Cengage Learning.
Eaton, M. L. (2007). Multivariate statistics: A vector space approach. Inst. of Mathematical Statistics.
Furr, R. (2017). Psychometrics: An introduction (3rd ed.). Sage.
Nunnally, J. C. (1967). Psychometric theory. McGraw-Hill.
Raykov, T., & Marcoulides, G. A. (2011). Introduction to psychometric theory. Routledge.
Strang, G. (2016). Introduction to linear algebra (5th edition). Cambridge press.