選擇統計方法

ESCS 是單一的連續變項,題目要的是描述這批資料的集中和分散,不是比較組別,也不是做推論檢定。集中量數用平均數和中位數,變異性用標準差、全距和 IQR。平均數與標準差適合大致對稱的連續分布;中位數與 IQR 比較不受兩端極端值影響。兩組一起算,才能看出這份資料適不適合只看平均數。

資料型態判斷

ESCS(Index of economic, social and cultural status)是經濟、社會與文化地位的綜合指數。PISA 把它量成連續分數,OECD 平均大約是 0、標準差大約是 1,所以低於平均的人會是負數,負數不是錯誤代碼。

它不是類別,不能用次數分配當主要結果;它也不是只能取整數的次數,所以用平均數、標準差、分位數,而不是只數每一格有幾人。檔案標籤裡的 95、97、98、99 是跳答、不適用、無效、未答。這些代碼若留在資料裡,平均數和全距都會被拉得很誇張,所以分析前要先改成遺漏值。

載入套件

haven 用來讀 SPSS 的 .sav。dplyr 用來挑欄位、改代碼、算摘要。ggplot2 畫分布圖,方便對照平均數和中位數;本題的圖表說明是略,圖只是用來核對形狀。knitr 的 kable() 把表排整齊。moments 算偏態。

Windows 的繪圖裝置不認得「微軟正黑體」這個名字,所以先用 windowsFonts() 登記成 JhengHei,圖上的中文才不會變方框。theme_set() 是把後面所有圖的底色、字級一次設好。

library(haven)
library(dplyr)
library(ggplot2)
library(knitr)
library(moments)

if (.Platform$OS.type == "windows") {
  windowsFonts(JhengHei = windowsFont("Microsoft JhengHei"))
  base_family <- "JhengHei"
} else {
  base_family <- ""
}
theme_set(
  theme_minimal(base_size = 12, base_family = base_family) +
    theme(
      plot.title = element_text(face = "bold"),
      panel.grid.minor = element_blank()
    )
)

讀檔,並把特殊代碼改成遺漏

read_sav() 讀進 PISA_tawian2022_trimmed_lab.sav。%>% 是把左邊的結果交給右邊。transmute() 只留下 ESCS。as.numeric() 拿掉 SPSS 的標籤,讓後面的平均數、分位數都用數字計算。if_else() 把 95、97、98、99 改成 NA。這份檔案裡其實沒有這些代碼,還是先處理,避免以後被當成真實分數。

最後的 cat() 印出有效人數和遺漏人數,用來確認資料有讀進來。

raw <- read_sav("PISA_tawian2022_trimmed_lab.sav")

dat <- raw %>%
  transmute(
    escs = if_else(ESCS %in% c(95, 97, 98, 99), NA_real_, as.numeric(ESCS))
  )

cat("有效樣本:", sum(!is.na(dat$escs)),
    ";遺漏:", sum(is.na(dat$escs)), "\n")
## 有效樣本: 5599 ;遺漏: 0

描述統計

summarise() 一次算出人數、平均數、標準差、最小最大值。全距是最大值減最小值,所以直接用同一個 summarise() 裡剛算出來的 max 和 min。中位數用 median()。quantile() 取 25% 和 75%,IQR 用 IQR(),也就是第三四分位數減第一四分位數。moments::skewness() 用來判斷分布歪不歪;偏態接近 0 表示大致對稱。across() 把表上的數字四捨五入到小數兩位,再交給 kable()。

escs_stats <- dat %>%
  summarise(
    人數 = sum(!is.na(escs)),
    平均數 = mean(escs, na.rm = TRUE),
    標準差 = sd(escs, na.rm = TRUE),
    最小值 = min(escs, na.rm = TRUE),
    最大值 = max(escs, na.rm = TRUE),
    全距 = 最大值 - 最小值,
    中位數 = median(escs, na.rm = TRUE),
    Q1 = quantile(escs, 0.25, na.rm = TRUE),
    Q3 = quantile(escs, 0.75, na.rm = TRUE),
    IQR = IQR(escs, na.rm = TRUE),
    偏態 = moments::skewness(escs, na.rm = TRUE)
  )

kable(
  escs_stats %>% mutate(across(where(is.numeric), \(x) round(x, 2))),
  caption = "ESCS 的集中量數與變異性(小數兩位)"
)
ESCS 的集中量數與變異性(小數兩位)
人數 平均數 標準差 最小值 最大值 全距 中位數 Q1 Q3 IQR 偏態
5599 -0.27 0.91 -3.84 4.21 8.05 -0.24 -0.94 0.44 1.38 -0.18

直方圖的 binwidth = 0.25 是每一柱寬 0.25 分。aes(y = after_stat(density)) 把縱軸改成密度,這樣才能和 geom_density() 的曲線畫在同一張圖上。兩條直線分別是平均數和中位數。盒形圖用 geom_boxplot(),盒子的高度就是 IQR。

ggplot(dat, aes(x = escs)) +
  geom_histogram(
    aes(y = after_stat(density)),
    binwidth = 0.25,
    fill = "#4C78A8",
    color = "white",
    boundary = 0
  ) +
  geom_density(linewidth = 0.8, color = "#E45756") +
  geom_vline(xintercept = escs_stats$平均數, linetype = "dashed", color = "#E45756") +
  geom_vline(xintercept = escs_stats$中位數, linetype = "dotted", color = "#72B7B2") +
  labs(
    title = "ESCS 分布",
    subtitle = "紅虛線 = 平均數;青點線 = 中位數",
    x = "ESCS",
    y = "密度"
  )

ggplot(dat, aes(x = "", y = escs)) +
  geom_boxplot(fill = "#4C78A8", width = 0.35, outlier.alpha = 0.35) +
  labs(title = "ESCS 盒形圖", x = NULL, y = "ESCS")

資料分析摘要

有效樣本 5599 人,沒有遺漏。平均數是 -0.27,標準差是 0.91。最小值 -3.84,最大值 4.21,全距 8.05。中位數是 -0.24。中間 50% 落在 Q1 -0.94 到 Q3 0.44,IQR 是 1.38。偏態 -0.18,接近 0。

平均數和中位數很接近,直方圖是中間高、兩邊下降,所以這份資料大致對稱、略為左偏。標準差約 0.91,和 PISA 國際量尺的 1 差不多,表示臺灣樣本內部的差異並沒有特別窄。全距有 8.05,是因為兩端有離平均很遠的人;IQR 只有 1.38,代表大多數人其實集中在大約 1.4 分的範圍裡。看變異性時,全距會被極端值拉大,IQR 和標準差比較能代表中間多數人的分散程度。