Point estimates: CIFA, SPIFA


Compare observed data with point estimates from CIFA and SPIFA models.

Load required libraries and data

rm(list = ls())
library(day2day)
library(spifa)
library(xtable)
library(tibble)
library(sf)
#> Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(tidyr)
library(purrr)

path_main <- git_path()
path_data <- file.path(path_main, "data")
path_raw <- file.path(path_data, "raw")
path_processed <- file.path(path_data, "processed")
path_modelled <- file.path(path_data, "modelled")
path_fig <- file.path(path_data, "figures")
path_src <- file.path(path_main, "src")

source(file.path(path_src, "itemnames.R"))

fidata <- file.path(path_processed, "fi-items-ipixuna-urban.gpkg") |>
    st_read(as_tibble = TRUE)
#> Reading layer `fi-items-ipixuna-urban' from data source 
#>   `/home/rstudio/documents/projects/food-insecurity-mapping/data/processed/fi-items-ipixuna-urban.gpkg' 
#>   using driver `GPKG'
#> Simple feature collection with 200 features and 36 fields
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -71.70038 ymin: -7.06058 xmax: -71.68109 ymax: -7.03724
#> Geodetic CRS:  WGS 84
samples_cifa <- readRDS(file.path(path_modelled, "cifa-ipixuna-urban.rds"))
samples_spifa <- readRDS(file.path(path_modelled, "spifa-ipixuna-urban-3gp.rds"))
iter <- nrow(samples_spifa[["theta"]])

Compute summaries from data

items_summary <- st_drop_geometry(fidata) |>
    dplyr::select(matches("^item_[0-9]+_"), registro) |>
    pivot_longer(-registro, names_to = "Item", values_to = "varvalue", names_ptypes = factor()) |>
    group_by(Item) |>
    summarise(`NA` = sum(is.na(varvalue)), `$\\pi$` = mean(varvalue, na.rm = TRUE)) |>
    mutate(
        Question = gsub("[A-D]-[0-9]+: ", "", clean_item_names(Item)),
        Item = as.character(1:n()),
        Section = map2(LETTERS[1:4], c(3, 4, 6, 5),
            ~ c(sprintf("\\multirow{%i}[3]{*}{%s}", .y, .x), rep("", .y - 1))) %>%
            Reduce(c, .)
    ) |>
    dplyr::select(Item, Section, Question, `NA`, `$\\pi$`) |>
    print(n = Inf)
#> # A tibble: 18 × 5
#>    Item  Section                  Question                  `NA` `$\\pi$`
#>    <chr> <chr>                    <chr>                    <int>    <dbl>
#>  1 1     "\\multirow{3}[3]{*}{A}" worried that food ends       0    0.565
#>  2 2     ""                       run out of food              0    0.52 
#>  3 3     ""                       ate few food types           0    0.64 
#>  4 4     "\\multirow{4}[3]{*}{B}" skipped a meal               0    0.305
#>  5 5     ""                       ate less than required       0    0.41 
#>  6 6     ""                       hungry but did not eat       0    0.24 
#>  7 7     ""                       at most one meal per day     0    0.26 
#>  8 8     "\\multirow{6}[3]{*}{C}" ate few food types          25    0.486
#>  9 9     ""                       ate less than required      25    0.314
#> 10 10    ""                       decreased food quantity     25    0.36 
#> 11 11    ""                       skipped a meal              25    0.229
#> 12 12    ""                       hungry but did not eat      25    0.2  
#> 13 13    ""                       at most one meal per day    25    0.177
#> 14 14    "\\multirow{5}[3]{*}{D}" food just with farinha       0    0.165
#> 15 15    ""                       credit for eating            0    0.675
#> 16 16    ""                       borrowed food                0    0.14 
#> 17 17    ""                       had meals at neighbors       0    0.175
#> 18 18    ""                       reduced meat or fish         0    0.535

Model summaries

discrimination_summary <- summary(as_tibble(samples_cifa, iter/5, select = c("a"))) |>
    bind_rows(summary(as_tibble(samples_spifa, iter/5, select = c("a"))), .id = "model") |>
    select(model, Parameters, `50%`) |>
    within({`50%`[`50%` == 0] <- NA}) |>
    separate_wider_regex(Parameters,
        patterns =  c(".+\\[", Item = "[0-9]+", ",", factor = "[1-3]+", "\\]")) |>
    pivot_wider(names_from = c("model", "factor"), values_from = `50%`,
    names_glue = "M{model}-F{factor}")

difficulty_summary <-
# summary(as_tibble(samples_cifa, iter/5, select = c("c"))) |>
    bind_rows(summary(as_tibble(samples_spifa, iter/5, select = c("c"))), .id = "model") |>
    select(model, Parameters, `50%`) |>
    separate_wider_regex(Parameters,
        patterns =  c(".+\\[", Item = "[0-9]+", "\\]")) |>
    pivot_wider(names_from = "model", values_from = `50%`, names_glue = "c")

full_summary <- left_join(items_summary, discrimination_summary) |>
    left_join(difficulty_summary)
#> Joining with `by = join_by(Item)`
#> Joining with `by = join_by(Item)`
full_summary
#> # A tibble: 18 × 12
#>    Item  Section     Question  `NA` `$\\pi$` `M1-F1` `M1-F2` `M1-F3` `M2-F1` `M2-F2` `M2-F3`       c
#>    <chr> <chr>       <chr>    <int>    <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
#>  1 1     "\\multiro… worried…     0    0.565  NA       1.63    NA     NA       1.77   NA      0.439 
#>  2 2     ""          run out…     0    0.52   NA      NA        1.51  NA      NA       1.88   0.216 
#>  3 3     ""          ate few…     0    0.64    1.68   NA       NA      1.81   NA      NA      1.46  
#>  4 4     "\\multiro… skipped…     0    0.305   1.47   NA        1.02   1.92   NA       0.998 -0.628 
#>  5 5     ""          ate les…     0    0.41    0.880  NA        1.75   1.39   NA       1.50  -0.0743
#>  6 6     ""          hungry …     0    0.24    1.26   NA        1.49   1.81   NA       1.54  -1.44  
#>  7 7     ""          at most…     0    0.26    1.57   NA       NA      1.80   NA      NA     -0.551 
#>  8 8     "\\multiro… ate few…    25    0.486   1.71   NA       NA      1.88   NA      NA      0.588 
#>  9 9     ""          ate les…    25    0.314   1.90   NA       NA      2.23   NA      NA     -0.360 
#> 10 10    ""          decreas…    25    0.36    2.17   NA       NA      2.53   NA      NA     -0.0331
#> 11 11    ""          skipped…    25    0.229   1.99   NA       NA      2.52   NA      NA     -1.05  
#> 12 12    ""          hungry …    25    0.2     2.11   NA       NA      2.59   NA      NA     -1.33  
#> 13 13    ""          at most…    25    0.177   1.93   NA       NA      2.43   NA      NA     -1.51  
#> 14 14    "\\multiro… food ju…     0    0.165   0.343  NA        1.25   0.626  NA       1.28  -1.62  
#> 15 15    ""          credit …     0    0.675  NA       0.716   NA     NA       0.796  NA      0.629 
#> 16 16    ""          borrowe…     0    0.14   NA       1.44    NA     NA       1.61   NA     -1.90  
#> 17 17    ""          had mea…     0    0.175  NA       0.982   NA     NA       1.04   NA     -1.26  
#> 18 18    ""          reduced…     0    0.535   1.29   NA       NA      1.43   NA      NA      0.751

Create and save latex table

# convert to latex
full_table <- xtable(
    full_summary,
    align = c("c", "c", "c", "l", "c", "c", "c", "c", "c", "c", "c", "c", "r"),
    caption = paste0(
    "Summary of the food insecurity items: ",
    "i) the number of missing values ($\\#$NA) and the proportion of endorsement ",
    "($\\pi$) are shown for the descriptive analysis, ",
    "ii) the posterior median of the discrimination parameters $\\{\\m{\\hat{A}}_{\\cdot 1}, \\m{\\hat{A}}_{\\cdot 2}, \\m{\\hat{A}}_{\\cdot 3}\\}$ are shown for the ",
    "confirmatory factor analysis (CIFA), and ",
    "iii) the posterior median of the discrimination and easiness parameters ",
    " $\\{\\m{\\hat{A}}_{\\cdot 1}, \\m{\\hat{A}}_{\\cdot 2}, \\m{\\hat{A}}_{\\cdot 3}, \\hat{\\ve{c}}\\}$ are shown for the ",
    "spatial item factor analysis (SPIFA)."),
    label = "tab:items"
)

# improve row names and add separators
addtorow <- list()
addtorow$pos <- list(0, 0, nrow(full_table))
addtorow$command <- c(
    "\\toprule[.15em] \\multirow{2}[3]{*}{\\textbf{Item}} & \\multirow{2}[3]{*}{\\textbf{Section}} & \\multirow{2}[3]{*}{\\textbf{Question}} & \\multicolumn{2}{c}{\\textbf{Descriptive}} & \\multicolumn{3}{c}{\\textbf{CIFA}} & \\multicolumn{4}{c}{\\textbf{SPIFA}} \\\\\n \\cmidrule(rl){4-5} \\cmidrule(rl){6-8} \\cmidrule(rl){9-12}",
    " & & & $\\#$NA & $\\pi$ & ${\\m{\\hat{A}}_{\\cdot 1}}$ & ${\\m{\\hat{A}}_{\\cdot 2}}$ & ${\\m{\\hat{A}}_{\\cdot 3}}$ & ${\\m{\\hat{A}}_{\\cdot 1}}$ & ${\\m{\\hat{A}}_{\\cdot 2}}$ & ${\\m{\\hat{A}}_{\\cdot 3}}$ & \\multicolumn{1}{c}{$\\hat{\\ve{c}}$}  \\\\\n \\midrule[.1em]",
    "\\bottomrule[.15em]"
)

# print latex with additional formating
print(full_table,
      file = file.path(path_fig, "results-summary-cifa-spifa.tex"),
      caption.placement = "top",
      include.rownames = FALSE,
      size = "\\scriptsize",
      sanitize.text.function = identity,
      add.to.row = addtorow,
      include.colnames = FALSE,
      hline.after = c(3, 7, 13),
      NA.string = "$\\cdot$"
      )

Time to execute the task

Only useful when executed with Rscript.

proc.time()
#>    user  system elapsed 
#>   3.951   0.411   4.046