代码分享|结构方程模型的可视化|Nature 子刊|R 语言 SEM 教程系列

文摘   2024-06-05 00:21   江苏  

引言

又有一个 SEM 代码学习好案例!最新出炉的好文章,公开了代码:

  • 代码地址见原文 Code availability 一节。

Larger nations benefit more than smaller nations from the stabilizing effects of crop diversity
以下代码,尝试用 R 语言完成文中 SEM 的可视化,效果如下(可以进一步到 PPT 里编辑,修改变量名、添加 R2 等)。

一、加载工具包

library(nlme)
library(piecewiseSEM)
library(igraph)
library(ggraph)
library(tidygraph)
library(dplyr)

二、原文所附 SEM 代码

# 加载数据
load("NATFOOD-23060800_data.RData")

# 拟合 SEM 的代码
figure1b_SEM <- psem(
# 回归:
gls(
log10(pre.cv) ~ log10(Area.h),
correlation = corAR1(form = ~ 1 | Country),
Nation_CV
),
gls(
log10(LPre.n) ~ log10(Area.h),
correlation = corAR1(form = ~ 1 | Country),
Nation_CV
),
gls(
log10(asy) ~ EH + log10(tmp.cv),
correlation = corAR1(form = ~ 1 | Country),
Nation_CV
),
gls(
log10(Avg.crop.S) ~ log10(Area.h) + log10(pre.cv) + log10(tmp.cv) + log10(LPre.n) + log10(Irrigation),
correlation = corAR1(form = ~ 1 | Country),
Nation_CV
),
lm(
log10(Yield.S) ~ log10(Avg.crop.S) + log10(asy),
Nation_CV
),

# 相关:
log10(Avg.crop.S) %~~% log10(asy),
log10(tmp.cv) %~~% log10(pre.cv),
log10(Irrigation) %~~% log10(pre.cv),
log10(LPre.n) %~~% log10(pre.cv),
EH %~~% log10(pre.cv)
)

三、保存 SEM 数据

  • 以 CSV 格式保存。

# 结果整理为 from、to、weight、p 数据框
coefs(figure1b_SEM) |>
select(-9) |> # 去掉星号列
filter(
str_detect(Response, "~~", negate = TRUE) # 去掉相关性部分
) |>
dplyr::relocate(
from = Predictor,
to = Response,
weight = Std.Estimate,
p = P.Value
) |>
write.csv("nature-food-sem-table.csv", row.names = FALSE)

四、SEM 结果变成图

  • SEM 是一个有向无环图:DAG(Directed Acyclic Graph)。

# 变为一个 graph
graph <- read.csv('nature-food-sem-table.csv') |>
graph_from_data_frame()
print(graph)
IGRAPH d7deb86 DNW- 9 11 -- 
+ attr: name (v/c), weight (e/n), p (e/n), Estimate (e/n), Std.Error
| (e/n), DF (e/n), Crit.Value (e/n)
+ edges from d7deb86 (vertex names):
[1] log10(Area.h) ->log10(pre.cv) log10(Area.h) ->log10(LPre.n)
[3] EH ->log10(asy) log10(tmp.cv) ->log10(asy)
[5] log10(Area.h) ->log10(Avg.crop.S) log10(pre.cv) ->log10(Avg.crop.S)
[7] log10(tmp.cv) ->log10(Avg.crop.S) log10(LPre.n) ->log10(Avg.crop.S)
[9] log10(Irrigation)->log10(Avg.crop.S) log10(Avg.crop.S)->log10(Yield.S)
[11] log10(asy) ->log10(Yield.S)
# 是一个 DAG 吗?
igraph::is_dag(graph)
[1] TRUE

五、Style 1:设置默认布局

绘图

font <- 'DejaVu Sans'

p0 <- ggraph(graph, layout = "sugiyama") +
geom_edge_diagonal(
strength = 1,
aes(
color = ifelse(weight > 0, "+", "-"),
edge_width = abs(weight),
edge_linetype = ifelse(p < 0.05, 'SIG', 'NS'),
label = round(weight, 2),
start_cap = label_rect(node1.name),
end_cap = label_rect(node2.name)
),
angle_calc = 'along',
label_size = 3,
label_push = unit(10, 'pt'),
label_dodge = unit(10, 'pt'),
family = font,
arrow = arrow(60, length = unit(7, 'pt'), type = 'closed'),
linejoin = "mitre",
linemitre = 2
) +
geom_node_label(
aes(label = name),
size = 3.5,
label.r = unit(0, "pt"),
alpha = 0.5,
family = font
) +
scale_color_brewer(name = NULL, palette = 'Paired') +
scale_edge_color_brewer(name = NULL, palette = 'Set2', direction = -1) +
scale_edge_width_continuous(guide = 'none', range = c(0.2, 2)) +
scale_edge_linetype_manual(name = NULL, values = c('SIG' = 1, 'NS' = 2)) +
coord_cartesian(clip = 'off') +
theme_graph(base_family = 'DejaVu Sans')

# Show plot
p0

存图为 SVG 格式,可以进一步在 PPT 里编辑

  • 修改变量名、添加 R2 等等。

# Now you can edit the SVG in PPT
ggsave('Graph0.svg', p0, width = 10, height = 5)

六、Style 2:手动指定布局(节点位置)

  • 以下手动布局的坐标,来自一个 SEM 可视化工具,详情见另几篇推送:

👉 R 语言 SEM|鼠标修改布局|结构方程模型可视化工具教程|全球独家
👉 R 语言 SEM|结构方程模型直接间接效应|可视化

(点击 👉 即可跳转。)
  • 空间想象能力好的话,可以自定义坐标。
# Define the layout coordinates
layout_coord <- data.frame(
name = c('log10(Area.h)', 'EH', 'log10(tmp.cv)', 'log10(pre.cv)', 'log10(LPre.n)', 'log10(Irrigation)', 'log10(Avg.crop.S)', 'log10(asy)', 'log10(Yield.S)'),
x = c(5, 19, 12, 1, 5, 15, 8, 19, 14),
y = c(19, 19, 19, 13, 13, 19, 7, 7, 1)
)

# Create the layout manually
layout <- create_layout(
graph,
layout = 'manual',
x = layout_coord$x,
y = layout_coord$y
)

绘图

p1 <- ggraph(layout) +
geom_edge_diagonal(
strength = 1,
aes(
color = ifelse(weight > 0, "+", "-"),
edge_width = abs(weight),
edge_linetype = ifelse(p < 0.05, 'SIG', 'NS'),
label = round(weight, 2),
start_cap = label_rect(node1.name),
end_cap = label_rect(node2.name)
),
angle_calc = 'along',
label_size = 3,
label_push = unit(10, 'pt'),
label_dodge = unit(10, 'pt'),
family = font,
arrow = arrow(60, length = unit(7, 'pt'), type = 'closed'),
linejoin = "mitre",
linemitre = 2
) +
geom_node_label(
aes(label = name),
size = 3.5,
label.r = unit(0, "pt"),
alpha = 0.5,
family = font
) +
scale_color_brewer(name = NULL, palette = 'Paired') +
scale_edge_color_brewer(name = NULL, palette = 'Set2', direction = -1) +
scale_edge_width_continuous(guide = 'none', range = c(0.2, 2)) +
scale_edge_linetype_manual(name = NULL, values = c('SIG' = 1, 'NS' = 2)) +
coord_cartesian(clip = 'off') +
theme_graph(base_family = 'DejaVu Sans')

# Show plot
p1

存图为 SVG 格式,可以进一步在 PPT 里编辑

  • 修改变量名、添加 R2 等等。

# Now you can edit the SVG in PPT
ggsave('Graph1.svg', p1, width = 10, height = 5)


ecologyR
🚀打赏可获取本公众号代码合集(见置顶文章)📌统计案例📌统计制图📌显著性标记📌结构方程模型可视化工具📌SEM教程与案例📌论文代码复现📌地图可视化
 最新文章