Total Sampel (N): 538
3 Analisis Deskriptif
Bagian ini menyajikan statistik deskriptif untuk profil demografi responden, peta sebaran wilayah, dan statistik level item (Mean, SD, Skewness, Kurtosis).
3.1 Statistik Deskriptif Demografi
3.1.1 Jumlah Sampel
3.1.2 Jenis Kelamin
3.1.3 Usia
3.1.4 Semester
Kode
| Kategori | Frekuensi | Persentase |
|---|---|---|
| Semester 1-2 | 174 | 32.34% |
| Semester 2-3 | 64 | 11.9% |
| Semester 3-4 | 157 | 29.18% |
| Semester 5-6 | 70 | 13.01% |
| Semester 7 atau Lebih | 73 | 13.57% |
3.1.4.1 Semester (Recode 3 Kategori)
Kode
data$Semester_Recode <- ifelse(data$Semester == 1, "Semester Awal (1-2)",
ifelse(data$Semester %in% c(2, 3), "Semester Menengah (3-4)", "Semester Lanjut (>=5)"))
sem_recode_freq <- table(data$Semester_Recode, useNA = "ifany")
sem_recode_pct <- prop.table(sem_recode_freq) * 100
knitr::kable(data.frame(
Kategori = names(sem_recode_freq), Frekuensi = as.numeric(sem_recode_freq),
Persentase = paste0(round(sem_recode_pct, 2), "%"), check.names = FALSE
), caption = "Semester (Recoded — 3 Kategori)", row.names = FALSE)| Kategori | Frekuensi | Persentase |
|---|---|---|
| Semester Awal (1-2) | 174 | 32.34% |
| Semester Lanjut (>=5) | 143 | 26.58% |
| Semester Menengah (3-4) | 221 | 41.08% |
3.1.5 Area Tempat Tinggal
3.1.6 Tipe Hunian
3.1.7 Pengetahuan Lingkungan
3.1.8 Lama Bergabung dengan Organisasi Lingkungan
3.1.9 Provinsi
Kode
| Kategori | Frekuensi | Persentase |
|---|---|---|
| Jawa Barat | 33 | 6.13% |
| Jawa Tengah | 263 | 48.88% |
| Jawa Timur | 51 | 9.48% |
| Banten | 3 | 0.56% |
| DIY | 177 | 32.9% |
| DKI Jakarta | 11 | 2.04% |
3.1.10 Status Anggota
| Kategori | Frekuensi | Persentase |
|---|---|---|
| Pengurus | 176 | 32.71% |
| Anggota Biasa | 362 | 67.29% |
3.2 Peta Sebaran Responden
Kode peta sebaran responden
library(sf)
library(geodata)
library(ggtext)
data_responden <- data.frame(
NAME_1 = c("Jawa Barat", "Jawa Tengah", "Jawa Timur", "Banten", "Yogyakarta", "Jakarta Raya"),
Nama_Dalam = c("Jawa Barat", "Jawa Tengah", "Jawa Timur", "Banten", "DIY", "DKI Jakarta"),
Label_Luar = c(
"italic(n)==33~~'(6.1%)'", "italic(n)==263~~'(48.9%)'",
"italic(n)==51~~'(9.5%)'", "italic(n)==3~~'(0.6%)'",
"italic(n)==177~~'(32.9%)'", "italic(n)==11~~'(2.0%)'"
),
Frekuensi = c(33, 263, 51, 3, 177, 11),
stringsAsFactors = FALSE
)
gadm_dir <- file.path(getwd(), "gadm_cache")
if (!dir.exists(gadm_dir)) dir.create(gadm_dir)
jawa_sf <- geodata::gadm("IDN", level = 1, path = gadm_dir) |>
sf::st_as_sf() |>
dplyr::filter(NAME_1 %in% data_responden$NAME_1) |>
dplyr::left_join(data_responden, by = "NAME_1")
suppressWarnings(cents <- sf::st_centroid(jawa_sf))
coords <- sf::st_coordinates(cents)
jawa_sf$cx <- coords[, 1]; jawa_sf$cy <- coords[, 2]
offset <- list(
"Banten" = c(105.87, -6.85, 105.40, -7.40),
"Jakarta Raya" = c(106.83, -6.08, 107.00, -5.53),
"Jawa Barat" = c(108.30, -6.23, 108.30, -5.53),
"Jawa Tengah" = c(110.10, -6.84, 110.10, -5.53),
"Yogyakarta" = c(110.45, -8.12, 110.45, -8.70),
"Jawa Timur" = c(112.73, -7.00, 112.73, -5.53)
)
jawa_sf <- jawa_sf |> dplyr::mutate(
ax = dplyr::case_when(NAME_1 == "Banten" ~ offset[["Banten"]][1], NAME_1 == "Jakarta Raya" ~ offset[["Jakarta Raya"]][1], NAME_1 == "Jawa Barat" ~ offset[["Jawa Barat"]][1], NAME_1 == "Jawa Tengah" ~ offset[["Jawa Tengah"]][1], NAME_1 == "Yogyakarta" ~ offset[["Yogyakarta"]][1], NAME_1 == "Jawa Timur" ~ offset[["Jawa Timur"]][1]),
ay = dplyr::case_when(NAME_1 == "Banten" ~ offset[["Banten"]][2], NAME_1 == "Jakarta Raya" ~ offset[["Jakarta Raya"]][2], NAME_1 == "Jawa Barat" ~ offset[["Jawa Barat"]][2], NAME_1 == "Jawa Tengah" ~ offset[["Jawa Tengah"]][2], NAME_1 == "Yogyakarta" ~ offset[["Yogyakarta"]][2], NAME_1 == "Jawa Timur" ~ offset[["Jawa Timur"]][2]),
lx = dplyr::case_when(NAME_1 == "Banten" ~ offset[["Banten"]][3], NAME_1 == "Jakarta Raya" ~ offset[["Jakarta Raya"]][3], NAME_1 == "Jawa Barat" ~ offset[["Jawa Barat"]][3], NAME_1 == "Jawa Tengah" ~ offset[["Jawa Tengah"]][3], NAME_1 == "Yogyakarta" ~ offset[["Yogyakarta"]][3], NAME_1 == "Jawa Timur" ~ offset[["Jawa Timur"]][3]),
ly = dplyr::case_when(NAME_1 == "Banten" ~ offset[["Banten"]][4], NAME_1 == "Jakarta Raya" ~ offset[["Jakarta Raya"]][4], NAME_1 == "Jawa Barat" ~ offset[["Jawa Barat"]][4], NAME_1 == "Jawa Tengah" ~ offset[["Jawa Tengah"]][4], NAME_1 == "Yogyakarta" ~ offset[["Yogyakarta"]][4], NAME_1 == "Jawa Timur" ~ offset[["Jawa Timur"]][4]),
nx = dplyr::case_when(NAME_1 == "Banten" ~ 106.20, NAME_1 == "Jakarta Raya" ~ cx + 0.05, NAME_1 == "Jawa Tengah" ~ cx - 0.25, NAME_1 == "Jawa Timur" ~ cx - 0.10, TRUE ~ cx),
ny = dplyr::case_when(NAME_1 == "Banten" ~ -6.38, NAME_1 == "Jawa Tengah" ~ cy + 0.15, NAME_1 == "Jawa Timur" ~ cy - 0.10, TRUE ~ cy)
)
ggplot(jawa_sf) +
geom_sf(aes(fill = Frekuensi), color = "#777777", linewidth = 0.30) +
scale_fill_distiller(palette = "YlGnBu", direction = 1, name = "Jumlah Responden (n)",
breaks = c(3, 50, 100, 177, 263), labels = scales::comma, limits = c(0, 270),
guide = guide_colorbar(title.position = "top", title.hjust = 0.5,
barwidth = 17, barheight = 0.6)) +
geom_text(aes(x = nx, y = ny, label = Nama_Dalam), size = 3.0, fontface = "bold", color = "#0a1628") +
geom_segment(aes(x = ax, y = ay, xend = lx, yend = ly), color = "#888888", linewidth = 0.28) +
geom_label(aes(x = lx, y = ly, label = Label_Luar), parse = TRUE, size = 3.0,
fill = "white", color = "#1a1a2e", alpha = 0.95, linewidth = 0.20,
label.r = unit(0.10, "lines"), label.padding = unit(0.25, "lines")) +
labs(caption = "<i>Catatan.</i> N = 538. Peta menggunakan shapefile GADM v4.1.") +
coord_sf(xlim = c(104.0, 115.5), ylim = c(-9.2, -5.0), expand = FALSE) +
theme_minimal(base_size = 11) +
theme(plot.caption = ggtext::element_markdown(size = 9, hjust = 0, color = "#666666"),
legend.position = "bottom", panel.grid = element_blank(),
axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank(),
panel.background = element_rect(fill = "#EAF3FB", color = NA))
3.3 Statistik Deskriptif Level Item
Statistik deskriptif semua item P (PEB), C (CCS), dan O (OL) untuk data screening dan pengecekan normalitas univariat.
Kode
item_cols <- names(data)[grep("^P\\d+$|^C\\d+$|^O\\d*$", names(data))]
item_desc <- psych::describe(data[, item_cols], type = 2)
item_stats <- data.frame(
Item = item_cols, N = item_desc$n,
Mean = round(item_desc$mean, 3), SD = round(item_desc$sd, 3),
Min = item_desc$min, Max = item_desc$max,
Skewness = round(item_desc$skew, 3), Kurtosis = round(item_desc$kurtosis, 3),
check.names = FALSE
)
knitr::kable(item_stats, caption = "Statistik Deskriptif Level Item", row.names = FALSE)| Item | N | Mean | SD | Min | Max | Skewness | Kurtosis |
|---|---|---|---|---|---|---|---|
| C1 | 538 | 3.307 | 1.484 | 1 | 7 | 0.157 | -0.580 |
| C2 | 538 | 3.273 | 1.606 | 1 | 7 | 0.391 | -0.798 |
| C3 | 538 | 2.115 | 1.254 | 1 | 7 | 1.122 | 0.634 |
| C4 | 538 | 2.745 | 1.439 | 1 | 7 | 0.659 | -0.174 |
| C5 | 538 | 3.052 | 1.563 | 1 | 7 | 0.483 | -0.473 |
| C6 | 538 | 2.375 | 1.271 | 1 | 7 | 0.665 | -0.259 |
| C7 | 538 | 2.684 | 1.145 | 1 | 6 | 0.133 | -1.062 |
| C8 | 538 | 2.364 | 1.495 | 1 | 7 | 0.988 | 0.192 |
| C9 | 538 | 2.688 | 1.591 | 1 | 7 | 0.788 | -0.226 |
| C10 | 538 | 2.946 | 1.547 | 1 | 7 | 0.545 | -0.403 |
| C11 | 538 | 2.463 | 1.547 | 1 | 7 | 1.029 | 0.323 |
| C12 | 538 | 2.063 | 1.100 | 1 | 5 | 0.776 | -0.634 |
| P1 | 538 | 4.249 | 0.988 | 1 | 5 | -1.259 | 0.915 |
| P2 | 538 | 3.794 | 1.145 | 1 | 5 | -0.665 | -0.352 |
| P3 | 538 | 3.487 | 1.187 | 1 | 5 | -0.395 | -0.684 |
| P4 | 538 | 3.779 | 0.994 | 1 | 5 | -0.265 | -0.747 |
| P5 | 538 | 4.424 | 0.845 | 1 | 5 | -1.377 | 1.191 |
| P6 | 538 | 4.145 | 0.879 | 1 | 5 | -0.700 | -0.273 |
| P7 | 538 | 3.301 | 1.175 | 1 | 5 | -0.284 | -0.519 |
| P8 | 538 | 3.916 | 1.026 | 1 | 5 | -0.517 | -0.506 |
| P9 | 538 | 4.288 | 0.870 | 1 | 5 | -0.900 | -0.062 |
| P10 | 538 | 3.561 | 1.054 | 1 | 5 | -0.229 | -0.356 |
| P11 | 538 | 3.375 | 0.899 | 1 | 5 | 0.114 | 0.006 |
| P12 | 538 | 3.593 | 0.852 | 1 | 5 | 0.034 | -0.147 |
| P13 | 538 | 3.416 | 0.885 | 1 | 5 | 0.101 | 0.031 |
| P14 | 538 | 3.582 | 0.858 | 1 | 5 | 0.011 | -0.076 |
| P15 | 538 | 3.738 | 0.854 | 1 | 5 | 0.063 | -0.732 |
| P16 | 538 | 3.059 | 1.194 | 1 | 5 | -0.128 | -0.719 |
| P17 | 538 | 3.517 | 0.969 | 1 | 5 | -0.300 | -0.080 |
| P18 | 538 | 2.455 | 1.284 | 1 | 5 | 0.481 | -0.817 |
| P19 | 538 | 2.786 | 1.330 | 1 | 5 | 0.159 | -1.071 |
| P20 | 538 | 3.753 | 0.953 | 1 | 5 | -0.459 | 0.095 |
| O1 | 538 | 3.831 | 0.830 | 1 | 5 | -0.225 | -0.208 |
| O2 | 538 | 3.848 | 0.823 | 1 | 5 | -0.194 | -0.347 |
| O3 | 538 | 3.822 | 0.860 | 1 | 5 | -0.354 | 0.002 |
| O4 | 538 | 3.619 | 0.873 | 1 | 5 | -0.157 | -0.177 |
| O5 | 538 | 3.894 | 0.813 | 1 | 5 | -0.200 | -0.376 |
| O6 | 538 | 4.132 | 0.805 | 1 | 5 | -0.437 | -0.694 |
| O7 | 538 | 4.024 | 0.826 | 1 | 5 | -0.443 | -0.131 |
| O8 | 538 | 3.862 | 0.859 | 1 | 5 | -0.281 | -0.242 |
| O9 | 538 | 4.030 | 0.797 | 1 | 5 | -0.297 | -0.550 |
| O10 | 538 | 3.879 | 0.831 | 1 | 5 | -0.161 | -0.705 |
| O11 | 538 | 3.978 | 0.818 | 1 | 5 | -0.286 | -0.535 |
| O12 | 538 | 3.875 | 0.838 | 1 | 5 | -0.201 | -0.558 |
| O13 | 538 | 3.974 | 0.807 | 1 | 5 | -0.209 | -0.749 |
| O14 | 538 | 3.853 | 0.834 | 1 | 5 | -0.280 | -0.176 |
| O15 | 538 | 3.987 | 0.773 | 1 | 5 | -0.123 | -0.828 |
CatatanCatatan Metodologis
- Skewness & Kurtosis: Type 2 (
psych::describe), konsisten dengan JASP/SPSS - Kurtosis = Excess Kurtosis (distribusi normal = 0)
- Threshold (West et al., 1995): Skewness > |2.0|, Kurtosis > |7.0|
3.3.1 Visualisasi Deskriptif Item — Dot Plot
Kode plot deskriptif item
# ---- Bangun data frame plot dari item_stats ----
item_plot_df <- item_stats |>
mutate(
prefix = gsub("[0-9]", "", Item),
Midpoint = ifelse(prefix == "C", 4, 3),
MaxSkala = ifelse(prefix == "C", 7, 5),
Skala = case_when(
prefix == "C" ~ "CCS",
prefix == "O" ~ "OL",
prefix == "P" ~ "PEB"
),
item_num = as.integer(gsub("[A-Za-z]", "", Item))
) |>
arrange(prefix, Mean) |>
mutate(
Skala = factor(Skala, levels = c("CCS", "OL", "PEB")),
Item = factor(Item, levels = unique(Item)),
label_x = Mean + SD + 0.08
)
# Data zona (di bawah / di atas midpoint)
zone_df <- item_plot_df |> distinct(Skala, Midpoint, MaxSkala)
# Batas x-axis (memaksa 1–MaxSkala per panel via geom_blank)
ref_items <- item_plot_df |>
group_by(Skala) |>
slice(1) |>
ungroup() |>
select(Skala, Item)
limits_df <- bind_rows(
zone_df |> select(Skala) |> mutate(x_lim = 1),
zone_df |> transmute(Skala, x_lim = MaxSkala)
) |>
left_join(ref_items, by = "Skala")
# Anotasi: rentang mean + interpretasi per panel
range_annot <- item_plot_df |>
summarise(
lo = min(Mean),
hi = max(Mean),
Midpoint = first(Midpoint),
MaxSkala = first(MaxSkala),
.by = Skala
) |>
mutate(
skala_label = case_when(Skala == "CCS" ~ "Skala 1\u20137", TRUE ~ "Skala 1\u20135"),
x_center = (1 + MaxSkala) / 2,
label = sprintf("%s, Mean: %.2f\u2013%.2f", skala_label, lo, hi)
)
# ---- Plot ----
p_item_means <- ggplot(item_plot_df, aes(x = Mean, y = Item)) +
# Zona: di bawah midpoint (merah muda lembut)
geom_rect(
data = zone_df,
aes(xmin = 1, xmax = Midpoint, ymin = -Inf, ymax = Inf),
inherit.aes = FALSE, fill = "#FFF0EE"
) +
# Zona: di atas midpoint (biru muda lembut)
geom_rect(
data = zone_df,
aes(xmin = Midpoint, xmax = MaxSkala, ymin = -Inf, ymax = Inf),
inherit.aes = FALSE, fill = "#EDF4FC"
) +
# Paksa batas sumbu x sesuai rentang skala asli
geom_blank(data = limits_df, aes(x = x_lim, y = Item), inherit.aes = FALSE) +
# Garis midpoint
geom_vline(
data = zone_df, aes(xintercept = Midpoint),
linetype = "longdash", color = "grey40", linewidth = 0.5
) +
# Error bar \u00b11 SD
geom_errorbarh(aes(xmin = Mean - SD, xmax = Mean + SD),
height = 0.25, linewidth = 0.3, color = "grey55"
) +
# Titik mean — warna berdasarkan posisi terhadap midpoint
geom_point(aes(fill = Mean < Midpoint),
shape = 21, size = 2.3,
color = "grey30", stroke = 0.3
) +
scale_fill_manual(
values = c("TRUE" = "#E74C3C", "FALSE" = "#2980B9"),
labels = c(
"TRUE" = "Di bawah midpoint",
"FALSE" = "Di atas midpoint"
),
name = "Mean"
) +
# Label nilai mean — di kanan ujung error bar (tidak menimpa titik/garis)
geom_text(aes(x = label_x, label = sprintf("%.2f", Mean)),
hjust = 0, vjust = 0.4, size = 2.2, color = "grey15",
fontface = "bold"
) +
# Anotasi skala + rentang mean (di luar panel, bawah x-axis)
geom_text(
data = range_annot,
aes(x = x_center, y = -Inf, label = label),
inherit.aes = FALSE, vjust = 3.8, hjust = 0.5,
size = 2.8, color = "grey30", fontface = "bold"
) +
coord_cartesian(clip = "off") +
# Facet: 3 kolom (CCS | OL | PEB)
facet_wrap(~Skala, scales = "free", ncol = 3) +
# Integer breaks — tidak ada desimal di sumbu x
scale_x_continuous(
breaks = function(lims) seq(ceiling(lims[1]), floor(lims[2])),
expand = expansion(mult = c(0.02, 0.12))
) +
labs(
title = "Item-Level Descriptive Statistics",
x = NULL,
y = NULL,
caption = paste0(
"N = ", nrow(data), ". ",
"Zona merah muda = di bawah midpoint (rendah); ",
"zona biru muda = di atas midpoint (tinggi).\n",
"Garis putus-putus = titik tengah skala (midpoint). ",
"Garis horizontal = \u00b11 SD."
)
) +
theme_bw(base_size = 10) +
theme(
plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
plot.caption = element_text(
size = 7.5, color = "grey45", hjust = 0,
margin = margin(t = 8), lineheight = 1.2
),
plot.margin = margin(10, 12, 35, 10),
axis.text.y = element_text(size = 9, face = "bold"),
axis.text.x = element_text(size = 9, face = "bold"),
strip.text = element_text(face = "bold", size = 12),
strip.background = element_rect(fill = "grey93", color = "grey70"),
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(color = "grey92", linewidth = 0.25),
panel.grid.minor = element_blank(),
panel.spacing = unit(1.0, "lines"),
legend.position = "bottom",
legend.direction = "horizontal",
legend.title = element_text(face = "bold", size = 9),
legend.text = element_text(size = 9),
legend.key.size = unit(0.5, "cm"),
legend.margin = margin(t = 5, b = 0),
legend.box.margin = margin(t = 0)
)
print(p_item_means)