威廉·鲍姆( 威杰鲍姆 ),新罕布什尔大学统计学研究生
我的项目是使用 JMP 脚本语言从多个网站提取数据来预测职业足球比赛的胜负。该脚本自动执行了原本费力的收集、汇总和重新组织数据以供分析的过程。脚本的几个部分包括不同的功能,例如用于消除下标的单元格处理以及多个数据集的串联和连接。使用关联数组来比较不同行中列公式的输出。最后,比较多个预测模型的结果。该项目的目的主要是说明如何使用 JSL 以可重复的方式自动执行数据收集、组织和预测过程。
介绍
大约两年前,我了解到 JMP 可以使用 JMP 脚本语言 [JSL] 从网络上抓取数据。作为一名统计学研究生,我经常寻找练习数据来磨练我的分析技能并改进我的编码。碰巧我是一个狂热的美式足球迷,体育统计数据很容易从网上的许多不同来源获得。作为一项练习,我尝试使用从网络上抓取的数据预测每个职业足球队在一个赛季的总胜场数。
数据抓取和清理技术可以应用于网络上以 html 表形式提供的任何数据。我发现 JSL 可用于在单个脚本或复合脚本组中自动清理数据并执行建模,这真是太神奇了。此外,JMP 还帮助那些编程经验有限的人,让用户通过其图形用户界面 [GUI] 进行分析,然后将该过程保存为可重复使用的脚本。这为用户在使用更新或新数据重复分析时节省了大量时间。
设置
第一步是创建文件夹,用于存储在数据聚合过程中创建的文件。我发现为每个数据源创建一个文件夹可以很好地组织生成的大量文件。

接下来,我要求脚本用户指定文件存储的本地路径,以使代码更清晰:dir = Pick Directory(“选择文件存储目录”,显示文件(0));
该本地路径也可以硬编码。
一旦选定了路径,数据就会从多个网站抓取并保存到单独的文件中(每个 HTML 表一个)。这些文件稍后在数据聚合阶段被引用。
抓取数据
使用 JMP,只需将 URL 名称从浏览器的地址栏复制并粘贴到 JSL 代码中即可。还可以直接在脚本中放置指向网站的链接,这有助于在编辑 JSL 代码时打开网站:Web("http://url_name.com");
导入数据
JMP 有各种有用的工具来帮助数据导入。首先,可以尝试直接将 html 表保存为 JMP 文件。当数据几乎不需要重新组织时,此方法最有效。第二种方法是先将 html 表保存为逗号分隔值 [CSV] 文件,然后可以使用 JSL 提供的用户定义设置将其导入 JMP。查看导入的表后,我注意到有几个空列。使用“删除列”命令,我能够用一个简短的脚本从表中删除空列。

JMP 会自动从网络中提取信息并保存文件。您不一定需要保存这些文件,但从网络抓取的数据有时会有点混乱。将数据保存到文件中可以更轻松地进行调试,因为您可以查看导入的表格并根据需要调整代码。
方法 1
数据被导入并保存为 CSV 文件,最初:
ObjectName = Open(“http//:url_name1.com”,HTML 表(#))<< 设置名称(“TableName1”)<< Save(dir||“FileName1.csv”);
方法 2
数据直接导入JMP并保存:
对象名称 = 打开(“http://url_name2.com”, HTML 表 (#) << 设置名称 (“TableName2”) << 保存 (dir||“FileName2.jmp”);

细胞处理
在脚本中对字符数据进行排序时,即使导入的字符串有细微的变化,也会导致代码出错。在本例中,季后赛即将到来,为了表明新英格兰队已经夺得分区冠军,球队名称中插入了一个“z”。幸运的是,JMP 提供了多种命令来操作单元格内的字符串。

在以下脚本中,JMP 循环遍历“Team”名称列的每一行,并删除出现在字符串开头的指定字母。“For Each Row”命令可轻松实现循环,该命令将一个过程应用于每一行。条件“if, then”短语告诉 JMP 在特定条件适用时该做什么。“Contains”命令返回字符串中指定项的位置。“Substr”(子字符串)命令返回字符串的一部分:从指定位置开始,返回指定数量的字符。

合并表
通过“表格”菜单,在 JMP 中合并表格非常容易。表格菜单提供多个选项。通常,我使用“连接”来合并具有不同列但具有相同行标签的表格。当我合并具有不同行标签但具有相同列的表格时,我使用“连接”。在本例中,我连接了来自多个表格的信息。为每个团队部门创建了一个表格。接下来,我按团队名称的字母顺序对结果文件的行进行排序,以确保稍后在连接过程中匹配相同的行。

创建新表
我发现在连接表格之前创建一个新表格很有用。JMP 允许用户通过几种方式创建新表格。首先,可以通过 GUI 完成。也可以通过脚本完成。在本例中,我使用“新建表格”命令创建一个具有适当行数的新表格:每个足球队一个。然后,我使用“新建列”命令添加了球队名称列,并使用列表设置值。

连接表
我发现如果没有 JMP,连接表格会是一件烦人的事情。幸运的是,JMP 在“表格”菜单中有一个不错的 GUI 用于连接表格。虽然命名约定始终很重要,但 JMP 会自动重命名来自不同表格但共享相同名称的列。在这种情况下,我通过 GUI 连接表格,然后简单地将结果表格的表格脚本复制并粘贴到我更大的自定义脚本中。否则,在连接表格之前,我得输入很多内容(重命名列)。我多次重复了连接过程。

重命名和重新格式化列
完成连接后,我得到了很多听起来很奇怪的列名。为了消除混淆,我重命名了这些列。为此,我首先创建了一个首选名称列表。然后,我使用循环和“设置名称”函数的组合重命名了这些列。

有时 JMP 会将数据导入为字符串,但用户需要不同的列格式,例如时间。这很容易在 JMP GUI 中更改,但也可以在 JSL 脚本中完成。在这种情况下,我让 JMP 知道该列包含连续时间信息,而不是字符。
重新组织列
汇总数据并创建新列后,可能想要更改数据表中列的顺序。使用 JSL 中的“移动选定列”命令可以轻松完成此操作。

数据表视图
这是已完成的数据表的部分视图。

开发关联数组
完成数据汇总后,就该进行一些分析了。我想比较的第一件事是不同球队在赛季到那个时间点之前的相对实力,基于他们的赛程强度。我的目标是预测一支球队未来的表现有多强,不仅基于他们自己过去的表现,还基于他们未来对手的过去表现。为了做到这一点,我必须比较表格中不同行和列的单元格中包含的信息。创建关联数组(又称字典或哈希映射)对于此任务非常有用。
在 JMP 中,可以使用列表、矩阵或关联数组中的列。在本例中,我使用了两列,默认值为空。键列“TEAM”包含每个球队的城市名称缩写。值列称为“Strength”,是一个公式列,用于计算指数,结合胜场数和净得分。我使用 17 周比赛日程表的每一周(一列)作为键来引用该周的关联数组值。
17 周课程表:钥匙

在脚本中,我定义了关联数组,然后创建了一个公式列来引用它。同样,公式通过关联数组的下标引用正确的值,使用每周对手作为键。如果键列中的值不在关联数组中,则该函数返回一个空值(适用于赛程中的休息周)。

然后,我为每周创建了一个新列,用于比较团队实力。这两个公式本来可以合并,但我更愿意将它们分开,这样我就可以在数据表中直观地看到不同的指标。

接下来,我计算了本赛季预测的获胜次数。计算列结果的一种简单方法是创建一个新的公式列,其中包含 17 列中每一列的一系列“如果-那么”条件的总和。在这种情况下,如果实力差异为正,则预测被视为获胜并计算在内。

创建预测模型
JMP 有多种预测建模技术。许多技术都可以通过“分析”菜单访问,包括“拟合模型”和“神经”平台。创建自定义脚本时,我建议首先在 JMP 平台中开发最佳模型。然后,可以将模型脚本保存到数据表(通过 GUI),并将代码复制并粘贴到自定义脚本中。还可以使用 JSL 将模型脚本保存到数据表。这使用户可以灵活地将模型设置为自动运行,或者使模型在自定义脚本创建的表的数据表脚本列表中可用。
以下是一个例子。

JMP Pro 中的高级建模技术
JMP Pro 提供了几种高级建模技术,而标准版 JMP 则不提供这些技术。两个例子是神经网络的增强版本和弹性网络广义回归技术。JMP 的另一个优点是它能够按照用户指定的比例执行保留验证,自动从数据集中选择一个随机样本。这简化了验证和模型比较。
增强神经网络

弹性网络

有时,多个模型预测的平均值可能会优于单个模型的性能。
这里我在 JSL 中创建了一个公式列,对两个预测公式进行平均。

JMP Pro 有一个模型比较平台,用户可以在其中并排比较多个模型的相对有效性。模型比较平台还允许用户只需单击几下即可对多个模型进行平均。
模型比较

在这种情况下,神经网络和弹性网络模型(带保留验证 [HB])的平均值略优于单独使用两个模型中的任何一个。模型比较平台的另一个不错的功能是“实际与预测”和“残差与行”图。
模型比较图

结论
借助 JMP 脚本语言 [JSL],JMP 可以从多个 Web 源抓取数据、处理数据、执行多个预测、比较并显示它们 - 所有这些都在一个脚本中完成。有效使用 JSL 可以节省大量时间,尤其是在必须定期重复分析时。