展会资讯
用DeepSeek V4写R语言分析报告:Quarto自动更新,数据改了不用手动改Word
2026-05-08 11:39
用DeepSeek V4写R语言分析报告:Quarto自动更新,数据改了不用手动改Word

这是「DeepSeek V4 × R语言数据科学」系列第六篇。 前五篇分别讲了工作台配置数据处理数据可视化统计建模机器学习。这一篇讲Quarto——你的分析报告从此不再需要手动复制粘贴数字。

01 先说一件让我印象很深的事

有个做临床研究的博士,给我发了一条消息:

王博士,我昨晚改了数据,把一个纳入标准调整了,样本量从268变成了241。现在要改的东西是:正文里提到样本量的地方有11处,Table 1要重新跑,三张图要重新出,讨论里引用的数字要逐一核对……

他说这个过程他以前做过,漏改了两处,被导师发现了。

我问他:你愿意花多长时间学一个工具,让你以后再遇到这种情况只需要运行一行命令?

他说:一个小时。

这篇文章教你学的那个工具,叫Quarto。学会了,数据改了,报告自动更新,一行代码搞定。

02 Quarto是什么,为什么要用它

用一句话说清楚: Quarto是一种把R代码和文字混在一起写的文件格式,运行之后自动生成Word文档或HTML报告,里面的数字和图表都是代码跑出来的,不是手动粘贴的。

换一种说法:你的分析报告里,每一个数字、每一张图、每一行统计结果,都直接来自你的R代码,而不是你手动复制进去的。

数据改了,重新运行一次,报告里所有的数字自动更新,不可能漏改,不可能改错。

和传统Word写法的对比:

传统写法(你现在可能的做法):  R跑出结果 → 复制数字 → 粘贴进Word → 改数据 → 重新跑 →  逐一找Word里的数字 → 逐一替换 → 祈祷没有漏掉Quarto写法:  在Quarto文件里写代码和文字 → 数据改了 → 运行一次 →  报告自动更新完毕

03 Quarto在前面系列文章里出现过几次

第一篇工作台配置里提到了renv管理包版本; 第三篇数据可视化里提到了图表导出; 第五篇机器学习里提到了可重复分析流程。

Quarto是把这一切串起来的最后一块:可重复的科研报告。

04 准备工作

1 安装Quarto

Quarto不是R包,是一个独立的软件。

访问:https://quarto.org/docs/get-started/

下载对应系统的安装包,安装即可。安装完成后,Positron会自动检测到Quarto。

2 验证安装

在Positron终端运行:

quarto --version

看到版本号(如1.4.550),说明安装成功。

若是需要教程的配套qmd文件和资料包,拿过去就复用,可以进入我们的R语言AI编程社群,扫码添加?。

3 安装R包

install.packages(c("tidyverse","gtsummary","survival","survminer","broom","flextable","knitr","kableExtra","here"))

05 第一步:创建你的第一个Quarto文件

在Positron里:File → New File → Quarto Document

新建的.qmd文件会有这样的基础结构:

---title:"临床数据分析报告"author:"王博士"date:todayformat:docx:defaulthtml:defaultexecute:echo:falsewarning:falsemessage:false---

YAML头部是整个文件的控制中心,先把它配置好。

06 第二步:YAML头部完整配置

这是最容易配错的地方,下面给你一个可以直接用的完整版本:

---title:"临床预测模型分析报告"subtitle:"基于机器学习的糖尿病风险预测"author:-name:"第一作者"affiliation:"某某大学附属医院"date:todaydate-format:"YYYY年MM月DD日"# 输出格式设置format:# Word格式(投稿用)docx:toc:true# 生成目录toc-depth:3# 目录深度number-sections:true# 章节编号reference-doc:template.docx# 自定义样式模板(可选)fig-width:7fig-height:5fig-dpi:300# HTML格式(在线查看/分享)html:toc:truetoc-float:truetheme:flatlycode-fold:true# 代码可折叠(读者可选择看代码)embed-resources:true# 把所有资源打包进单个HTML文件# 全局代码块设置execute:echo:false# 默认不显示代码(投稿报告)warning:false# 不显示警告信息message:false# 不显示提示信息cache:true# 缓存结果(改了别的地方不需要重新跑所有代码)# 图片设置fig-align:centerfig-cap-location:bottom# 表格设置tbl-cap-location:top---

关键参数说明:

echo: false — 最重要的设置。投稿的报告不需要展示代码,只展示结果。

cache: true — 分析时间长的时候救命神器。跑完一次之后,没有改动的代码块直接用缓存结果,不重新运行。

embed-resources: true — 生成单个HTML文件,发给别人不用额外传图片文件夹。

07 第三步:代码块——Quarto的核心

Quarto里的R代码放在代码块里,用三个反引号包裹:

```{r}#| label: load-data#| cache: true#| echo: falselibrary(tidyverse)library(gtsummary)# 读取数据df <- readRDS(here::here("data", "processed", "clean_data.rds"))```

代码块的选项用#|开头,常用的有:

#| label: 代码块名称(用于交叉引用)#| echo: false       # 不显示代码#| cache: true       # 缓存结果#| fig-cap: "图1 KM生存曲线"  # 图表标题#| fig-width: 8      # 图宽(英寸)#| fig-height: 6     # 图高

08 第四步:内联代码——让数字自动更新的关键

这是Quarto最强大的功能,也是最容易被忽视的。

普通写法(需要手动改):

本研究共纳入268例患者,其中男性145例(54.1%)。

Quarto写法(数据变了自动更新):

本研究共纳入 `r nrow(df)` 例患者,其中男性 `r sum(df$sex == "男")` 例`r round(mean(df$sex == "男") * 100, 1)`%)。

当你把样本量从268改成241,重新运行报告,这段文字里的数字自动变成正确的值,不会漏改任何一处。

09 第五步:完整的临床分析报告模板

下面是一个完整的临床分析报告.qmd文件,可以直接复制使用:

---title: "临床数据分析报告"author: "研究者姓名"date: todayformat:  docx:    toc: true    number-sections: true    fig-dpi: 300execute:  echo: false  warning: false  message: false  cache: true---```{r}#| label: setup#| cache: falselibrary(tidyverse)library(gtsummary)library(survival)library(survminer)library(broom)library(here)# 读取数据df <-readRDS(here("data", "processed", "clean_data.rds"))# 定义关键变量(只需要改这里,下面全部自动更新)N_TOTAL   <-nrow(df)N_MALE    <-sum(df$sex == "男性")PCT_MALE  <-round(mean(df$sex == "男性") * 1001)N_EVENT   <-sum(df$status == 1)```## 研究概述本研究共纳入 `rN_TOTAL` 例患者,其中男性 `rN_MALE` 例(`rPCT_MALE`%),随访期间共发生终点事件 `rN_EVENT` 例。## 基线特征```{r}#| label:tbl-baseline#| tbl-cap: "表1 基线特征"table1 <-df |>  select(-patient_id) |> # 这一步去掉了 ID 列  tbl_summary(    by = group,    statistic = list(      all_continuous()  ~ "{median} ({p25}, {p75})",      all_categorical() ~ "{n} ({p}%)"    )  ) |>  add_p() |>  add_overall() |>  bold_labels()table1```两组患者在年龄(P=`r inline_text(table1, variable=age, column="p.value")`)、性别构成方面差异无统计学意义。## 生存分析```{r}#| label: fig-km#| fig-cap: "图1 两组患者的生存曲线"#| fig-width: 8#| fig-height: 7km_fit <- survfit(Surv(time, status) ~ group, data = df)ggsurvplot(  km_fit,  data            = df,  pval            = TRUE,  risk.table      = TRUE,  palette         = c("#000000", "#888888"),  ggtheme         = theme_classic() +    theme(text = element_text(family = "Arial", size = 11)),  xlab            = "随访时间(月)",  ylab            = "生存率",  legend.title    = "分组",  legend          = c(0.85, 0.85))``````{r}#| label: km-stats#| include: false# 提取中位生存时间km_summary  <- summary(km_fit)$tablemedian_g1   <- km_summary["group=治疗组", "median"]median_g2   <- km_summary["group=对照组", "median"]logrank_p   <- surv_pvalue(km_fit, df)$pval```治疗组和对照组的中位生存时间分别为`r median_g1` 个月和 `r median_g2` 个月,Log-rank检验显示两组差异`r ifelse(logrank_p < 0.05, "有统计学意义", "无统计学意义")`(P=`r round(logrank_p, 3)`)。## Cox回归```{r}#| label: tbl-cox#| tbl-cap: "表2 多因素Cox回归分析"cox_model <- coxph(  Surv(time, status) ~ age + sex + stage + treatment,  data = df)cox_model |>  tbl_regression(exponentiate = TRUE) |>  bold_p()```## 统计方法本研究采用R软件(版本`r R.version.string`)进行统计分析,共纳入`r N_TOTAL`例患者。采用Kaplan-Meier法估计生存曲线,Log-rank检验比较组间差异。以Cox比例风险回归模型进行多因素分析,结果以风险比(HR)及95%置信区间(CI)表示。P<0.05为差异有统计学意义。

10 第六步:运行报告

在Positron终端运行:

# 生成Word文档quarto render my_analysis.qmd --to docx# 生成HTML报告quarto render my_analysis.qmd --to html# 同时生成两种格式quarto render my_analysis.qmd

或者在Positron里直接点击.qmd文件右上角的Render按钮。

第一次运行需要几分钟(安装依赖),之后因为有缓存,重新运行只需要几秒钟。

11 第七步:自定义Word样式

Quarto生成的Word文档默认样式比较朴素,可以用自己的模板样式。

# 第一步:生成默认模板quarto pandoc -o template.docx --print-default-data-file reference.docx# 第二步:在Word里修改template.docx的样式(字体、行距、标题样式等)# 第三步:在YAML里指定使用这个模板# format:#   docx:#     reference-doc: template.docx

12 第八步:用DeepSeek V4生成Quarto代码

COSTAR提示词——生成完整报告框架

把这段发给DeepSeek V4:

【C·背景】我要用Quarto写一份临床数据分析报告,数据结构如下:[粘贴 glimpse(df) 的完整输出]分析内容:- 基线特征表(按treatment分组)- KM生存曲线(time + status ~ treatment)- 多因素Cox回归(自变量:age, sex, stage, treatment)- 统计方法描述输出格式:Word文档和HTML(同时输出)运行环境:R 4.4.0,已安装tidyverse、gtsummary、survival、survminer【O·目标】生成完整的.qmd文件,要求:1. YAML头部配置(同时输出Word和HTML,cache=true,echo=false)2. Setup代码块(加载包,读取数据,计算关键统计数字存为变量)3. 使用内联代码 `r xxx` 让正文里的数字自动更新4. 每个图表有标签(label)和图题(fig-cap/tbl-cap)5. 统计方法部分用内联代码引用R版本【S·风格】符合临床SCI论文规范,图表格式满足期刊投稿要求【T·语气】解释三个最重要的设置:- cache: true 的作用- #| include: false 和 #| echo: false 的区别- 内联代码为什么比手动复制更可靠【A·受众】会R和ggplot2,但没用过Quarto的临床科研人员【R·格式】完整的.qmd文件内容(从---到最后),可以直接保存运行

13 常见问题和解决方法

Q1:运行报错"render failed",什么原因?

最常见的原因是代码块里有报错。Quarto运行时会把所有代码跑一遍,任何一个代码块出错都会导致整个报告失败。

解决方法:先在普通的.R脚本里把所有代码跑通,确认没有报错,再放到Quarto文件里。

Q2:中文显示乱码怎么办?

# 在YAML头部加这两行lang:zhmainfont:"Noto Sans CJK SC"# 或者 "Arial Unicode MS"

或者在代码块里设置:

#| label: setuplibrary(showtext)showtext_auto()font_add_google("Noto Sans SC""noto")

Q3:图片分辨率不够,期刊要求300DPI怎么设置?

format:docx:fig-dpi:300# 全局设置fig-width:8# 图宽(英寸)fig-height:6# 图高(英寸)

或者在单个代码块里设置:

#| fig-dpi: 300#| fig-width: 8#| fig-height: 6

Q4:cache让结果不更新了,怎么清除缓存?

quarto render my_analysis.qmd --cache-refresh

或者删除项目文件夹里的_cache文件夹,再重新运行。

Q5:想在报告里引用表格和图的编号怎么做?

如表 @tbl-baseline 所示,两组基线特征无统计学差异。 KM曲线见图 @fig-km。

对应的代码块需要有对应的label

#| label: tbl-baseline#| tbl-cap: "表1 基线特征"

Quarto会自动在"如表"后面填入正确的编号,调整顺序时编号自动更新。

这套流程和你现在的工作方式有什么不同

你现在的工作方式大概是这样的:

分析完成    ↓用ggsave导出图片文件    ↓打开Word,Insert图片    ↓把统计结果复制进去    ↓调整格式    ↓导师/审稿人说改数据    ↓重新跑代码    ↓重新导出图片    ↓回到Word,逐一替换数字    ↓检查有没有漏改    ↓祈祷

Quarto之后的工作方式:

写.qmd文件(代码+文字混在一起)    ↓运行一次    ↓Word和HTML都出来了    ↓导师/审稿人说改数据    ↓改数据    ↓再运行一次    ↓完成

14 写在最后

Quarto解决的不是一个小问题,是你每次修改数据时会花掉的几个小时。

这几个小时,乘以你这辈子要做的论文数量,是一个不小的数字。

我见过的最惨的情况,是有人把KM曲线的图更新了,但正文里引用的中位生存时间忘记改了。投稿出去了,被审稿人发现。

用Quarto,这件事不会发生。数字直接从代码里来,改了代码就全改了,不可能只改图忘记改文字。

这一行学习成本,换来的是之后每篇论文都省掉的那几个小时。

今天所有的Quarto代码、完整的报告模板、各种场景的COSTAR提示词,整理成了配套资料包。

加我微信进入R语言AI编程群获取。

扫码添加?

加了微信,告诉我你平时写报告用的是什么方式——Word手动、R Markdown还是其他?我来聊聊Quarto能帮你优化哪个环节。

群里每周都有类似的工作流更新,遇到问题直接在群里发,我当天回。

如果你身边有每次改数据都要手动更新Word的同学,把这篇文章发给他。省的不只是时间,是每次投稿前的那份焦虑。

你现在写分析报告用的是什么方式?评论区说说,我来看看你的流程有没有可以省掉的步骤。

发表评论
0评