Load libraries.
# R markdown link: https://rpubs.com/jasohosk/1428122
# Load libraries
packages <- c("ideanet", "kableExtra", "tidyverse", "psych", "purrr")
installed <- packages %in% rownames(installed.packages())
if (any(!installed)) {
install.packages(packages[!installed])
}
lapply(packages, library, character.only = TRUE)
# Set working directory
setwd(
"/Users/jasonhoskin/Library/CloudStorage/OneDrive-IndianaUniversity/spring-2026/saa/sgm-caregivers"
)
Load survey/demographics dataset. Test for and remove any rows with NAs.
# Import dataset
url <- "final-combined-table.csv"
df0 <- read.csv(url)
## Assess for NAs
colSums(is.na(df0))
## id current.gender race
## 0 0 0
## ethnicity sexual.orientation education
## 0 0 0
## military living.situation marital.status
## 0 0 0
## employment.status personal.income food.insecurity
## 0 0 0
## biological.children not.biological.children work.hours.per.week
## 0 0 0
## caregiver.burden ipaq.continuous ipaq.categorical
## 1 0 0
## loneliness qol
## 1 0
# Conduct listwise deletions
df0 <- na.omit(df0)
Read in Network Canvas data.
networks <- nc_read(
path = "networkcanvasexport_merged")
# Exclude ego_id = 1 (missing data, excluded from analysis)
networks$egos <- networks$egos |> filter(ego_id != 1)
networks$alters <- networks$alters |> filter(ego_id != 1)
networks$alter_edgelists <- networks$alter_edgelists |> filter(ego_id != 1)
res <- ego_netwrite(networks$egos,
ego_id = "ego_id",
networks$alters,
alter_id = "alter_id",
alter_ego = "ego_id",
max_alters = Inf,
alter_alter = networks$alter_edgelists,
aa_ego = "ego_id",
i_elements = "from",
j_elements = "to")
Check results.
# Average across all networks
res$overall_summary |>
knitr::kable() |>
kable_styling(full_width = TRUE, bootstrap_options = c("striped", "hover")) |>
column_spec(1, bold = TRUE)
| measure_labels | measure_descriptions | measures |
|---|---|---|
| Number of egos/ego networks | Total number of egos providing ego networks in dataset | 19 |
| Number of alters | Total number of alters nominated by egos across entire dataset | 214 |
| Number of isolates | Number of egos who did not report any alters in their personal network | 0 |
| Number of one-node networks | Number of egos who reported only one alter in their personal network | 0 |
| Smallest non-isolate network size | Smallest number of alters provided by a single ego | 4 |
| Largest network size | Largest number of alters provided by a single ego | 21 |
| Average network size | Average number of alters provided by a single ego | 11.2631578947368 |
| Average network density | The average density of personal networks provided by egos (networks with 0-1 alters excluded from calculation) | 0.465546476227591 |
| Average fragmentation | The mean fragmentation index score of personal networks provided by egos (networks with 0-1 alters excluded from calculation) | 0.215077354705838 |
# Summaries for each network (ego)
res$summaries |>
knitr::kable() |>
kable_styling(full_width = TRUE, bootstrap_options = c("striped", "hover")) |>
column_spec(1, bold = TRUE)
| ego_id | network_size | mean_degree | density | num_isolates | prop_isolates | num_weakcomponent | size_largest_weakcomponent | prop_largest_weakcomponent | num_strongcomponent | size_largest_strongcomponent | prop_largest_strongcomponent | component_ratio | pairwise_strong_un | pairwise_weak_un | fragmentation_index | effective_size | efficiency | constraint | betweenness | norm_betweenness | dyad_mut | dyad_null | triad_003 | triad_102 | triad_201 | triad_300 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 9 | 5.1111111 | 0.6388889 | 0 | 0.0000000 | 1 | 9 | 1.0000000 | 1 | 9 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 3.888889 | 0.4320988 | 0.3804137 | 4.333333 | 0.1203704 | 23 | 13 | 2 | 28 | 29 | 25 |
| 2 | 15 | 3.4666667 | 0.2476190 | 2 | 0.1333333 | 4 | 10 | 0.6666667 | 4 | 10 | 0.6666667 | 0.2142857 | 0.4571429 | 0.4571429 | 0.5428571 | 11.533333 | 0.7688889 | 0.1927847 | 73.333333 | 0.6984127 | 26 | 79 | 183 | 232 | 14 | 26 |
| 3 | 21 | 6.5714286 | 0.3285714 | 0 | 0.0000000 | 2 | 12 | 0.5714286 | 2 | 12 | 0.5714286 | 0.0500000 | 0.4857143 | 0.4857143 | 0.5142857 | 14.428571 | 0.6870748 | 0.1654584 | 133.000000 | 0.6333333 | 69 | 141 | 297 | 885 | 18 | 130 |
| 4 | 9 | 6.2222222 | 0.7777778 | 1 | 0.1111111 | 2 | 8 | 0.8888889 | 2 | 8 | 0.8888889 | 0.1250000 | 0.7777778 | 0.7777778 | 0.2222222 | 2.777778 | 0.3086420 | 0.3595679 | 8.000000 | 0.2222222 | 28 | 8 | 0 | 28 | 0 | 56 |
| 5 | 13 | 9.6923077 | 0.8076923 | 0 | 0.0000000 | 1 | 13 | 1.0000000 | 1 | 13 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 3.307692 | 0.2544379 | 0.2826019 | 2.276984 | 0.0291921 | 63 | 15 | 4 | 33 | 87 | 162 |
| 6 | 4 | 1.5000000 | 0.5000000 | 0 | 0.0000000 | 1 | 4 | 1.0000000 | 1 | 4 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 2.500000 | 0.6250000 | 0.6835938 | 1.500000 | 0.2500000 | 3 | 3 | 1 | 0 | 3 | 0 |
| 7 | 6 | 2.6666667 | 0.5333333 | 0 | 0.0000000 | 1 | 6 | 1.0000000 | 1 | 6 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 3.333333 | 0.5555556 | 0.4910571 | 5.000000 | 0.3333333 | 8 | 7 | 0 | 12 | 4 | 4 |
| 8 | 6 | 0.6666667 | 0.1333333 | 2 | 0.3333333 | 4 | 2 | 0.3333333 | 4 | 2 | 0.3333333 | 0.6000000 | 0.1333333 | 0.1333333 | 0.8666667 | 5.333333 | 0.8888889 | 0.3055556 | 13.000000 | 0.8666667 | 2 | 13 | 12 | 8 | 0 | 0 |
| 9 | 6 | 5.0000000 | 1.0000000 | 0 | 0.0000000 | 1 | 6 | 1.0000000 | 1 | 6 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 1.000000 | 0.1666667 | 0.5601852 | 0.000000 | 0.0000000 | 15 | 0 | 0 | 0 | 0 | 20 |
| 10 | 18 | 3.2222222 | 0.1895425 | 2 | 0.1111111 | 4 | 14 | 0.7777778 | 4 | 14 | 0.7777778 | 0.1764706 | 0.6013072 | 0.6013072 | 0.3986928 | 14.777778 | 0.8209877 | 0.1605335 | 105.583333 | 0.6900871 | 29 | 124 | 438 | 311 | 48 | 19 |
| 11 | 18 | 6.8888889 | 0.4052288 | 1 | 0.0555556 | 2 | 17 | 0.9444444 | 2 | 17 | 0.9444444 | 0.0588235 | 0.8888889 | 0.8888889 | 0.1111111 | 11.111111 | 0.6172840 | 0.1883356 | 68.904762 | 0.4503579 | 62 | 91 | 170 | 423 | 100 | 123 |
| 12 | 11 | 2.0000000 | 0.2000000 | 2 | 0.1818182 | 3 | 9 | 0.8181818 | 3 | 9 | 0.8181818 | 0.2000000 | 0.6545455 | 0.6545455 | 0.3454545 | 9.000000 | 0.8181818 | 0.2342080 | 39.000000 | 0.7090909 | 11 | 44 | 82 | 70 | 10 | 3 |
| 13 | 15 | 4.4000000 | 0.3142857 | 0 | 0.0000000 | 1 | 15 | 1.0000000 | 1 | 15 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 10.600000 | 0.7066667 | 0.2162960 | 57.666667 | 0.5492063 | 33 | 72 | 134 | 249 | 36 | 36 |
| 14 | 12 | 2.5000000 | 0.2272727 | 5 | 0.4166667 | 6 | 7 | 0.5833333 | 6 | 7 | 0.5833333 | 0.4545455 | 0.3181818 | 0.3181818 | 0.6818182 | 9.500000 | 0.7916667 | 0.1954317 | 46.700000 | 0.7075758 | 15 | 51 | 110 | 82 | 16 | 12 |
| 15 | 7 | 2.2857143 | 0.3809524 | 1 | 0.1428571 | 2 | 6 | 0.8571429 | 2 | 6 | 0.8571429 | 0.1666667 | 0.7142857 | 0.7142857 | 0.2857143 | 4.714286 | 0.6734694 | 0.4003685 | 9.500000 | 0.4523810 | 8 | 13 | 10 | 14 | 7 | 4 |
| 16 | 9 | 2.8888889 | 0.3611111 | 0 | 0.0000000 | 1 | 9 | 1.0000000 | 1 | 9 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 6.111111 | 0.6790123 | 0.3545259 | 14.250000 | 0.3958333 | 13 | 23 | 26 | 32 | 19 | 7 |
| 17 | 4 | 3.0000000 | 1.0000000 | 0 | 0.0000000 | 1 | 4 | 1.0000000 | 1 | 4 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 1.000000 | 0.2500000 | 0.7656250 | 0.000000 | 0.0000000 | 6 | 0 | 0 | 0 | 0 | 4 |
| 18 | 17 | 5.4117647 | 0.3382353 | 1 | 0.0588235 | 2 | 16 | 0.9411765 | 2 | 16 | 0.9411765 | 0.0625000 | 0.8823529 | 0.8823529 | 0.1176471 | 11.588235 | 0.6816609 | 0.2074136 | 45.816667 | 0.3368873 | 46 | 90 | 234 | 261 | 126 | 59 |
| 19 | 14 | 6.0000000 | 0.4615385 | 0 | 0.0000000 | 1 | 14 | 1.0000000 | 1 | 14 | 1.0000000 | 0.0000000 | 1.0000000 | 1.0000000 | 0.0000000 | 8.000000 | 0.5714286 | 0.2451334 | 31.133333 | 0.3421245 | 42 | 49 | 54 | 181 | 64 | 65 |
plot(res$igraph_objects[[1]]$igraph_ego)
Incorporate SNA data into df0.
# Extract SNA variables from ego_netwrite results
sna_vars <- res$summaries |>
select(
ego_id,
network.size = network_size,
mean.degree = mean_degree,
ego.density = density,
effective.size = effective_size
)
# Match IDs
df0$id = 1:19
## Join SNA results into df0
df1 <- df0 |>
left_join(sna_vars, by = c("id" = "ego_id"))
Provide descriptive statistics for continuous variables.
# Create descriptive table
continuous_vars <- df1 |>
select(
caregiver.burden,
ipaq.continuous,
network.size,
effective.size,
mean.degree,
ego.density,
work.hours.per.week,
loneliness,
qol,
biological.children,
not.biological.children
)
continuous_descriptives <- psych::describe(continuous_vars) |>
as.data.frame() |>
select(n, mean, sd, median, min, max, skew, kurtosis)
continuous_descriptives |>
mutate(across(where(is.numeric), \(x) round(x, 2))) |>
knitr::kable(
caption = "Descriptive Statistics for Continuous Variables",
col.names = c("n", "Mean", "SD", "Median", "Min", "Max", "Skew", "Kurtosis"),
align = c("r", "r", "r", "r", "r", "r", "r", "r")
) |>
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE,
position = "left"
)
| n | Mean | SD | Median | Min | Max | Skew | Kurtosis | |
|---|---|---|---|---|---|---|---|---|
| caregiver.burden | 19 | 19.84 | 5.30 | 20.00 | 11.00 | 29.00 | 0.12 | -0.84 |
| ipaq.continuous | 19 | 3249.95 | 3794.43 | 1884.00 | 0.00 | 13488.00 | 1.90 | 2.45 |
| network.size | 19 | 11.26 | 5.16 | 11.00 | 4.00 | 21.00 | 0.21 | -1.30 |
| effective.size | 19 | 7.08 | 4.43 | 6.11 | 1.00 | 14.78 | 0.23 | -1.40 |
| mean.degree | 19 | 4.18 | 2.25 | 3.47 | 0.67 | 9.69 | 0.57 | -0.36 |
| ego.density | 19 | 0.47 | 0.26 | 0.38 | 0.13 | 1.00 | 0.77 | -0.68 |
| work.hours.per.week | 19 | 27.37 | 19.55 | 35.00 | 0.00 | 60.00 | -0.17 | -1.52 |
| loneliness | 19 | 8.74 | 3.28 | 8.00 | 3.00 | 14.00 | -0.24 | -1.07 |
| qol | 19 | 6.11 | 2.00 | 7.00 | 2.00 | 9.00 | -0.45 | -1.09 |
| biological.children | 19 | 0.21 | 0.54 | 0.00 | 0.00 | 2.00 | 2.25 | 4.09 |
| not.biological.children | 19 | 0.42 | 1.12 | 0.00 | 0.00 | 4.00 | 2.31 | 3.96 |
# Create histograms
continuous_vars <- c(
"biological.children",
"not.biological.children",
"work.hours.per.week",
"ego.density",
"network.size",
"effective.size",
"mean.degree",
"ipaq.continuous",
"loneliness",
"qol"
)
df_hist_long <- df1 |>
select(all_of(continuous_vars)) |>
pivot_longer(cols = everything(),
names_to = "variable",
values_to = "value")
ggplot(df_hist_long, aes(x = value)) +
geom_histogram(bins = 30, color = "white") +
facet_wrap(~ variable, scales = "free") +
theme_bw()
# Create scatterplots of continuous variables by caregiver burden
df_scatter_long <- df1 |>
select(caregiver.burden, all_of(continuous_vars)) |>
pivot_longer(
cols = all_of(continuous_vars),
names_to = "variable",
values_to = "value"
)
ggplot(df_scatter_long, aes(x = value, y = caregiver.burden)) +
geom_point(alpha = 0.7) +
facet_wrap(~ variable, scales = "free_x") +
theme_bw() +
labs(x = "Value", y = "Caregiver Burden")
Provide descriptive statistics for categorical variables.
# Create cross tables
categorical_vars <- c(
"current.gender",
"race",
"ethnicity",
"sexual.orientation",
"education",
"military",
"living.situation",
"marital.status",
"employment.status",
"personal.income",
"food.insecurity",
"ipaq.categorical"
)
df1 <- df1 |>
mutate(across(all_of(categorical_vars), as.factor))
cat_tables <- map(categorical_vars, function(v) {
df1 |>
count(.data[[v]], name = "n") |>
mutate(percent = round(100 * n / sum(n), 1), variable = v) |>
relocate(variable)
})
names(cat_tables) <- categorical_vars
cat_summary <- map_dfr(categorical_vars, function(v) {
df1 |>
count(.data[[v]], name = "n") |>
mutate(percent = round(100 * n / sum(n), 1), variable = v) |>
rename(category = .data[[v]]) |>
select(variable, category, n, percent)
})
cat_summary |>
knitr::kable(
col.names = c("Variable", "Category", "n", "%"),
caption = "Descriptive Statistics for Categorical Variables",
align = c("l", "l", "r", "r")
) |>
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE,
position = "left"
) |>
kableExtra::pack_rows(index = table(cat_summary$variable)[unique(cat_summary$variable)])
| Variable | Category | n | % |
|---|---|---|---|
| current.gender | |||
| current.gender | Female | 8 | 42.1 |
| current.gender | Male | 9 | 47.4 |
| current.gender | Nonbinary | 2 | 10.5 |
| race | |||
| race | Asian | 1 | 5.3 |
| race | Black | 1 | 5.3 |
| race | Multiracial | 4 | 21.1 |
| race | White | 13 | 68.4 |
| ethnicity | |||
| ethnicity | Hispanic/Latino | 1 | 5.3 |
| ethnicity | not Hispanic/Latino | 18 | 94.7 |
| sexual.orientation | |||
| sexual.orientation | Asexual | 1 | 5.3 |
| sexual.orientation | Bisexual | 2 | 10.5 |
| sexual.orientation | Gay or Lesbian | 15 | 78.9 |
| sexual.orientation | Queer | 1 | 5.3 |
| education | |||
| education | Advanced degree | 7 | 36.8 |
| education | College degree | 8 | 42.1 |
| education | Doctorate | 1 | 5.3 |
| education | High school graduate | 2 | 10.5 |
| education | Some college (no degree) | 1 | 5.3 |
| military | |||
| military | No | 18 | 94.7 |
| military | Yes | 1 | 5.3 |
| living.situation | |||
| living.situation | Assisted living facility | 1 | 5.3 |
| living.situation | Other | 3 | 15.8 |
| living.situation | Own personal home | 12 | 63.2 |
| living.situation | Pay rent on an apartment | 3 | 15.8 |
| marital.status | |||
| marital.status | Married | 9 | 47.4 |
| marital.status | Never been married | 7 | 36.8 |
| marital.status | Not married but living with partner | 3 | 15.8 |
| employment.status | |||
| employment.status | Disabled; Homemaker | 1 | 5.3 |
| employment.status | Other | 3 | 15.8 |
| employment.status | Student | 1 | 5.3 |
| employment.status | Unemployed and looking for work | 3 | 15.8 |
| employment.status | Working full-time | 8 | 42.1 |
| employment.status | Working part-time | 3 | 15.8 |
| personal.income | |||
| personal.income | $15,000-$24,999 | 4 | 21.1 |
| personal.income | $35,000-$49,999 | 3 | 15.8 |
| personal.income | $50,000-$74,999 | 2 | 10.5 |
| personal.income | $75,000 and over | 6 | 31.6 |
| personal.income | Under $5,000 | 4 | 21.1 |
| food.insecurity | |||
| food.insecurity | 0 | 11 | 57.9 |
| food.insecurity | 1 | 8 | 42.1 |
| ipaq.categorical | |||
| ipaq.categorical | High | 5 | 26.3 |
| ipaq.categorical | Low | 3 | 15.8 |
| ipaq.categorical | Moderate | 11 | 57.9 |
# Create boxplots
df_cat_long <- df1 |>
select(caregiver.burden, all_of(categorical_vars)) |>
pivot_longer(
cols = all_of(categorical_vars),
names_to = "variable",
values_to = "category"
) |>
mutate(category = as.factor(category))
ggplot(df_cat_long, aes(x = category, y = caregiver.burden)) +
geom_boxplot() +
facet_wrap( ~ variable, scales = "free_x") +
theme_minimal() +
labs(x = "Category", y = "Caregiver burden") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))