Executive Summary
Reliability of a 5-item scale
Yes, these 5 neuroticism items hang together well enough to score as one scale: Cronbach's alpha is 0.813 (95% CI 0.802 to 0.824)—good internal consistency across 2,694 complete responses. No single item's removal would improve alpha, meaning every item earns its place. The average inter-item correlation of 0.467 falls in the healthy range of 0.15 to 0.50, high enough to share a construct but low enough to avoid redundancy.
Analysis Overview
Internal consistency of a 5-item scale across 2,694 complete responses.
Internal consistency measures how much items in a scale move together, justifying their combination into a single score. Cronbach's alpha ranges from 0 to 1; the usual bands are below 0.5 (unacceptable), 0.5–0.6 (poor), 0.6–0.7 (questionable), 0.7–0.8 (acceptable), 0.8–0.9 (good), and above 0.9 (excellent). This 5-item neuroticism scale achieves 0.813, placing it in the good band. The standardized alpha of 0.814 is nearly identical to the raw alpha of 0.813, indicating the items have comparable spread—no rescaling is needed. A critical caveat: an alpha above 0.95 signals redundancy and near-duplicate items, not scale superiority. Because alpha rises mechanically with each added item, the per-item analysis matters as much as the headline number.
Data Quality
Items used, items dropped, and complete responses retained.
All 2,694 responses were complete across the 5 items; no rows were dropped for missing data and no items were removed as non-numeric or constant. The full dataset entered the reliability calculation. Cronbach's alpha requires identical respondents across every item, so listwise deletion is the standard approach—here it removed zero rows, indicating high data quality and no missing-data burden on the estimate.
Item Analysis
Per-item mean, spread, item-total correlation, and alpha-if-deleted.
| Item | Mean | SD | Item Total Correlation | Alpha If Deleted |
|---|---|---|---|---|
| n1 get angry easily | 2.93 | 1.57 | 0.666 | 0.757 |
| n2 irritated easily | 3.51 | 1.53 | 0.651 | 0.763 |
| n3 have frequent mood swings | 3.22 | 1.6 | 0.673 | 0.755 |
| n4 often feel blue | 3.19 | 1.57 | 0.542 | 0.795 |
| n5 panic easily | 2.97 | 1.62 | 0.487 | 0.812 |
All 5 items correlate at least 0.30 with the rest of the scale, so none is a clear outlier. The strongest item-total correlations are n3 (have frequent mood swings) at 0.673 and n1 (get angry easily) at 0.666; the weakest is n5 (panic easily) at 0.487—still well above the 0.30 floor. Alpha-if-deleted shows that removing n5 would drop alpha to 0.812, the smallest loss; removing n3 would drop it to 0.755, the largest loss. Since no item's removal raises alpha above the observed 0.813, all items contribute positively to scale reliability.
Alpha If Item Removed
The scale's reliability with each item dropped, versus the overall alpha.
Removing any single item lowers the scale's alpha. The item whose removal causes the smallest decline is n5 (panic easily), falling to 0.812—only 0.001 below the overall 0.813. The item whose removal causes the largest decline is n3 (have frequent mood swings), falling to 0.755, a drop of 0.058. Because no item's bar reaches or exceeds the overall alpha of 0.813, the scale is best kept whole; no item is actively hurting reliability.
Inter-Item Correlation Summary
Alpha, standardized alpha, inter-item correlation range, and confidence interval.
| Statistic | Value | Interpretation |
|---|---|---|
| Items in scale | 5 | Number of items summed into the scale. |
| Complete responses | 2,694 | Respondents with a value on every item (listwise complete). |
| Mean inter-item correlation | 0.467 | Average correlation among item pairs — the engine of internal consistency. |
| Lowest inter-item correlation | 0.352 | Weakest pairwise item relationship. |
| Highest inter-item correlation | 0.706 | Strongest pairwise item relationship. |
| Cronbach's alpha (raw) | 0.813 | Internal consistency: good. |
| Standardized alpha | 0.814 | Alpha rescaled as if every item had equal variance — compare to raw. |
| Alpha 95% CI (Feldt) | 0.802 to 0.824 | Range the true alpha plausibly falls in. |
Inter-item correlations range from 0.352 (lowest) to 0.706 (highest), averaging 0.467—a healthy spread that indicates shared measurement of an underlying construct without redundancy. The mean of 0.467 sits comfortably in the ideal 0.15–0.50 band. Raw alpha (0.813) and standardized alpha (0.814) are nearly identical, confirming that items operate on comparable scales. The Feldt 95% confidence interval of 0.802 to 0.824 narrows the plausible range of the true alpha, lending precision to the good-reliability verdict.
Scale Reliability — Cronbach's Alpha
Are a set of survey or test items internally consistent enough to be summed into a single scale? From the wide-format item columns the user maps, this computes Cronbach's alpha with its interpretation band and a Feldt 95% confidence interval, the standardized alpha from the mean inter-item correlation, a full item analysis (mean, spread, corrected item-total correlation, and alpha-if-item-deleted per item), and an inter-item correlation summary.
Why This Method?
Cronbach's alpha is the dominant survey-validation statistic: one number that says whether questions meant to measure the same thing actually hang together. Reporting the item-total correlations and alpha-if-deleted at the same time answers the perennial follow-up — WHICH item to cut when a scale is weak.
What This Analysis Covers
- Cronbach's alpha with interpretation band and confidence interval
- Standardized alpha from the mean inter-item correlation
- Per-item corrected item-total correlation and alpha-if-deleted
- Inter-item correlation summary (mean, min, max)
Standard Library
Platform standard-library module (LAT-1441): runs on ANY dataset via the semantic mapping {item_1..item_N}. All narrative is derived from the user's own column names and computed values.
suppressPackageStartupMessages(library(DT))
suppressPackageStartupMessages(library(htmlwidgets))
suppressPackageStartupMessages(library(arrow))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(rmarkdown))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(tidyr))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(stringr))
suppressPackageStartupMessages(library(lubridate))
suppressPackageStartupMessages(library(broom))
suppressPackageStartupMessages(library(Matrix))
suppressPackageStartupMessages(library(cluster))
suppressPackageStartupMessages(library(data.table))Core Analysis Pipeline
compute_shared <- function(df, params, col_map = list()) {
# === SHARED EXPORTS ===
# initial_rows/final_rows/rows_removed $ row accounting (responses)
# item_names $ named character — semantic -> humanized item names
# used_items $ character — semantic item names used
# dropped_items $ character — excluded items
# dropped_note $ humanized description of drops
# n_incomplete $ responses removed by listwise deletion
# k $ integer — items in the scale
# alpha_raw / alpha_std $ numeric — Cronbach's alpha, standardized alpha
# alpha_ci $ numeric(2) or NULL — Feldt 95% CI
# band $ interpretation band for alpha_raw
# redundancy $ logical — alpha > 0.95
# rbar / r_min / r_max $ inter-item correlation summary
# item_stats_df $ data.frame(item, mean, sd, item_total_correlation, alpha_if_deleted)
# aid_df $ data.frame(item, alpha_if_deleted) — sorted, for the bar
# inter_item_summary_df $ data.frame(statistic, value, interpretation)
# worst_item_name / alpha_del_best / improves $ best single deletion
# low_itc_name $ item with the lowest corrected item-total correlation
# weak_items $ character — items with item-total correlation < 0.30
# metrics / json_output
# === /SHARED EXPORTS ===Step 1: Discover mapped items
initial_rows <- nrow(df)
item_cols <- grep("^item_[0-9]+$", names(df), value = TRUE)
item_cols <- item_cols[order(as.integer(sub("^item_", "", item_cols)))]
if (length(item_cols) < 3) {
stop("Scale reliability needs at least three items mapped(item_1, item_2, item_3). Cronbach's alpha is undefined for fewer.")
}
item_names <- setNames(humanize_semantic(item_cols, col_map), item_cols)Step 2: Coerce numeric (95% rule); drop non-numeric items (report)
dropped_items <- character(0)
dropped_reasons <- character(0)
for (ic in item_cols) {
v <- df[[ic]]
if (!is.numeric(v)) {
conv <- suppressWarnings(as.numeric(as.character(v)))
n_orig <- sum(!is.na(v) & as.character(v) != "")
if (n_orig > 0 && sum(!is.na(conv)) >= 0.95 * n_orig) {
df[[ic]] <- conv
} else {
dropped_items <- c(dropped_items, ic)
dropped_reasons <- c(dropped_reasons, "non-numeric")
next
}
}
}
usable_items <- setdiff(item_cols, dropped_items)
if (length(usable_items) < 3) {
stop(sprintf("Only %d numeric items remained after dropping non-numeric columns — need at least three to assess scale reliability.",
length(usable_items)))
}Step 3: Listwise-complete responses for the item set (report dropped)
M <- df[, usable_items, drop = FALSE]
complete_idx <- stats::complete.cases(M)
n_incomplete <- sum(!complete_idx)
M <- M[complete_idx, , drop = FALSE]Step 4: Drop constant (zero-variance) items — report them
const_items <- usable_items[vapply(usable_items, function(ic) {
vv <- M[[ic]]
is.na(var(vv)) || isTRUE(var(vv) == 0)
}, logical(1))]
if (length(const_items) > 0) {
dropped_items <- c(dropped_items, const_items)
dropped_reasons <- c(dropped_reasons, rep("constant", length(const_items)))
usable_items <- setdiff(usable_items, const_items)
M <- M[, usable_items, drop = FALSE]
}
k <- length(usable_items)
if (k < 3) {
stop(sprintf("Only %d usable items after removing non-numeric and constant columns — need at least three for Cronbach's alpha.", k))
}
final_rows <- nrow(M)
rows_removed <- initial_rows - final_rows
if (final_rows < 10) {
stop(sprintf("Only %d complete responses(no missing item) — need at least 10 to estimate Cronbach's alpha.", final_rows))
}Step 5: Cronbach's alpha
X <- as.matrix(M)
item_vars <- apply(X, 2, var)
total <- rowSums(X)
var_total <- var(total)
if (is.na(var_total) || var_total <= 0) {
stop("The total scale score has no variance — reliability cannot be estimated.")
}
alpha_raw <- (k / (k - 1)) * (1 - sum(item_vars) / var_total)Step 6: Inter-item correlation matrix -> standardized alpha
C <- suppressWarnings(cor(X))
offdiag <- C[upper.tri(C)]
offdiag <- offdiag[is.finite(offdiag)]
rbar <- if (length(offdiag) > 0) mean(offdiag) else NA_real_
r_min <- if (length(offdiag) > 0) min(offdiag) else NA_real_
r_max <- if (length(offdiag) > 0) max(offdiag) else NA_real_
alpha_std <- if (!is.na(rbar)) (k * rbar) / (1 + (k - 1) * rbar) else NA_real_Step 7: Per-item statistics — corrected item-total and alpha-if-deleted
item_mean <- colMeans(X)
item_sd <- apply(X, 2, sd)
item_total_cor <- rep(NA_real_, k)
alpha_del <- rep(NA_real_, k)
for (i in seq_len(k)) {
others <- rowSums(X[, -i, drop = FALSE])
if (!is.na(var(others)) && var(others) > 0) {
item_total_cor[i] <- suppressWarnings(cor(X[, i], others))
}
ki <- k - 1
if (ki >= 2) {
iv <- item_vars[-i]
var_i <- var(others)
if (!is.na(var_i) && var_i > 0) {
alpha_del[i] <- (ki / (ki - 1)) * (1 - sum(iv) / var_i)
}
}
}Step 8: Feldt (1965) F-based 95% CI for alpha (graceful on failure)
alpha_ci <- tryCatch({
df1 <- final_rows - 1
df2 <- (final_rows - 1) * (k - 1)
a2 <- 1 - 0.95
fL <- qf(1 - a2 / 2, df1, df2)
fU <- qf(a2 / 2, df1, df2)
lo <- 1 - (1 - alpha_raw) * fL
hi <- 1 - (1 - alpha_raw) * fU
if (is.finite(lo) && is.finite(hi)) c(lo, hi) else NULL
}, error = function(e) NULL)Step 9: Interpretation band + redundancy caveat
alpha_band <- function(a) {
if (is.na(a)) return("not estimable")
if (a < 0.5) "unacceptable"
else if (a < 0.6) "poor"
else if (a < 0.7) "questionable"
else if (a < 0.8) "acceptable"
else if (a < 0.9) "good"
else "excellent"
}
band <- alpha_band(alpha_raw)
redundancy <- !is.na(alpha_raw) && alpha_raw > 0.95
hn <- unname(item_names[usable_items])Step 10: Assemble item tables (NA-safe extremes)
item_stats_df <- data.frame(
item = hn,
mean = round(item_mean, 2),
sd = round(item_sd, 2),
item_total_correlation = round(item_total_cor, 3),
alpha_if_deleted = round(alpha_del, 3),
stringsAsFactors = FALSE
)
rownames(item_stats_df) <- NULL
weak_mask <- !is.na(item_stats_df$item_total_correlation) &
item_stats_df$item_total_correlation < 0.30
weak_items <- item_stats_df$item[weak_mask]
aid_df <- data.frame(item = hn, alpha_if_deleted = round(alpha_del, 3),
stringsAsFactors = FALSE)
aid_df <- aid_df[order(-aid_df$alpha_if_deleted, na.last = TRUE), , drop = FALSE]
rownames(aid_df) <- NULLBest single deletion — NEVER which.max over an all-NA vector
ok_del <- which(!is.na(alpha_del))
if (length(ok_del) > 0) {
best_i <- ok_del[which.max(alpha_del[ok_del])]
worst_item_name <- hn[best_i]
alpha_del_best <- alpha_del[best_i]
improves <- !is.na(alpha_del_best) && alpha_del_best > alpha_raw
} else {
worst_item_name <- NA_character_; alpha_del_best <- NA_real_; improves <- FALSE
}
ok_itc <- which(!is.na(item_total_cor))
low_itc_name <- if (length(ok_itc) > 0) hn[ok_itc[which.min(item_total_cor[ok_itc])]] else NA_character_
ci_txt <- if (!is.null(alpha_ci)) sprintf("%.3f to %.3f", alpha_ci[1], alpha_ci[2]) else "not computable for this data"
inter_item_summary_df <- data.frame(
statistic = c("Items in scale", "Complete responses",
"Mean inter-item correlation", "Lowest inter-item correlation",
"Highest inter-item correlation", "Cronbach's alpha (raw)",
"Standardized alpha", "Alpha 95% CI(Feldt)"),
value = c(
format(k, big.mark = ","),
format(final_rows, big.mark = ","),
if (is.na(rbar)) "n/a" else sprintf("%.3f", rbar),
if (is.na(r_min)) "n/a" else sprintf("%.3f", r_min),
if (is.na(r_max)) "n/a" else sprintf("%.3f", r_max),
sprintf("%.3f", alpha_raw),
if (is.na(alpha_std)) "n/a" else sprintf("%.3f", alpha_std),
ci_txt
),
interpretation = c(
"Number of items summed into the scale.",
"Respondents with a value on every item(listwise complete).",
"Average correlation among item pairs — the engine of internal consistency.",
"Weakest pairwise item relationship.",
"Strongest pairwise item relationship.",
paste0("Internal consistency: ", band, "."),
"Alpha rescaled as if every item had equal variance — compare to raw.",
"Range the true alpha plausibly falls in."
),
stringsAsFactors = FALSE
)
dropped_note <- if (length(dropped_items) > 0) {
parts <- character(0)
nn <- sum(dropped_reasons == "non-numeric")
nc <- sum(dropped_reasons == "constant")
if (nn > 0) parts <- c(parts, sprintf("%d non-numeric", nn))
if (nc > 0) parts <- c(parts, sprintf("%d constant", nc))
dn <- humanize_semantic(dropped_items, col_map)
paste0(length(dropped_items), " mapped item",
if (length(dropped_items) == 1) "" else "s", " dropped(",
paste(parts, collapse = ", "), "): ", paste(dn, collapse = ", "), ". ")
} else "All mapped items were usable. "
metrics <- list(
`Items` = k,
`Responses` = final_rows,
`Cronbachs Alpha` = round(alpha_raw, 3),
`Reliability` = band,
`Standardized Alpha`= if (is.na(alpha_std)) NA_real_ else round(alpha_std, 3),
`Mean Inter-Item r` = if (is.na(rbar)) NA_real_ else round(rbar, 3)
)
improve_answer <- if (isTRUE(improves)) {
paste0("Dropping ", worst_item_name, " would raise alpha to ",
round(alpha_del_best, 3), ".")
} else {
"No single item's removal would raise alpha."
}
json_output <- list(
answer = paste0(
"Cronbach's alpha across ", k, " items and ", format(final_rows, big.mark = ","),
" complete responses is ", round(alpha_raw, 3), " — ", band,
" internal consistency",
if (!is.null(alpha_ci)) paste0(" (95% CI ", ci_txt, ")") else "", ". ",
"The standardized alpha is ",
if (is.na(alpha_std)) "not estimable" else round(alpha_std, 3),
" and the mean inter-item correlation is ",
if (is.na(rbar)) "not estimable" else round(rbar, 3), ". ",
improve_answer,
if (redundancy) " Alpha above 0.95 may signal redundant, near-duplicate items." else ""
),
cards = lapply(
c("tldr", "overview", "preprocessing", "item_statistics",
"alpha_if_deleted", "inter_item"),
function(cid) list(id = cid, metrics = metrics)
)
)
list(
initial_rows = initial_rows, final_rows = final_rows,
rows_removed = rows_removed, n_incomplete = n_incomplete,
item_names = item_names, used_items = usable_items,
dropped_items = dropped_items, dropped_reasons = dropped_reasons,
dropped_note = dropped_note,
k = k, alpha_raw = alpha_raw, alpha_std = alpha_std, alpha_ci = alpha_ci,
ci_txt = ci_txt, band = band, redundancy = redundancy,
rbar = rbar, r_min = r_min, r_max = r_max,
item_stats_df = item_stats_df, aid_df = aid_df,
inter_item_summary_df = inter_item_summary_df,
weak_items = weak_items,
worst_item_name = worst_item_name, alpha_del_best = alpha_del_best,
improves = improves, low_itc_name = low_itc_name,
metrics = metrics, json_output = json_output
)
}