因子分析適合處理這樣一類社會科學研究問題:問卷中有許多彼此相關的題項,但研究者希望將它們歸并為少數幾個具有理論含義的潛在維度。例如,多個關于學習投入、學業壓力或組織認同的題項,可能分別反映更少數量的潛在因子。使用 R 完成因子分析時,真正困難的地方通常不在于運行一條函數,而在于確定哪些變量可以進入模型、提取幾個因子、如何解釋載荷,以及如何把分析結果轉化為后續回歸或結構模型中的變量。

下面以問卷題項為例,介紹一套可以寫入論文方法部分的完整流程。示例中的變量名使用 q1、q2 等占位符,實際分析時應替換為自己的題項名稱。

一、先明確因子分析的研究目的

因子分析不是簡單的“把變量壓縮成幾個變量”。在開始運行 R 之前,應先回答兩個問題。

第一,題項是否具有共同的潛在結構?如果每個題項都在測量完全不同的內容,強行進行因子分析并不能產生有意義的因子。

第二,因子結果將如何用于后續研究?如果因子分數要進入回歸、相關分析或組間比較,就需要在提取因子時關注穩定性、解釋性和可復現性,而不能只選擇能夠最大限度解釋方差的方案。

社會科學問卷中的題項通常來自理論構念,因此因子數量不能完全交給統計軟件決定。統計指標可以幫助判斷合理范圍,但最終方案應同時考慮理論預期、題項內容和載荷結果。

二、導入數據并檢查變量編碼

假設數據保存在一個數據文件中,且每一行代表一名受訪者,每一列代表一個題項。首先導入數據,并檢查數據的基本結構。

# 讀取數據
dat <- read.csv("survey_data.csv",
                stringsAsFactors = FALSE,
                na.strings = c("", "NA", "N/A", "缺失"))

# 查看數據結構
str(dat)
dim(dat)
head(dat)

# 查看每個變量的缺失數量
colSums(is.na(dat))

因子分析所使用的變量應當是數值型。如果問卷答案被讀成字符或因子,需要先轉換為數值。需要特別小心的是,直接使用 as.numeric() 轉換因子變量,可能得到內部編碼,而不是題項原本的分值。

# 查看變量類型
sapply(dat, class)

# 如果原始變量是字符型,確認其內容確實為數值后再轉換
items <- c("q1", "q2", "q3", "q4", "q5", "q6",
           "q7", "q8", "q9", "q10")

dat[items] <- lapply(dat[items], function(x) {
  as.numeric(trimws(x))
})

# 檢查轉換后的取值
lapply(dat[items], function(x) sort(unique(x)))

如果題項采用五級或七級量表,應確認所有變量的編碼方向一致。例如,有些題目分值越高表示認同程度越高,另一些反向題可能分值越高表示認同程度越低。反向題如果未處理,會降低相關性,甚至導致因子結構被錯誤分裂。

以五點量表為例,假設 q3 和 q7 是反向題:

# 五點量表的反向計分
dat$q3_r <- 6 - dat$q3
dat$q7_r <- 6 - dat$q7

# 后續使用反向處理后的變量
items <- c("q1", "q2", "q3_r", "q4", "q5",
           "q6", "q7_r", "q8", "q9", "q10")

反向計分公式必須根據量表范圍調整。對于最低分為 min_score、最高分為 max_score 的量表,反向后的分數通常可按下式計算:

dat$reverse_item <- max_score + min_score - dat$original_item

不要在沒有核對問卷編碼說明的情況下直接反向處理題項。題目措辭中的否定表達,并不一定意味著需要反向計分,最終應以量表設計和編碼規則為準。

三、篩選進入模型的題項

檢查取值范圍和異常編碼

先檢查每個題項的最小值、最大值、均值和缺失情況。

item_summary <- data.frame(
  variable = items,
  n = sapply(dat[items], function(x) sum(!is.na(x))),
  missing = sapply(dat[items], function(x) sum(is.na(x))),
  min = sapply(dat[items], function(x) min(x, na.rm = TRUE)),
  max = sapply(dat[items], function(x) max(x, na.rm = TRUE)),
  mean = sapply(dat[items], function(x) mean(x, na.rm = TRUE)),
  sd = sapply(dat[items], function(x) sd(x, na.rm = TRUE))
)

item_summary

如果量表范圍為一到五,卻出現了九十九、負值或其他異常編碼,應先將這些編碼轉換為缺失值,再進行分析。

invalid_codes <- c(99, 999, -9)

dat[items] <- lapply(dat[items], function(x) {
  x[x %in% invalid_codes] <- NA
  x
})

不能把異常編碼當成普通分值參與相關矩陣計算,否則相關系數和因子載荷都可能失真。

檢查題項之間的相關性

因子分析要求題項之間存在一定程度的相關。如果所有題項之間都幾乎沒有相關性,提取出的因子通常缺少解釋意義。

cor_mat <- cor(dat[items],
               use = "pairwise.complete.obs",
               method = "pearson")

round(cor_mat, 2)

如果使用成對刪除處理缺失值,不同相關系數可能基于不同的樣本量。缺失較多時,應在報告中說明缺失處理方式,并檢查相關矩陣是否仍然穩定。對于題項缺失較少的情況,也可以使用完整案例進行分析:

dat_complete <- dat[complete.cases(dat[items]), ]

cor_mat_complete <- cor(dat_complete[items],
                        method = "pearson")

round(cor_mat_complete, 2)

不能僅憑某一個相關系數決定刪除題項。題項之間的相關性還要結合題目內容、理論歸屬和后續載荷共同判斷。

四、評估數據是否適合因子分析

計算 KMO 指標

KMO 指標用于比較題項之間的普通相關與偏相關。整體 KMO 越高,說明題項之間更可能存在共同因子結構。下面使用 R 代碼計算整體 KMO 和各題項的 KMO。

kmo_result <- function(R) {
  R_inv <- solve(R)

  # 由逆相關矩陣計算偏相關矩陣
  P <- -R_inv / sqrt(outer(diag(R_inv), diag(R_inv)))
  diag(P) <- 1

  r2 <- R^2
  p2 <- P^2

  # 去除對角線
  diag(r2) <- 0
  diag(p2) <- 0

  overall_kmo <- sum(r2) / (sum(r2) + sum(p2))
  item_kmo <- rowSums(r2) / (rowSums(r2) + rowSums(p2))

  list(
    overall = overall_kmo,
    item = item_kmo
  )
}

kmo <- kmo_result(cor_mat_complete)

kmo$overall
kmo$item

KMO 較低時,先不要急于刪除變量。應檢查是否存在以下問題:題項內容本身不屬于同一構念、反向題沒有正確處理、樣本量過少、變量取值幾乎沒有變化,或者相關矩陣存在嚴重異常。

計算 Bartlett 球形檢驗

Bartlett 球形檢驗用于檢驗相關矩陣是否顯著不同于單位矩陣。其原假設是各題項之間不存在總體相關。

bartlett_test <- function(R, n) {
  p <- ncol(R)
  determinant_value <- det(R)

  chi_square <- -(n - 1 - (2 * p + 5) / 6) *
    log(determinant_value)

  df <- p * (p - 1) / 2
  p_value <- pchisq(chi_square, df = df, lower.tail = FALSE)

  data.frame(
    chi_square = chi_square,
    df = df,
    p_value = p_value
  )
}

bartlett_test(
  R = cor_mat_complete,
  n = nrow(dat_complete)
)

如果相關矩陣接近單位矩陣,因子分析通常缺乏基礎。相反,檢驗顯著也不能單獨證明因子分析一定合理,因為樣本量較大時,很小的相關也可能達到顯著水平。因此,KMO、相關矩陣、題項內容和后續因子載荷應結合判斷。

五、確定因子數量

因子數量是因子分析中最需要研究者判斷的環節之一。可以先比較理論預期和不同因子數量下的模型表現,再觀察結果是否具有清晰解釋。

使用特征值進行初步判斷

eigen_result <- eigen(cor_mat_complete)

eigen_values <- eigen_result$values

data.frame(
  factor = seq_along(eigen_values),
  eigenvalue = eigen_values,
  explained_percent = eigen_values / sum(eigen_values) * 100,
  cumulative_percent = cumsum(eigen_values / sum(eigen_values) * 100)
)

特征值可以幫助觀察相關矩陣中主要維度的數量,但不應機械地把特征值大于一的維度全部保留。該標準容易在題項較多時提取過多因子,也可能產生難以解釋的結構。

比較不同因子數量的可解釋性

假設理論上可能存在二到四個因子,可以分別運行模型:

fa_2 <- factanal(
  x = dat_complete[items],
  factors = 2,
  rotation = "promax",
  scores = "regression"
)

fa_3 <- factanal(
  x = dat_complete[items],
  factors = 3,
  rotation = "promax",
  scores = "regression"
)

fa_4 <- factanal(
  x = dat_complete[items],
  factors = 4,
  rotation = "promax",
  scores = "regression"
)

fa_2
fa_3
fa_4

比較時重點關注以下問題:

  • 每個因子是否至少有若干個具有清晰載荷的題項;
  • 同一個因子中的題項是否具有共同的理論含義;
  • 是否存在一個因子只有一個題項或極少題項;
  • 是否有大量題項在多個因子上同時具有較高載荷;
  • 增加因子后,解釋是否變得更清晰,還是只是把相近題項機械拆開。

如果多個因子之間理論上可能相關,應優先考慮斜交旋轉,例如 promax。如果研究者有充分理由認為因子彼此獨立,可以考慮正交旋轉,例如 varimax。社會科學構念往往存在相關,因此不應默認所有因子完全獨立。

六、運行因子分析并選擇旋轉方式

使用最大似然法提取因子

factanal() 可以使用最大似然方法提取因子。下面以三個因子為例:

fa_model <- factanal(
  x = dat_complete[items],
  factors = 3,
  rotation = "promax",
  scores = "regression"
)

print(fa_model,
      cutoff = 0.30,
      sort = TRUE)

cutoff = 0.30 只影響打印結果,不會改變模型本身。為了判斷題項在不同因子上的真實表現,也可以直接查看載荷矩陣:

loadings_matrix <- as.matrix(fa_model$loadings)

round(loadings_matrix, 3)

載荷可以理解為題項與因子的關系強度。載荷絕對值較高,通常說明題項與該因子聯系較緊密,但不能只根據某個統一數值機械刪除題項。載荷的解釋還需要結合題項內容、樣本量、因子數量和理論預期。

比較正交旋轉與斜交旋轉

fa_varimax <- factanal(
  x = dat_complete[items],
  factors = 3,
  rotation = "varimax",
  scores = "regression"
)

fa_promax <- factanal(
  x = dat_complete[items],
  factors = 3,
  rotation = "promax",
  scores = "regression"
)

round(as.matrix(fa_varimax$loadings), 3)
round(as.matrix(fa_promax$loadings), 3)

如果使用斜交旋轉,應同時查看因子之間的相關矩陣:

fa_promax$Phi

因子之間存在相關并不代表模型失敗。相反,如果理論上相關的構念在斜交旋轉后顯示出一定相關,往往比強行使用正交旋轉更符合研究對象。報告中應說明提取方法、旋轉方法和選擇該方法的理由。

七、讀取并解釋因子載荷

為了更清楚地識別每個題項主要歸屬的因子,可以整理載荷矩陣。

loading_df <- as.data.frame(unclass(fa_model$loadings))

loading_df$item <- rownames(loading_df)

loading_df <- loading_df[, c("item",
                             setdiff(names(loading_df), "item"))]

loading_df

還可以為每個題項標記絕對載荷最大的因子:

factor_columns <- setdiff(names(loading_df), "item")

loading_df$primary_factor <- factor_columns[
  apply(abs(loading_df[factor_columns]), 1, which.max)
]

loading_df$primary_loading <- apply(
  abs(loading_df[factor_columns]),
  1,
  max
)

loading_df

解釋載荷時,至少要關注三種情況。

第一,題項在某個因子上的主要載荷較高,且在其他因子上的載荷較低。這類題項通常有較清晰的歸屬。

第二,題項在兩個或多個因子上的載荷都較高。這說明題項可能同時反映多個構念,也可能存在題目表述過于寬泛、反向題處理錯誤或因子數量設定不合適等問題。此時不能只看統計結果,還要回到題目內容判斷是否保留。

第三,題項在所有因子上的載荷都較低。這類題項可能沒有充分反映共同構念,但也應先檢查數據編碼、缺失處理和量表方向,再考慮刪除。

因子命名應根據同一因子下題項的共同含義完成,而不是根據軟件自動生成的編號決定。因子編號本身沒有實質意義,旋轉或重新運行模型后,因子編號可能改變。

例如,如果某個因子上的題項都圍繞“主動參與課堂、投入學習時間和完成學習任務”,可以將其命名為“學習投入”。論文中應說明命名依據,并列出構成該因子的主要題項。

八、處理題項刪除與模型重估

刪除題項不能只因為它的載荷低。一個較穩妥的處理過程是:先發現問題,再核對題目內容,刪除后重新估計模型,最后比較新舊結構是否更合理。

# 假設經過理論判斷后,刪除 q5 和 q8
items_reduced <- setdiff(items, c("q5", "q8"))

dat_reduced <- dat_complete[items_reduced]

fa_reduced <- factanal(
  x = dat_reduced,
  factors = 3,
  rotation = "promax",
  scores = "regression"
)

print(fa_reduced,
      cutoff = 0.30,
      sort = TRUE)

刪除題項后,應重新檢查相關矩陣、KMO、因子數量和載荷結構。不能先反復刪除變量,直到輸出結果看起來“漂亮”為止。過度根據當前樣本調整題項,會增加結果對特定樣本的依賴,也可能削弱量表的內容效度。

如果刪除某個題項只是為了提高某個統計指標,卻使理論構念的重要內容缺失,通常不應刪除。論文中還應記錄刪除依據,而不是只報告最終保留下來的題項。

九、提取因子得分并構建后續變量

完成因子結構確認后,可以提取每位受訪者的因子得分。使用 scores = "regression" 后,因子得分通常保存在模型對象的 scores 中。

factor_scores <- as.data.frame(fa_model$scores)

head(factor_scores)
summary(factor_scores)

將因子得分合并回原始數據:

dat_analysis <- cbind(
  dat_complete,
  factor_scores
)

head(dat_analysis)

為了讓變量名更容易用于后續分析,可以重命名:

names(factor_scores) <- c(
  "learning_engagement",
  "academic_pressure",
  "institutional_support"
)

dat_analysis <- cbind(
  dat_complete,
  factor_scores
)

因子得分通常是標準化形式,均值接近零。它們適合用于后續回歸或相關分析,但解釋時應明確說明:系數反映的是潛在因子得分變化與結果變量之間的關系,而不是原始問卷分值的直接變化。

除了模型估計的因子得分,也可以根據題項均值或總分構建量表得分。這種方法更容易解釋,但前提是題項已經確認屬于同一個因子,并且缺失處理規則已經確定。

engagement_items <- c("q1", "q2", "q4")

dat_analysis$engagement_mean <- rowMeans(
  dat_analysis[engagement_items],
  na.rm = TRUE
)

使用 rowMeans(..., na.rm = TRUE) 時要注意:如果某一行所有題項都是缺失,結果可能不符合預期。可以先設置最低有效題項數量。

row_mean_min <- function(x, min_valid = 2) {
  valid_n <- rowSums(!is.na(x))
  result <- rowMeans(x, na.rm = TRUE)
  result[valid_n < min_valid] <- NA
  result
}

dat_analysis$engagement_mean <- row_mean_min(
  dat_analysis[engagement_items],
  min_valid = 2
)

因子得分和題項均值不是同一個變量。前者由模型估計,考慮了題項之間的關系;后者直接反映題項答案的平均水平。研究者應根據研究目的和論文中的變量定義選擇一種,并在全文保持一致。

十、將因子結果用于后續分析

如果后續需要把因子結果用于回歸分析,可以直接使用已經生成的因子變量。下面的代碼僅展示變量進入模型的方式,具體結果應根據自己的研究設計確定。

model <- lm(
  outcome ~ learning_engagement +
    academic_pressure +
    institutional_support +
    age +
    gender,
  data = dat_analysis
)

summary(model)

如果因子之間存在較高相關,應在解釋回歸結果時保持謹慎。高度相關的因子可能使回歸系數不穩定,也可能導致單個因子的解釋與零階相關不一致。此時應回到因子相關矩陣和研究理論,確認這些因子是否確實代表可以區分的構念。

在構建后續變量之前,還應檢查因子得分是否存在大量缺失、極端分布或與原始題項方向不一致。

sapply(dat_analysis[c(
  "learning_engagement",
  "academic_pressure",
  "institutional_support"
)], function(x) {
  c(
    missing = sum(is.na(x)),
    mean = mean(x, na.rm = TRUE),
    sd = sd(x, na.rm = TRUE)
  )
})

十一、常見錯誤及排查方法

報錯“相關矩陣不是正定矩陣”

這通常意味著題項之間存在完全重復、近乎重復,或者某些變量之間存在嚴重線性關系。可以先檢查相關矩陣:

round(cor_mat_complete, 3)

重點查看是否有兩個題項的相關系數接近一。如果存在,應核對這兩個題項是否重復、是否被錯誤復制,或是否實際上測量了完全相同的內容。也要檢查變量方差:

sapply(dat_complete[items], var, na.rm = TRUE)

方差為零或極低的題項沒有足夠的信息參與因子分析。

factanal() 無法收斂

無法收斂可能與因子數量過多、樣本信息不足、相關矩陣異常或題項之間高度共線有關。可以先減少因子數量,檢查數據和相關矩陣,再比較不同旋轉方式。如果某些題項存在極端分布或幾乎沒有變化,也應優先處理這些變量。

不要把增加迭代次數當成唯一解決辦法。即使模型最終收斂,如果因子數量和題項結構本身不合理,結果仍然可能無法解釋。

結果中出現 Heywood 情況

如果某個題項的獨特性接近零,或者模型估計出的共同度異常偏高,可能存在 Heywood 情況。這通常提示模型設定不合適、題項高度重復、因子數量不合理或數據規模不足。

fa_model$uniquenesses

發現異常時,應檢查相關矩陣、因子數量和題項內容,必要時重新設定模型。不能簡單把異常結果當作“題項質量很好”。

反向題載荷方向相反

因子載荷為負不一定意味著模型錯誤。它可能反映題項方向與其他題項相反,也可能是反向計分未完成。先核對原始問卷編碼和反向處理過程,再決定是否需要調整。

如果只是整個因子的方向相反,而同一因子內各題項關系一致,可以在解釋時統一方向;如果同一因子內部載荷正負混雜,則應重點檢查題項編碼和因子結構。

缺失值導致樣本量變化

complete.cases() 會刪除任一分析題項缺失的受訪者,題項較多時可能損失較多樣本。pairwise.complete.obs 雖然可以保留更多相關系數,但不同相關系數的樣本量可能不同,相關矩陣有時會變得不穩定。

因此,論文中應明確報告缺失值處理方法、最終分析樣本量,以及該處理方式可能帶來的限制。不能在不同步驟中隨意切換缺失處理方式而不記錄。

十二、如何撰寫可復現的分析報告

一份可復現的因子分析報告,應讓讀者知道數據如何進入模型、模型如何設定,以及最終因子如何被解釋和使用。建議至少交代以下內容:

  • 分析對象、題項數量和題項的計分范圍;
  • 反向題的處理方式;
  • 缺失值和異常編碼的處理方式;
  • 題項進入或退出模型的依據;
  • KMO 和 Bartlett 球形檢驗結果;
  • 因子數量的判斷依據;
  • 因子提取方法和旋轉方法;
  • 主要題項在各因子上的載荷;
  • 因子命名的理論依據;
  • 因子得分或量表均值如何構建;
  • 因子變量如何進入后續分析。

為了保留分析過程,可以將關鍵代碼和模型對象保存下來:

analysis_record <- list(
  items = items,
  correlation_matrix = cor_mat_complete,
  eigenvalues = eigen_values,
  factor_model = fa_model,
  loadings = as.matrix(fa_model$loadings),
  factor_scores = fa_model$scores
)

saveRDS(analysis_record, file = "factor_analysis_record.rds")

也可以保存整理后的載荷表:

write.csv(
  loading_df,
  file = "factor_loadings.csv",
  row.names = FALSE
)

論文中不必逐行展示全部代碼,但應保留能夠復現主要結果的腳本、變量篩選記錄和模型設定。尤其要避免只報告最終因子名稱,卻不說明題項刪除和因子數量選擇過程。

因子分析的最終目標不是得到一張載荷表,而是建立一個有理論依據、統計結構清晰、能夠用于后續研究的變量體系。只要數據編碼、題項篩選、因子數量、旋轉方式和變量構建都被完整記錄,研究者就能在 R 中重復運行分析,并讓論文讀者理解每一個因子結果是如何形成的。

聲明:本站所有文章,如無特殊說明或標注,均為本站原創發布。任何個人或組織,在未征得本站同意時,禁止復制、盜用、采集、發布本站內容到任何網站、書籍等各類媒體平臺。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。