irt_ruby

Item Response Theory Library

Ruby IRT Psychometrics Statistical Modeling

A comprehensive Ruby gem for Item Response Theory (IRT) analysis. Implements Rasch, 2PL (Two-Parameter Logistic), and 3PL (Three-Parameter Logistic) models with support for missing data, adaptive optimization, and detailed psychometric reporting.

7
GitHub Stars
Gem
RubyGems
MIT
License
Ruby
Language

Installation

Add irt_ruby to your Gemfile:

gem 'irt_ruby'

Or install directly:

gem install irt_ruby

Key Features

Multiple IRT Models

Rasch (1PL), 2PL, and 3PL models with full parameter estimation.

Missing Data Support

Robust handling of incomplete response patterns and missing values.

Adaptive Optimization

Advanced optimization algorithms for accurate parameter estimation.

Comprehensive Reports

Detailed psychometric statistics, item fit indices, and ability estimates.

Quick Start - Rasch Model

Here's a simple example using the Rasch (1PL) model:

require 'irt_ruby'

# Response data: rows = examinees, columns = items
# 1 = correct, 0 = incorrect
responses = [
  [1, 1, 1, 0, 0],  # Examinee 1
  [1, 1, 0, 0, 0],  # Examinee 2
  [1, 1, 1, 1, 0],  # Examinee 3
  [0, 0, 1, 0, 0],  # Examinee 4
  [1, 1, 1, 1, 1]   # Examinee 5
]

# Fit Rasch model
rasch = IrtRuby::Rasch.new(responses)
rasch.fit!

# Get item difficulties
puts "Item Difficulties:"
rasch.item_parameters.each_with_index do |difficulty, i|
  puts "Item #{i + 1}: #{difficulty.round(3)}"
end

# Get ability estimates
puts "\nAbility Estimates:"
rasch.ability_estimates.each_with_index do |theta, i|
  puts "Examinee #{i + 1}: #{theta.round(3)}"
end

# Calculate item fit statistics
fit_stats = rasch.item_fit_statistics
puts "\nItem Fit (Infit MNSQ):"
fit_stats[:infit].each_with_index do |infit, i|
  puts "Item #{i + 1}: #{infit.round(3)}"
end

Two-Parameter Logistic (2PL) Model

The 2PL model estimates both difficulty and discrimination parameters:

require 'irt_ruby'

# Larger dataset for 2PL model
responses = [
  [1, 1, 1, 0, 0, 1, 1, 0, 0, 0],
  [1, 1, 0, 0, 0, 1, 0, 0, 0, 0],
  [1, 1, 1, 1, 0, 1, 1, 1, 0, 0],
  [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [1, 0, 1, 0, 0, 1, 1, 0, 0, 0],
  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]

# Fit 2PL model
two_pl = IrtRuby::TwoParameterLogistic.new(responses)
two_pl.fit!(max_iterations: 100, tolerance: 0.001)

# Get item parameters
puts "Item Parameters (Difficulty, Discrimination):"
two_pl.item_parameters.each_with_index do |params, i|
  difficulty = params[:difficulty]
  discrimination = params[:discrimination]
  puts "Item #{i + 1}: b = #{difficulty.round(3)}, a = #{discrimination.round(3)}"
end

# Calculate item information
puts "\nItem Information at θ = 0:"
two_pl.item_information(theta: 0.0).each_with_index do |info, i|
  puts "Item #{i + 1}: #{info.round(3)}"
end

# Test information function
theta_range = (-3.0..3.0).step(0.5).to_a
puts "\nTest Information Function:"
theta_range.each do |theta|
  info = two_pl.test_information(theta)
  se = 1.0 / Math.sqrt(info)
  puts "θ = #{theta.round(1)}: Info = #{info.round(2)}, SE = #{se.round(3)}"
end

Three-Parameter Logistic (3PL) Model

The 3PL model adds a guessing parameter for multiple-choice items:

require 'irt_ruby'

# Multiple-choice test data
responses = [
  [1, 1, 1, 0, 0, 1, 1, 0],
  [1, 1, 1, 1, 0, 1, 1, 1],
  [0, 1, 1, 0, 0, 0, 1, 0],
  [1, 1, 1, 1, 1, 1, 1, 1],
  [0, 0, 1, 0, 0, 0, 0, 0],
  [1, 1, 0, 0, 0, 1, 1, 0]
]

# Fit 3PL model
three_pl = IrtRuby::ThreeParameterLogistic.new(responses)
three_pl.fit!(max_iterations: 150)

# Get all item parameters
puts "Item Parameters (Difficulty, Discrimination, Guessing):"
three_pl.item_parameters.each_with_index do |params, i|
  b = params[:difficulty]
  a = params[:discrimination]
  c = params[:guessing]
  puts "Item #{i + 1}: b = #{b.round(3)}, a = #{a.round(3)}, c = #{c.round(3)}"
end

# Probability of correct response
theta = 0.5  # Ability level
puts "\nProbability of correct response at θ = #{theta}:"
three_pl.item_parameters.each_with_index do |params, i|
  prob = three_pl.probability(theta, params)
  puts "Item #{i + 1}: #{(prob * 100).round(1)}%"
end

# Model fit comparison
puts "\nModel Information:"
puts "Log-Likelihood: #{three_pl.log_likelihood.round(2)}"
puts "AIC: #{three_pl.aic.round(2)}"
puts "BIC: #{three_pl.bic.round(2)}"

Handling Missing Data

irt_ruby gracefully handles incomplete response patterns:

require 'irt_ruby'

# Response data with missing values (nil or :missing)
responses = [
  [1, 1, nil, 0, 0],      # Examinee 1: missing item 3
  [1, nil, 0, 0, nil],     # Examinee 2: missing items 2 and 5
  [1, 1, 1, nil, 0],       # Examinee 3: missing item 4
  [nil, 0, 1, 0, 0],       # Examinee 4: missing item 1
  [1, 1, 1, 1, 1]          # Examinee 5: complete data
]

# Fit model with missing data
rasch = IrtRuby::Rasch.new(responses)
rasch.fit!(handle_missing: :ignore)  # or :impute

# Get estimates (missing data handled automatically)
puts "Ability Estimates (with missing data):"
rasch.ability_estimates.each_with_index do |theta, i|
  completed = responses[i].compact.size
  total = responses[i].size
  puts "Examinee #{i + 1}: θ = #{theta.round(3)} (#{completed}/#{total} items)"
end

# Item statistics with missing data counts
puts "\nItem Statistics:"
rasch.item_statistics.each_with_index do |stats, i|
  puts "Item #{i + 1}:"
  puts "  Responses: #{stats[:n_responses]}"
  puts "  Difficulty: #{stats[:difficulty].round(3)}"
  puts "  P-value: #{stats[:p_value].round(3)}"
end

Use Cases

Educational Testing

Analyze standardized tests, classroom assessments, and student ability levels.

Psychometric Research

Validate psychological assessments, personality tests, and cognitive measures.

Survey Analysis

Analyze survey responses, questionnaires, and attitude scales with precision.

Adaptive Testing

Build computer-adaptive tests (CAT) with real-time ability estimation.

Item Banking

Calibrate and maintain large item banks for test development and equating.

Model Selection

Choose the right IRT model for your data:

Model Parameters Best For
Rasch (1PL) Difficulty Achievement tests with similar discrimination
2PL Difficulty + Discrimination Most educational and psychological tests
3PL Difficulty + Discrimination + Guessing Multiple-choice tests with guessing

Get Started Today