---
title: "Mixed graphical models"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Mixed graphical models}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 5)
has_cograph <- requireNamespace("cograph", quietly = TRUE)
```

```{r}
library(psychnets)
```

A **mixed graphical model** (`method = "mgm"`) estimates a network over variables
of *different types in the same model* -- here continuous (Gaussian) and binary
nodes. Each node is regressed on all the others with the L1-penalised GLM that
matches its type (linear for continuous, logistic for binary), and the asymmetric
estimates are symmetrised by the AND rule. It is equivalent to `mgm::mgm()` for
the Gaussian + binary case, and self-certifies via the nodewise GLM residual.

## Building a mixed data set

We keep three constructs continuous (`CSU`, `IV`, `SE`) and treat two as binary
(`SR`, `TA`) -- as if self-regulation and test anxiety had been recorded as
high/low. A small helper dichotomises the binary pair with
`dichotomize(method = "rank")` and binds them to the three continuous constructs.

```{r}
mixed_scores <- function(x) {
  d <- as.data.frame(x)
  b <- dichotomize(d[c("SR", "TA")], method = "rank")
  data.frame(d[c("CSU", "IV", "SE")], SR = b[, "SR"], TA = b[, "TA"])
}

mixed <- mixed_scores(SRL_GPT)
head(mixed)
```

## The fitted network

`psychnet()` auto-detects each column's type and fits the matching GLM nodewise:

```{r}
fit <- psychnet(mixed, method = "mgm")
fit
certificate(fit)
```

The edges, and the per-node type and predictability (R-squared for the Gaussian
nodes, normalised accuracy `nCC` for the binary ones):

```{r}
as.data.frame(fit)
net_predict(fit, data = mixed)
```

A binary--binary edge carries the sign of its nodewise-logistic coefficient,
which `mgm::mgm()` leaves undefined, so compare such edges on `abs()`. The edge
magnitudes otherwise match `mgm::mgm()` closely.

## Plotting

Pass the network object to `cograph::splot()` with `psych_styling = TRUE`
(green = positive, red = negative); ask for the predictability ring with
`predictability = TRUE`.

```{r mgm-plot, eval = has_cograph}
cograph::splot(fit, psych_styling = TRUE, predictability = TRUE)
```

`method = "mgm"` (v0.1) supports Gaussian and binary nodes; a multi-level
categorical column is rejected with a clear message (one-hot encode it first).
See `net_crosswalk("mgm")` for the argument map against `mgm::mgm()`.
