如何使用 JSL 基于随机列创建平均值列我想根据一些选择条件创建一个列列表。列名事先未知。然后,我使用该列列表创建一个公式列,计算这些列的平均值(或标准差或数量)。
一个简单的示例脚本,它会读取所有数值列:
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For(i=1, i<=NCols(), i++,
If(Column(i)<
<GETDATATYPE></GETDATATYPE>
<BR /> <BR /> <P>请注意,ColList 是一个有效的列列表。当将其插入到第一列公式中时,公式编辑器中的预览显示计算结果正确,但该列仍然为空。显然,我们需要在 Mean() 函数中插入标量、列表或矩阵(但预览无论如何都会正常工作)。</P> <P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><span class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><img src="https://us.v-cdn.net/6038925/uploads/images/115064i3C11FFA7C1D866DE/pauldeen_0-1788272598908.png" role="button" title="pauldeen_0-1788272598908.png" alt="pauldeen_0-1788272598908.png" /></span><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN></P> <P>第二个公式列在列引用周围添加了 AsColumn() 函数……这有点违反直觉,因为它本身就是一列。但现在它会创建一个列表、标量或矩阵,并且 mean() 公式就能正常工作了。</P> <P>感觉我把事情想得太复杂了。有没有更简单的方法来程序化地生成这样的汇总列?</P>
回复:如何使用 JSL 基于随机列创建平均值列通常对于像这样的简单情况,我会使用 Substitute 将列表替换为其他表达式。
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
collist = dt << Get Column Names("Numeric", "String");
colrefs = Transform Each({colname}, collist,
Name Expr(As Column(dt, colname))
);
mexpr = Substitute(colrefs, Expr(List), Expr(Mean));
Eval(EvalExpr(
dt << New Column("AVG", Numeric, Continuous, Formula(
Expr(Name Expr(mexpr))
));
));
Write();
回复:如何使用 JSL 基于随机列创建平均值列谢谢,但这仍然是针对简单问题的进阶解决方案。我仍然很想知道是否有人能找到更简单的方法,将列引用添加到列公式中。
回复:如何使用 JSL 基于随机列创建平均值列假设我们在表 dt 中有一个名为“TEST”的列。“基本”之间存在差异
- 列(dt, "TEST")
- AsColumn(dt, "TEST")
- “测试”
- 名称表达式(作为列(dt, "TEST"))
查看更多...
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
Row() = 0; // default row value
col = "Size";
Show(col);
Show(Column(dt, col));
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
Write("\!N\!N");
Row() = 1;
Show(Column(dt, col)[Row()]);
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
您在寻找哪种解决方案?除非您在公式中使用方括号 [] 或 [Row()],否则您不能直接在公式中添加列引用。如果您获取的列是引用(或字符串),通常需要将其转换为“列访问”才能在公式中使用。
回复:如何使用 JSL 基于随机列创建平均值列我向JMP提交了一份错误报告。
这个错误在于列公式不接受 `Column(“name”)` 参数,而是必须先用 `As Column()` 表达式包裹起来。在使用可视化公式编辑器时,可以在参数字段中拖放列,因此 JSL 也应该体现相同的行为。将此功能添加到 JSL 中将大大简化从 JSL 创建列公式的过程。
显然,公式编辑器中的预览窗口能够正确解读这一点,因为它会显示预览。
回复:如何使用 JSL 基于随机列创建平均值列Column() 和 AsColumn()/:colname 并不相同,不应该以类似的方式使用。
我认为问题出在公式编辑器上,以及它显示使用 JSL 构建的公式的方式上。它会漏掉错误的公式(就像这个例子一样),而且应该显示错误信息的时候它也不会显示。
jthi_1-1788881236165.pngjthi_1-1788881236165.pngjthi_1-1788881236165.png
jthi_2-1788881243139.pngjthi_2-1788881243139.pngjthi_2-1788881243139.png
jthi_4-1788881274171.pngjthi_4-1788881274171.pngjthi_4-1788881274171.png
在这种情况下,它应该在列属性中显示此信息。
jthi_7-1788882167381.pngjthi_7-1788882167381.pngjthi_7-1788882167381.png
以及公式编辑器中的这个
jthi_6-1788882151203.pngjthi_6-1788882151203.pngjthi_6-1788882151203.png
如果你尝试应用它,会报这样的错误
jthi_5-1788882131736.pngjthi_5-1788882131736.pngjthi_5-1788882131736.png
如果将其修改为 Column()[],则显示正确,并且返回正确的结果。
jthi_0-1788880964367.pngjthi_0-1788880964367.pngjthi_0-1788880964367.png
但最终由 JMP 开发人员决定这种行为应该如何表现。
回复:如何使用 JSL 基于随机列创建平均值列Jarmo 的观点很好,并提供了一个使用 Column("name")[] 的替代方案。正如 Jarmo 所提到的,在公式编辑器中使用 Column("name")[] 看起来不太美观。我下面的解决方案没有涉及这个选项,但它解释了为什么很多用户会对此感到困惑。它确实重复了 Jarmo 已经发布的很多内容,但既然我已经输入好了……
实际上,楼主提供的脚本并非漏洞。这是预期行为,也说明了许多用户在引用列以及列公式求值方面存在的困惑。
造成困惑的关键在于理解 `Column("name")` 语法和 `:name` 语法之间的区别。在某些情况下,两者都是引用列的合法方式,但它们返回的值不同。具体来说,`Column("name")` 返回的是对列对象的引用,而 `:name` 返回的是当前行 `name` 列中的值。顺便一提,`:name` 是函数 `As Column("name")` 的运算符形式。换句话说,它们本质上是相同的。
以下示例脚本可供参考。该脚本假设您的 JMP 会话中已打开并更新了 Cars.jmp 数据表。
Names Default To Here(1);
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
// sending messages to a column; either syntax works
Column(dt, "Year") << Set Property("Range Check", LELE(87, 97));
dt:Head IC << Set Property("Spec Limits", {LSL( 150 ), Show Limits( 1 )});
// Return values
// returns a column object reference shown as Column( "Year" ) in log
Column(dt, "Year"); // returns Column( "Year" )
// returns value in Year column on the current row.
// Since current row is 0 (the default invalid row number), returns missing (.)
:Year; // returns .
// Set the current row to the first row
Row() = 1;
:Year; // returns 87
考虑到以上信息,应该很清楚 JMP 无法计算一组列引用的平均值。这就是为什么第一列公式无法成功计算的原因。`Mean()` 函数需要值——这些值在第二列公式中提供。数据表在计算列公式时,会将当前行设置为 1,然后计算存储在“公式”属性中的表达式。它会将返回值放入当前行的列单元格中。然后,它会将当前行设置为下一个值并重复此过程。这些步骤会一直重复,直到计算完最后一行的公式。因此,列公式的语法必须能够对数据表的每一行都进行计算。
对我来说,你的示例脚本中有一个出乎意料的结果。那就是 `As Column(Column("name"))` 语法与 `As Column("name")` 的计算结果相同。我原本以为它会报错,但 JMP 却接受了它并正确理解了其意图。这就是脚本语言相对于正式编程语言的(有时)优势。不过,我不建议使用这种语法,因为它将来可能会出错。
我认为,根据示例脚本,实现目标的最佳方法是放弃第一种方法中的列公式,而采用第二种方法。此外,还需要将 ColList 定义为列名列表,而不是列引用。以下是修改后的 OP 脚本示例,应该更加稳定可靠。
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For( i = 1, i <= N Cols(), i++,
If( Column( i ) << GetDataType == "Numeric",
Insert Into( ColList, <FONT color="#FF6600"><STRONG>Column( i ) << Get Name</STRONG></FONT> )
)
);
MeanExpr2 = Name Expr( Mean() );
For( i = 1, i <= N Items( ColList ), i++,
Insert Into( MeanExpr2, Name Expr( As Column( ColList[i] ) ) )
);
Eval( Eval Expr( dt << New Column( "Average of numerics 2", Formula( Expr( Name Expr( MeanExpr2 ) ) ) ) ) );
回复:如何使用 JSL 基于随机列创建平均值列从理论和实际实现机制的角度来看,您说的或许完全正确……但用户界面并非如此运作。我可以从表格中选择列,然后将它们拖到 mean() 运算符上进行计算。然而,在脚本中,我无法选择列,而必须选择字符串对象(对应于列名),然后告诉 JSL 将它们解释为列引用,之后才能将这些引用注入到 mean 运算符中。如果能改进 JSL 运算符,使其将 Column("Name") 视为可以索引到行的列对象,岂不是一个简单的解决方案?这样做会更加直观,也更符合用户界面的行为和用户的思维方式。正如您所指出的,用户对此有很多困惑。
正如 Jarmo 所指出的:公式编辑器中的错误信息需要改进,使其更加清晰一致。再次强调:请注意,预览显示计算结果正确,但使用 Column("Name") 语法时,公式实际计算却失败。