> 用于决策分析的模拟



首先，从 “模拟（Simulate）” 标签页的 “选择类型（Select types）”  下拉菜单中选择模拟中使用的变量类型。可用类型包括二项分布（Binomial）、常数（Constant）、离散分布（Discrete）、对数正态分布（Log normal）、正态分布（Normal）、均匀分布（Uniform）、数据（Data）、网格搜索（Grid  search）和序列（Sequence）。

### 二项分布（Binomial）

使用 “二项分布变量（Binomial variables）” 输入框添加二项分布随机变量。首先指定名称（`crash`）、试验次数（n）（例如 20）和成功概率（p）（0.01），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`crash 20 .01`）。

### 常数（Constant）

在 “常数变量（Constant variables）” 输入框中列出分析中要包含的常数。你可以直接在文本区域输入名称和值（例如`cost 3`），或者分别在 “名称（Name）” 和 “值（Value）” 输入框中输入名称（`cost`）和值（5），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。点击<i title='Remove variable' href='#' class='fa  fa-minus-circle'></i>图标可删除条目。注意，只有（较大的）文本输入框中列出的变量才会包含在模拟中。

### 离散分布（Discrete）

使用 “离散分布变量（Discrete variables）” 输入框定义离散分布随机变量。首先指定名称（`price`）、取值（6 8）及其相关概率（.3 .7），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`price 6 8 .3 .7`）。注意，概率之和必须为 1，否则会显示错误信息，模拟无法运行。

### 对数正态分布（Log Normal）

要在分析中包含对数正态分布随机变量，从 “选择类型（Select types）” 下拉菜单中选择 “对数正态分布（Log Normal）”，并使用  “对数正态分布变量（Log-normal variables）” 输入框。更多信息见下文 “正态分布（Normal）” 部分。

### 正态分布（Normal）

要在分析中包含正态分布随机变量，从 “选择类型（Select types）” 下拉菜单中选择 “正态分布（Normal）”，并使用 “正态分布变量（Normal variables）” 输入框。例如，输入名称（`demand`）、均值（Mean）（1000）和标准差（St.dev.）（100），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`demand 1000 100`）。

### 泊松分布（Poisson）

泊松分布适用于模拟特定时间范围内事件发生的次数，例如晚上 10 点到 11 点急诊室的就诊人数。要在分析中包含泊松分布随机变量，从 “选择类型（Select types）” 下拉菜单中选择  “泊松分布（Poisson）”，并使用 “泊松分布变量（Poisson variables）” 输入框。例如，输入名称（`patients`）和事件发生次数的参数 “Lambda” 值（20），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`patients 20`）。

### 均匀分布（Uniform）

要在分析中包含均匀分布随机变量，从 “选择类型（Select types）” 下拉菜单中选择 “均匀分布（Uniform）”，在 “均匀分布变量（Uniform variables）” 输入框中提供参数。例如，输入名称（`cost`）、最小值（Min）（10）和最大值（Max）（15），然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`cost 10 15`）。

### 数据（Data）

要在 “模拟公式（Simulation formulas）” 输入框指定的计算中包含来自其他数据集的变量，从 “计算输入数据（Input data  for calculations）” 下拉菜单中选择数据集。这与 “网格搜索（Grid search）”  功能结合使用时，对投资组合优化非常有用。但与其他输入结合使用时，必须确保不同计算返回的值数量相同，否则会出现如下错误：

`Error: arguments imply differing number of rows: 999, 3000`

### 网格搜索（Grid search）

要包含值序列，从 “选择类型（Select types）” 下拉菜单中选择 “网格搜索（Grid search）”，在 “网格搜索（Grid search）” 输入框中提供最小值、最大值和步长。例如，输入名称（`price`）、最小值（Min）（4）、最大值（Max）（10）和步长（Step）（0.01）。如果在 “网格搜索（Grid search）” 中指定多个变量，模拟会生成并评估所有可能的取值组合。例如，假设在 “网格搜索（Grid  search）” 文本输入框中定义第一个变量为`x 1 3 1`，第二个为`y 4 5 1`，则会生成以下数据：

<table class='table table-condensed table-hover' style='width:40%;'>
 <thead>
  <tr>
   <th style="text-align:left;"> x </th>
   <th style="text-align:left;"> y </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 1 </td>
   <td style="text-align:left;"> 4 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 4 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 4 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 1 </td>
   <td style="text-align:left;"> 5 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 5 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 5 </td>
  </tr>
</tbody>
</table>

注意，如果选择了 “网格搜索（Grid search）”，生成的值数量将覆盖 “模拟次数（# sims）” 或 “重复次数（# reps）”  中指定的数量。如果不希望如此，请使用 “序列（Sequence）”。然后点击<i title='Add variable'  href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`price 4 10 0.01`）。

### 序列（Sequence）

要包含值序列，从 “选择类型（Select types）” 下拉菜单中选择 “序列（Sequence）”，在 “序列变量（Sequence variables）” 输入框中提供最小值和最大值。例如，输入名称（`trend`）、最小值（Min）（1）和最大值（Max）（1000）。注意，“步数” 由模拟次数决定。然后点击<i title='Add variable' href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本输入区域输入（或删除）内容（例如`trend 1 1000`）。

### 公式（Formulas）

要使用生成的变量执行计算，在主面板的 “模拟公式（Simulation formulas）” 输入框中创建公式（例如`profit = demand * (price - cost)`）。公式用于向模拟添加（计算得到的）变量或更新现有变量。必须在`=`左侧指定新变量的名称。变量名称可包含字母、数字和`_`，但不能包含其他字符或空格。可以输入多个公式。例如，如果还想计算每次模拟的边际利润，在第一个公式后按回车，输入`margin = price - cost`。

“数据> 转换” 标签页中 “创建（Create）” 功能和 “数据 > 查看” 标签页中 “筛选数据（Filter data）” 功能使用的许多函数也可包含在公式中。可以使用`>`和`<`符号并组合它们。例如，`x > 3 & y == 2`在变量`x`的值大于 3**且**变量`y`的值等于 2 时，结果为`TRUE`。注意，在 R 和大多数其他编程语言中，`=`用于**赋值**，`==`用于判断变量值是否**恰好等于**某个值。相反，`!=`用于判断变量值**不等于**某个值。也可以使用包含**或（OR）** 条件的表达式。例如，要判断 “Salary” 小于 100,000 美元**或**大于 20,000 美元，使用`Salary > 20000 | Salary < 100000`。`|`是**或（OR）** 的符号，`&`是**且（AND）** 的符号（另见 “数据> 查看” 的帮助文件）。

下面展示几个公式示例：

- 创建新变量 z，为变量 x 和 y 的差值

```r
z = x - y
```

- 创建新的逻辑变量 z，当 x > y 时取值为 TRUE，否则为 FALSE

```r
z = x > y
```

- 创建新的逻辑变量 z，当 x 等于 y 时取值为 TRUE，否则为 FALSE

```r
z = x == y
```

- 上面的命令与下面使用`ifelse`的命令等效。注意与 Excel 中的`if`语句类似

```r
z = ifelse(x < y, TRUE, FALSE)
```

- `ifelse`语句也可用于创建更复杂的（数值）变量。在下面的示例中，如果 x 小于 60，z 取值为 0；如果 x 大于 100，z 取值为 1；最后，当 x 为 60、100 或介于 60 到 100 之间时，z 取值为 2。**注意：** 确保包含适当数量的左括号`(`和右括号`)`！

```r
z = ifelse(x < 60, 0, ifelse(x > 100, 1, 2))
```

- 创建新变量 z，为变量 x 的转换，且均值为 0：

```r
z = x - mean(x)
```

- 创建新变量 z，为 x 的绝对值：

```r
z = abs(x)
```

- 要找到使`profit`最大化的`price`值，使用`find_max`命令。在本示例中，`price`可以是随机变量或 “序列变量（Sequence variable）”。还有`find_min`命令。

```r
optimal_price = find_max(profit, price)
```

- 要确定多个变量（例如 x 和 y）中每对值的最小值（最大值），使用函数`pmin`和`pmax`。在下面的示例中，当 x 大于 y 时，z 取值为 x；否则，z 取值为 y。

```r
z = pmax(x, y)
```

示例见下表：

<table class='table table-condensed table-hover' style='width:40%;'>
 <thead>
  <tr>
   <th style="text-align:left;"> x </th>
   <th style="text-align:left;"> y </th>
   <th style="text-align:left;"> pmax(x,y) </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 1 </td>
   <td style="text-align:left;"> 0 </td>
   <td style="text-align:left;"> 1 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 3 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 8 </td>
   <td style="text-align:left;"> 8 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 4 </td>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 4 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 5 </td>
   <td style="text-align:left;"> 10 </td>
   <td style="text-align:left;"> 10 </td>
  </tr>
</tbody>
</table>
- 与`pmin`和`pmax`类似，有一些函数可用于计算多个变量的汇总统计量。例如，`psum`计算不同向量元素的总和。更多信息见<a href="https://radiant-rstats.github.io/radiant.data/reference/pfun.html" target="_blank">https://radiant-rstats.github.io/radiant.data/reference/pfun.html</a>。

```r
z = psum(x, y)
```

示例见下表：

<table class='table table-condensed table-hover' style='width:40%;'>
 <thead>
  <tr>
   <th style="text-align:left;"> x </th>
   <th style="text-align:left;"> y </th>
   <th style="text-align:left;"> psum(x,y) </th>
  </tr>
 </thead>
<tbody>
  <tr>
   <td style="text-align:left;"> 1 </td>
   <td style="text-align:left;"> 0 </td>
   <td style="text-align:left;"> 1 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 5 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 3 </td>
   <td style="text-align:left;"> 8 </td>
   <td style="text-align:left;"> 11 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 4 </td>
   <td style="text-align:left;"> 2 </td>
   <td style="text-align:left;"> 6 </td>
  </tr>
  <tr>
   <td style="text-align:left;"> 5 </td>
   <td style="text-align:left;"> 10 </td>
   <td style="text-align:left;"> 15 </td>
  </tr>
</tbody>
</table>


其他常用函数包括`ln`（自然对数，例如`ln(x)`）、`sqrt`（x 的平方根，例如`sqrt(x)`）和`square`（计算变量的平方，例如`square(x)`）。

要从计算中返回单个值，使用`min`、`max`、`mean`、`sd`等函数。

- 投资组合优化中一个有用的特殊函数是`sdw`。它接受权重和变量作为输入，返回变量加权和的标准差。例如，要计算三只股票（如波音、通用汽车和埃克森美孚）投资组合的标准差，可在 “模拟公式（Simulation formulas）” 输入框中使用以下方程。`f`和`g`可以是值（例如 0.2 和 0.8），或通过 “网格搜索（Grid search）” 输入框指定的不同权重向量（见上文）。`Boeing`、`GM`和`Exxon`是使用 “数据（Data）” 输入框（见上文）包含在模拟中的数据集中的变量名称。

```r
Pstdev = sdw(f, g, 1-f-g, Boeing, GM, Exxon)
```

关于如何使用模拟工具进行投资组合优化的示例，见可下载的状态文件<a  href="https://radiant-rstats.github.io/docs/examples/investment-3stocks.state.rda">此处</a>。

### 函数（Functions）

可能 R 中可用的标准函数不足以灵活地进行你想要的模拟。如果是这种情况，点击屏幕左下角的 “添加函数（Add functions）”  复选框，在主面板的 “模拟函数（Simulation functions）” 输入框中创建自定义函数。要学习编写 R 函数，<a  href="https://www.statmethods.net/management/userfunctions.html"  target="_blank">https://www.statmethods.net/management/userfunctions.html</a>是一个很好的起点。

关于如何在赌博模拟中使用自定义 R 函数的示例，见可下载的状态文件<a  href="https://radiant-rstats.github.io/docs/examples/gamblers-ruin.state.rda">此处</a>。通过 “报告> Rmd” 生成的<a  href="https://radiant-rstats.github.io/docs/examples/gamblers-ruin.nb.html" target="_blank">报告</a>提供了关于模拟设置和函数使用的更多信息。

### 运行模拟

“模拟次数（# sims）” 输入框中显示的值决定模拟**抽取**的次数。要使用相同的随机生成值重新进行模拟，在 “设置随机种子（Set random seed）” 输入框中指定一个数字（例如 1234）。

要保存模拟数据供进一步分析，在 “模拟数据（Simulated data）” 输入框中指定名称。然后，可在任何 “数据” 标签页（例如 “数据 > 查看”、“数据  > 可视化” 或 “数据 > 探索”）的 “数据集（Datasets）” 下拉菜单中选择指定名称的数据集，以研究模拟数据。

指定所有必要输入后，点击 “模拟（Simulate）” 按钮运行模拟。

在下方截图中，`var_cost`和`fixed_cost`被指定为常数。`E`服从均值为 0、标准差为 100 的正态分布。`price`是离散随机变量，取值为 6 美元（概率 30%）或 8 美元（概率 70%）。“模拟公式（Simulation formulas）”  文本输入框中有三个公式。第一个公式确定 “需求（demand）” 对模拟变量 “价格（price）”  的依赖关系；第二个公式指定利润函数；最后一个公式用于确定利润低于 100 的案例数量（和比例），结果赋值给新变量`profit_small`。

<p align="center"><img src="figures_model/simulater_sim.png"></p>

在 “模拟摘要（Simulation summary）” 的输出中，首先看到模拟规格的详细信息（例如模拟次数）。“常数（Constants）”  部分列出各模拟中不变的变量值。“随机变量（Random variables）” 和 “逻辑变量（Logicals）”  部分列出模拟结果。我们看到模拟中的平均 “需求（demand）” 为 627.94，标准差为  109.32。还提供了模拟数据的其他特征（例如最大利润为 1758.77）。最后，我们看到利润低于 100 的概率为 0.32（即 1000  次模拟中，有 315 次利润低于 100 美元）。

要查看随机变量以及使用 “模拟公式（Simulation formulas）” 创建的变量的直方图，请确保勾选 “显示图表（Show plots）”。

<p align="center"><img src="figures_model/simulater_sim_plot.png"></p>

由于我们在 “模拟数据（Simulated data）” 框中指定了名称，数据在 Radiant 中以`simdat`为名可用（见下方截图）。要在 Excel 中使用该数据，点击 “数据> 查看” 标签页右上角的下载图标，或前往 “数据 > 管理” 标签页将数据保存为 csv 文件（或使用剪贴板功能）。更多信息见 “数据 > 管理” 标签页的帮助文件。

<p align="center"><img src="figures_model/simulater_view.png"></p>

## 重复模拟

假设上述模拟用于更好地理解每日利润。要深入了解年度利润，我们可以重新运行模拟 365 次。但通过 “重复（Repeat）” 标签页的功能可以更方便地实现。首先，在 “要重新模拟的变量（Variables to re-simulate）” 中选择变量，此处为`E`和`price`。然后在 “输出变量（Output variables）” 框中选择关注的变量（例如`profit`）。将 “重复次数（# reps）” 设置为 365。

接下来，需要确定如何汇总数据。如果在 “分组依据（Group by）” 中选择 “模拟（Simulation）”，数据将按每次模拟抽取**在**365 次重复模拟中汇总，得到 1000 个值。如果选择 “重复（Repeat）”，数据将按每次重复**在**1000 次模拟中汇总，得到 365 个值。如果将完整的重复模拟数据集想象为 1000 行 365 列的表格，按 “模拟（Simulation）”  分组将为每行创建汇总统计量，按 “重复（Repeat）” 分组将为每列创建汇总统计量。在本示例中，要确定 365 次重复模拟的每日利润总和，在  “分组依据（Group by）” 框中选择 “模拟（Simulation）”，在 “应用函数（Apply function）” 框中选择  “sum”。

要确定年度利润低于 36,500 美元的概率，在 “重复模拟公式（Repeated simulation formula）” 文本输入框中输入以下公式：

```r
profit_365 = profit_sum < 36500
```

注意，`profit_sum`是 “模拟（Simulation）” 标签页中定义的`profit`变量的重复模拟总和。输入所有值后，点击 “重复（Repeat）” 按钮。由于我们为 “重复数据（Repeat data）” 指定了名称，将创建新数据集。`repdat`将包含按模拟分组的汇总数据（即 1000 行）。要存储所有 365×1000 次模拟 / 重复结果，从 “应用函数（Apply function）” 下拉菜单中选择 “none”。

重复模拟的描述性统计量显示在主面板的 “重复模拟摘要（Repeated simulation summary）” 下。我们看到公司的年度预期利润（即`profit_sum`的均值）为 172,311.84 美元，标准差为 10,772.29 美元。尽管上文发现每日利润可能低于 100 美元，但全年利润低于 365×100 美元的可能性几乎为零（即年度利润低于 36,500 美元的重复模拟比例为 0）。

<p align="center"><img src="figures_model/simulater_repeat.png"></p>

如果勾选 “显示图表（Show plots）”，“重复模拟图表（Repeated simulation plots）” 下将显示年度利润（`profit_sum`）的直方图。`profit_365`没有图表，因为它只有一个值（即 FALSE）。

<p align="center"><img src="figures_model/simulater_repeat_plot.png"></p>

下方截图中示例的状态文件可从<a href="https://radiant-rstats.github.io/docs/examples/sim-help.state.rda">此处</a>下载。

关于如何使用模拟工具找到最大化利润的价格的简单示例，见可下载的状态文件<a  href="https://radiant-rstats.github.io/docs/examples/iceskimo-optimal-price.state.rda">此处</a>。

### 在重复标签页中使用网格搜索

注意，“重复（Repeat）” 标签页也可以使用 “网格搜索（Grid search）” 输入，通过迭代方式替换 “模拟（Simulation）” 标签页中指定的一个或多个  “常数（Constants）” 来重复模拟。仅当 “分组依据（Group by）” 设置为 “重复（Repeat）” 时，才显示此输入选项。在  “网格搜索（Grid search）” 输入框中提供最小值、最大值和步长。例如，输入名称（`price`）、最小值（Min）（4）、最大值（Max）（10）和步长（Step）（0.01）。如果在 “网格搜索（Grid search）” 中指定多个变量，模拟会生成并评估所有可能的取值组合。注意，如果选择了 “网格搜索（Grid  search）”，生成的值数量将覆盖 “重复次数（# reps）” 中指定的数量。然后点击<i title='Add variable'  href='#' class='fa  fa-plus-circle'></i>图标。或者，直接在文本区域输入（或删除）内容（例如`price 4 10 0.01`）。

### 报告 > Rmd

通过点击屏幕左下角的<i title="report results" class="fa fa-edit"></i>图标或按键盘上的`ALT-enter`，向<a href="https://radiant-rstats.github.io/docs/data/report_rmd.html" target="_blank">*报告 > Rmd*</a>添加代码以（重新）创建分析。

如果已创建图表，可使用`ggplot2`命令或`patchwork`进行自定义。详见下方示例和<a href="https://radiant-rstats.github.io/docs/data/visualize.html" target="_blank">*数据 > 可视化*</a>。


```r
plot(result, custom = TRUE) %>%
  wrap_plots(plot_list, ncol = 2) + plot_annotation(title = "Simulation plots")
```

### R 函数

有关 Radiant 中用于构建和评估（重复）模拟模型的相关 R 函数概述，请参见<a href =  "https://radiant-rstats.github.io/radiant.model/reference/index.html#section-model-simulate" target="_blank">*模型 > 模拟*</a>。

`simulater`工具中使用的来自`stats`包的核心函数包括`rbinom`、`rlnorm`、`rnorm`、`rpois`和`runif`。

### 视频教程

将以下完整命令复制粘贴到 RStudio 控制台（即左下角窗口），按回车即可获取 Radiant 教程系列中模拟模块使用的所有材料：

<pre>usethis::use_course("https://www.dropbox.com/sh/72kpk88ty4p1uh5/AABWcfhrycLzCuCvI6FRu0zia?dl=1")</pre>

<a href="https://youtu.be/kYaRVbStwwI" target="_blank">在 Radiant 中设置模拟（一）</a>

- 本视频演示如何使用 Radiant 设置模拟
- 主题列表：
  - 泊松分布简介
  - 指定模拟
  - 模拟摘要解读

<a href="https://youtu.be/fsP4x5-MLsY" target="_blank">在 Radiant 中设置重复模拟（二）</a>

- 本视频展示如何使用 Radiant 设置重复模拟
- 主题列表：
  - 指定重复模拟
  - 重复模拟摘要解读

<a href="https://youtu.be/eMlQhmN7UUA" target="_blank">使用模拟解决概率问题（三）</a>

- 本视频演示如何使用 Radiant 中的模拟解决概率问题
- 主题列表：
  - 回顾设置（重复）模拟
  - 模拟摘要解读
  - 重复模拟工作原理的直观理解

<a href="https://youtu.be/gxzrVtAefoo" target="_blank">模拟公式技巧（四）</a>

- 本视频讨论模拟公式中常用的一些实用函数
- 主题列表：
  - 使用`ifelse`指定模拟公式
  - 使用`pmax`指定模拟公式

<a href="https://youtu.be/vCExcD24ACM" target="_blank">在模拟中使用网格搜索（五）</a>

- 本视频演示如何在模拟中使用网格搜索
- 主题列表：
  - 通过排序模拟数据或创建图表找到最优值
  - 使用`find_max`函数找到最优值
