2.2 Bookdown 中的 Markdown 功能拓展

尽管 Pandoc 风格的 Markdown 比原来的 Markdown 语法要丰富得多,但它仍然缺少我们在学术写作中可能需要的一些东西。例如,它支持数学公式,但不能在多页 HTML 或 EPUB 输出中对公式进行编号和引用。我们在 bookdown 中提供了一些 Markdown 扩展来填补这些空白。

2.2.1 方程编号与引用

To number and refer to equations, put them in the equation environments and assign labels to them using the syntax (\#eq:label), e.g.,

要对方程进行编号和引用,请将它们放在方程环境中,并使用语法 (\#eq:label) 为它们指定标签,例如:

\begin{equation} 
  f\left(k\right) = \binom{n}{k} p^k\left(1-p\right)^{n-k}
  (\#eq:binom)
\end{equation} 

方程将展示如下:

\[\begin{equation} f\left(k\right)=\binom{n}{k}p^k\left(1-p\right)^{n-k} \tag{2.1} \end{equation}\]

你可以使用 \@ref(eq:binom) 来引用它,例如:请看方程 (2.1)

方程标签在 bookdown 中必须以前缀 eq: 开头。bookdown 中的所有标签只能包含字母数字字符、:- 和/或 /。方程引用最适合 LaTeX/PDF 输出格式,它们在 Word 或电子书中没有收到很好的支持。对于 HTML 输出,bookdown 只能对带有标签的方程进行编号。请确保没有标签的方程没有使用 equation* 环境或在方程中添加 \nonumber\notag 进行编号。同样的规则也适用于其他数学环境,如 eqnarraygatheralign 等(例如可以使用 align* 环境)。

我们将在下面演示更多的数学方程环境。下面是一个使用 equation* 环境的未编号方程:

\begin{equation*} 
\frac{d}{dx}\left( \int_{a}^{x} f(u)\,du\right)=f(x)
\end{equation*} 

\[\begin{equation*} \frac{d}{dx}\left( \int_{a}^{x} f(u)\,du\right)=f(x) \end{equation*}\]

下面展示了一个 align 环境 (2.2):

\begin{align} 
g(X_{n}) &= g(\theta)+g'({\tilde{\theta}})(X_{n}-\theta) \notag \\
\sqrt{n}[g(X_{n})-g(\theta)] &= g'\left({\tilde{\theta}}\right)
  \sqrt{n}[X_{n}-\theta ] (\#eq:align)
\end{align} 

\[\begin{align} g(X_{n}) &= g(\theta)+g'({\tilde{\theta}})(X_{n}-\theta) \notag \\ \sqrt{n}[g(X_{n})-g(\theta)] &= g'\left({\tilde{\theta}}\right) \sqrt{n}[X_{n}-\theta ] \tag{2.2} \end{align}\]

你可以在 equation 中使用 split 环境,以便所有行共享相同的编号 (2.3)。默认情况下,align 环境中的每一行都将被分配一个方程编号。在前面的示例中,我们使用 \notag 取消了第一行的编号。在本例中,整个 split 环境被分配了一个编号。

\begin{equation} 
\begin{split}
\mathrm{Var}(\hat{\beta}) & =\mathrm{Var}((X'X)^{-1}X'y)\\
 & =(X'X)^{-1}X'\mathrm{Var}(y)((X'X)^{-1}X')'\\
 & =(X'X)^{-1}X'\mathrm{Var}(y)X(X'X)^{-1}\\
 & =(X'X)^{-1}X'\sigma^{2}IX(X'X)^{-1}\\
 & =(X'X)^{-1}\sigma^{2}
\end{split}
(\#eq:var-beta)
\end{equation} 

\[\begin{equation} \begin{split} \mathrm{Var}(\hat{\beta}) & =\mathrm{Var}((X'X)^{-1}X'y)\\ & =(X'X)^{-1}X'\mathrm{Var}(y)((X'X)^{-1}X')'\\ & =(X'X)^{-1}X'\mathrm{Var}(y)X(X'X)^{-1}\\ & =(X'X)^{-1}X'\sigma^{2}IX(X'X)^{-1}\\ & =(X'X)^{-1}\sigma^{2} \end{split} \tag{2.3} \end{equation}\]

2.2.2 定理与证明

定理和证明常用于数学文章和书籍中。但是请不要被名称误导:“定理”只是一个编号或标记的环境,它不一定是一个数学定理(例如,它可以是一个与数学无关的例子)。类似地,“证明”是一个没有编号的环境。在这一节中,除非明确说明,否则我们总是使用“定理”和“证明”的一般含义。

bookdown 中,支持的定理环境类型在表 2.1。要写出一个定理,可以使用以下语法:

::: {.theorem}
This is a `theorem` environment that can contain **any**
_Markdown_ syntax.
:::

这个语法基于 Pandoc 的 fenced Div blocks,并且已经可以在任何 R Markdown 文档中用于编写自定义块Bookdown 只提供定理和证明环境的特殊处理。因为这使用了 Pandoc 风格的 Markdown 语法,所以可以在块内编写任何有效的 Markdown 文本。

表 2.1: Bookdown 中的定理环境。
Environment Printed Name Label Prefix
theorem Theorem thm
lemma Lemma lem
corollary Corollary cor
proposition Proposition prp
conjecture Conjecture cnj
definition Definition def
example Example exm
exercise Exercise exr
hypothesis Hypothesis hyp

要编写其他定理环境,请用表 2.1 中的其他环境名称替换 ::: {.theorem},例如 ::: {.lemma}

一个定理可以有一个 name 属性,这样它的名字就会被打印出来。例如:

::: {.theorem name="Pythagorean theorem"}
For a right triangle, if $c$ denotes the length of the hypotenuse
and $a$ and $b$ denote the lengths of the other two sides, we have
$$a^2 + b^2 = c^2$$
:::

如果你想引用一个定理,应该给它贴上标签。标签可以以 #label 的形式作为一个 ID 提供给块。例如:

::: {.theorem #foo}
A labeled theorem here.
:::

当你为一个定理贴上标签后,你可以使用语法 \@ref(prefix:label)来引用它。对于每个环境中的 prefix 值,请看表 2.1 中的 Label Prefix 列。例如,我们在下面有一个标记和命名了的定理,\@ref(thm:pyth) 给出了它的定理编号 2.1

::: {.theorem #pyth name="Pythagorean theorem"}
For a right triangle, if $c$ denotes the length of the hypotenuse
and $a$ and $b$ denote the lengths of the other two sides, we have

$$a^2 + b^2 = c^2$$
:::

定理 2.1 (Pythagorean theorem) 对于直角三角形,如果 \(c\) 表示斜边的长度,\(a\)\(b\) 表示另外两边的长度,我们有

\[a^2 + b^2 = c^2\]

目前支持的证明环境有 proofremarksolution。它的语法类似于定理环境,并且证明环境也能够使用 name 属性命名。唯一的区别是你不能引用它们,即便你为证明环境提供了 ID,因为它们无法进行编号。

无论你选择的输出是 PDF 还是 HTML,我们都已经尝试使所有这些定理和证明环境开箱即用。如果你是 LaTeX 或 HTML 专家,你可能希望自定义这些环境的样式(请参阅第 4 章)。使用 CSS 可以很容易在 HTML 中自定义样式,每个环境都包含在 <div></div> 中,CSS class 属性为环境名称,例如 <div class=“lemma”></div>。对于 LaTeX 输出,我们为环境 definitionexampleexercisehypothesis 预定义了样式 definition,为环境 proofremark 预定义了样式 remark。所有其他环境都使用 plain 样式。样式定义是通过 amsthm 包的 \theoremstyle{} 命令完成的。如果你不希望 bookdown 自动添加默认的定理定义,可以设置 options(bookdown.thermo.preamble = FALSE)。例如,使用输出格式 bookdown::pdf_book 和已经包含 amsmath 定义的 base_format 来避免单个文档(第 3.4 节)中的冲突非常有用。

默认情况下,定理按篇章编号。如果文档中没有篇章,则按小节编号。如果整篇文档没有编号(输出格式选项为 number_sections = FALSE),则所有定理都从 1、2、…、N 开始依次编号。LaTeX 支持依次对一个又一个定理环境进行编号,例如,让定理和引理共享同一个计数器。bookdown 中的 HTML/EPUB 输出不支持此操作。你可以通过定义自己的定理环境来更改 LaTeX 导言 (preamble) 中的编号方案,例如:

\newtheorem{theorem}{Theorem}
\newtheorem{lemma}[theorem]{Lemma}

bookdown 在 LaTeX 导言 (preamble) 中检测到 \newtheorem{themore} 时,它不会输出其默认的定理定义,这意味着你必须自己定义所有定理环境。为了简单和一致性,我们不建议你这样做。当 PDF 中的定理 18 变成 HTML 中的定理 2.4 时可能会令人十分困惑。

下面我们展示了定理和证明环境的更多的例子4,所以你可以在 bookdown 中看到默认样式。

定义 2.1 随机变量 \(x\) 的特征函数定义如下:

\[\varphi _{X}(t)=\operatorname {E} \left[e^{itX}\right], \; t\in\mathcal{R}\]

例 2.1 我们用概率密度函数 \(f(x)=\mathbf{1}_{x \in [0,1]}\) 导出了特征函数 \(X\sim U(0,1)\)

\[\begin{equation*} \begin{split} \varphi _{X}(t) &= \operatorname {E} \left[e^{itX}\right]\\ & =\int e^{itx}f(x)dx\\ & =\int_{0}^{1}e^{itx}dx\\ & =\int_{0}^{1}\left(\cos(tx)+i\sin(tx)\right)dx\\ & =\left.\left(\frac{\sin(tx)}{t}-i\frac{\cos(tx)}{t}\right)\right|_{0}^{1}\\ & =\frac{\sin(t)}{t}-i\left(\frac{\cos(t)-1}{t}\right)\\ & =\frac{i\sin(t)}{it}+\frac{\cos(t)-1}{it}\\ & =\frac{e^{it}-1}{it} \end{split} \end{equation*}\]

注意,我们使用了两次 \(e^{ix}=\cos(x)+i\sin(x)\)

引理 2.1 对任意两个随机变量 \(X_1\), \(X_2\),它们都具有相同的概率分布当且仅当

\[\varphi _{X_1}(t)=\varphi _{X_2}(t)\]

定理 2.2 如果 \(X_1\), …, \(X_n\) 是相互独立的随机变量。并且 \(a_1\), …, \(a_n\) 是一些常数,那么线性组合 \(S_n=\sum_{i=1}^na_iX_i\) 的特征函数是

\[\varphi _{S_{n}}(t)=\prod_{i=1}^n\varphi _{X_i}(a_{i}t)=\varphi _{X_{1}}(a_{1}t)\cdots \varphi _{X_{n}}(a_{n}t)\]

命题 2.1 独立且服从泊松分布的随机变量 \(X_i \sim \mathrm{Pois}(\lambda_i),\: i=1,2,\cdots,n\) 之和的分布是 \(\mathrm{Pois}(\sum_{i=1}^n\lambda_i)\).

证明. \(X\sim\mathrm{Pois}(\lambda)\) 的特征函数是 \(\varphi _{X}(t)=e^{\lambda (e^{it}-1)}\)。令 \(P_n=\sum_{i=1}^nX_i\)。我们从定理 2.2 可以知道

\[\begin{equation*} \begin{split} \varphi _{P_{n}}(t) & =\prod_{i=1}^n\varphi _{X_i}(t) \\ & =\prod_{i=1}^n e^{\lambda_i (e^{it}-1)} \\ & = e^{\sum_{i=1}^n \lambda_i (e^{it}-1)} \end{split} \end{equation*}\]

这是具有参数 \(\lambda=\sum_{i=1}^n \lambda_i\) 的服从泊松分布的随机变量的特征函数。从引理 2.1 可以知道 \(P_n\) 的分布是 \(\mathrm{Pois}(\sum_{i=1}^n\lambda_i)\)

Remark. 在以些情况下,使用特征函数计算独立随机变量之和的分布是非常方便和容易的。

推论 2.1 两个独立随机变量 \(X_1\)\(X_2\) 之和的特征函数是 \(X_1\)\(X_2\) 特征函数的乘积,即

\[\varphi _{X_1+X_2}(t)=\varphi _{X_1}(t) \varphi _{X_2}(t)\]

练习 2.1 (样本均值的特征函数) \(\bar{X}=\sum_{i=1}^n \frac{1}{n} X_i\)\(n\) 个独立同分布的随机变量的均值,每个变量具有特征函数 \(\varphi _{X}\)。计算 \(\bar{X}\) 的特征函数。

. 应用定理 2.2,我们得到

\[\varphi _{\bar{X}}(t)=\prod_{i=1}^n \varphi _{X_i}\left(\frac{t}{n}\right)=\left[\varphi _{X}\left(\frac{t}{n}\right)\right]^n.\]

假设 2.1 (黎曼猜想) 黎曼 Zeta 函数被定义为 \[\zeta(s) = \sum_{n=1}^{\infty} \frac{1}{n^s}\] 对于复数值 \(s\),当 \(s\) 的实部大于 1 时收敛。黎曼猜想是黎曼 zeta 函数只在负偶数和实部为 \(1/2\) 的复数处有零点。

2.2.2.1 关于旧语法的注记

对于较早版本的 bookdown(v0.21 之前),可以这样编写 theorem 环境:

```{theorem pyth, name="Pythagorean theorem"}
对于直角三角形,如果 $c$ 表示斜边的长度,$a$ 和 $b$ 表示另外两边的长度,我们有

$$a^2 + b^2 = c^2$$
```

这种语法仍然有效,但我们不建议使用这种语法,因为新语法允许编写更丰富的内容,并且具有更清晰的实现。

这两种语法之间的转换非常简单。上述定理可以这样改写:

::: {.theorem #pyth name="Pythagorean theorem"}
For a right triangle, if $c$ denotes the length of the hypotenuse
and $a$ and $b$ denote the lengths of the other two sides, we have

$$a^2 + b^2 = c^2$$
:::

&emso; 你可以使用帮助函数 bookdown::fence_theorems() 来转换整个文件或一段文本。这是一次性的操作。我们已经尝试过安全地从旧语法转换到新语法,但是可能错过了一些边缘情况。为确保不会意外覆盖 input 文件,可以将转换后的源代码写入新文件,例如:

bookdown::fence_theorems("01-intro.Rmd", output = "01-intro-new.Rmd")

然后仔细检查 01-intro-new.Rmd 的内容。使用 output = NULL 将在 R 控制台中打印转换结果,这是检查转换的另一种方法。如果你使用的是版本控制工具,则可以将 output 设置为与 input 相同,因为如果出现任何问题,你应该可以安全且轻松地还原更改。

2.2.3 特殊的标题

有几种特殊类型的一级标题在 bookdown 会以不同方式处理。第一种类型是没有编号的标题,以标志 (PART) 开头。这种类型的标题将会翻译为书籍各部份的标题。如果你熟悉 LaTeX 就应该知道它基本上等同于 \part{}。当你的书籍有大量章节时,你可能希望将它们组织成部分,例如:

# (PART) 第一部分 {-} 

# 第一章

# 第二章

# (PART) 第二部分 {-} 

# 第三章

各部分的标题应写在本部分第一章标题之前,两个标题应在同一文件中。如果各部分标题不应该参与自动编号,则可以使用 (PART\*)* 前的反斜杠是必须的)而不是 (PART)

第二种类型是以 (APPENDIX) 开头的无编号标题,表示此标题后面的所有章节都是附录,例如:

# 第一章

# 第二章

# (APPENDIX) 附录 {-} 

# 附录 A

# 附录 B

附录的编号样式将在 LaTeX/PDF 和 HTML 输出中自动更改(通常采用 A、A.1、A.2、B、B.1 等格式)。此功能不适用于电子书或 Word 输出。

2.2.4 文本引用

你可以将一些文本指定给标签,并使用文档中其他位置的标签来引用这些文本。这对于长图形/表格的标题(第 2.4 节和第 2.5 节)特别有用,在这种情况下,你通常需要将整个字符串写入区块标题(例如 fig.cap = "一张长图片的标题”)或 R 代码(例如kable(caption = “一个很长很长的表格的标题”))。当这些标题包含特殊的 HTML 或 LaTeX 字符时,它也很有用。例如,如果图片标题包含下划线,则它在 HTML 输出中正常工作,但在 LaTeX 输出中可能不起作用,因为下划线必须在 LaTeX 中进行转义。

文本引用的语法是 (ref:label) text。其中 text 的标签 label 是在整个文档中唯一的标签5。文本引用必须放在一个单独的段落中,上面和下面都有空行。段落不能有多行,也不能以空格结尾。例如,

(ref:foo) **在这里**定义一个文本引用。

然后你可以在图形/表格标题中使用 (ref:foo)。只要是一个段落,文本可以包含 Markdown 支持的任何内容。下面是一个完整的示例:

A normal paragraph.

(ref:foo) 使用 **base** R 图形系统绘制的数据集 `cars` 的散点图。

```{r foo, fig.cap='(ref:foo)'}
plot(cars)  # 绘制散点图
```

文本引用可以在文档中的任何位置使用(不仅限于图片标题)。如果你想在多个位置重用文本片段,它也很有用。


  1. 一些例子改编自维基百科页面 https://en.wikipedia.org/wiki/Characteristic_function_(probability_theory)↩︎

  2. 你可以考使用代码块标签↩︎