从数据列中减去子集平均值的公式?我正在寻找一种方法来获取仅使用与指定条件匹配的行的数据表的子集,并从列中减去这些行的平均值。
例如,使用 Big Class 数据集,假设我想创建一个新列来显示“该学生与 14 岁同性别平均身高之间的差异。”
我知道如何做到这一点的方法是添加第二个表,使用表 - >摘要 - >统计:平均值(身高),组:性别,子组:年龄。 然后我可以 Table -> Update: Big Class By (sex), Match columns: sex = sex,这将为 Mean(height, [age]) 添加几列。 然后我可以创建一个新列“Delta height vs 14yo of Same Sex”,即:height - :Mean(height, 14)。
我的问题:有没有什么方法可以在不创建额外的表和额外的列(例如“Mean(height, 14)”)的情况下完成? 看起来 Col Mean(x, byVar) 接近提供此功能,但缺乏选择不同组的功能;例如,我可以使用 :height - Col Mean(:height, :age, :sex) 来查找学生 X 与同性别和身高的平均学生之间的增量,但我不知道是否有办法指定在 Col 中意味着我只想考虑年龄=14 的行,而不是使用与该行关联的年龄值。
我非常频繁地进行这种类型的标准化,因此任何可以使其更快、更容易的方法都将受到极大的赞赏!
数据混合和清理回复:从数据列中减去子集平均值的公式?美丽的! 谢谢!!!
回复:从数据列中减去子集平均值的公式?你好@MarkJSchwab ,
是的,我可以看到在很多情况下用条件语句包装它可能并不理想。 这是一个修改@brady_brady应该有效的解决方案(附表):

testVal = :sex;
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == testVal )] );
在本例中,我们获取当前行的 :sex 值,并将其保存到变量 testVal 中。 然后,当我们评估居中函数时,我们可以测试在 get rows where() 函数中使用该值。
以下表格的一列仅包含此 Get RowsWhere() 函数选择的行:

正如您所看到的,所有行都使用年龄 14 作为子集,但哪个性别子集由性别的当前行值确定。 应该很容易适应不同级别的复杂性。
@朱利安
回复:从数据列中减去子集平均值的公式?您只需扩展公式即可处理男性和女性
If( :sex == "F",
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )] ),
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == "M" )] )
)
回复:从数据列中减去子集平均值的公式?你好@朱利安再次感谢您的帮助!
最后一个难题:理想情况下,我希望从女孩中减去 14 岁女孩的平均年龄,从男孩中减去 14 岁男孩的平均年龄。 (在您的示例中,您从男孩和女孩中减去 14 岁女孩的年龄。)
(我意识到在这种特定情况下,只有 M/F 就很容易使用条件,并说“如果 :sex == 'F' 则使用此公式,如果 :sex == 'M' 则将公式修改为说 {mean(:height[(:height << get datatable) << get rows where( :age == 14 & :sex == "M" )])}" 但在我更一般的用例中,我可能有一个大量的组和嵌套条件会变得难以处理。)
有什么简单的方法可以实现这一目标吗?
回复:从数据列中减去子集平均值的公式?你好@MarkJSchwab ,
它确实出现了 <
这是 jmp 向导的解决方案@brady_brady :
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 )] )

花点时间来解开这个公式是值得的,因为我敢打赌,您会发现一些方法在以后很有用。
(:height << get datatable) << get rows where( :age == 14 )
将返回其中 :age==14 的行条目矩阵。 重要的是,您可以修改 get rows where() 函数以匹配您想要的任何查找,包括我相信您必须包含另一个变量的第二个要求。 例如:
(:height << get datatable) << get rows where( :age == 14 & :sex == "F"

现在我们有了一个与您的条件匹配的行矩阵,Brady 使用该矩阵作为下标:height。
height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )]

这将返回每一行的 :height 值的矩阵,在本例中为 14 岁女学生的身高:[61, 62, 65, 63, 62]
最后,Mean() 函数包裹在这个矩阵中,它返回计算中心变量所需的平均值:
mean(:height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )])

这个解决方案更灵活,可以容忍丢失数据,并且适用于 jmp 的早期版本,因此我认为这是一个更好的解决方案。 谢谢, @brady_brady !
@朱利安
回复:从数据列中减去子集平均值的公式?你好@朱利安,谢谢你的建议。 不幸的是,当我粘贴那个确切的公式时
Col Mean( :height, <<FREQ></FREQ>
进入我的大类,它返回 62.55(即没有选择年龄 = 14 的总体 Col 平均值),而不是您看到的正确值 64.166。
我什至可以下载您的附件,正确的值会显示在“以年龄==14 时的平均值为中心”列中。 但是,如果我在该表中使用完全相同的公式创建一个新列,它会返回不同的值(显示 [高度] - [总体平均高度],而不是正确显示 [高度] - [14岁的平均高度])。
我使用的是 JMP Pro 14.3.0。 关于如何使我的输出与您的输出相匹配有什么想法吗?
还有一个问题,如果您在工作表上添加一个额外的 byVar :sex (对于总公式“:height - (Col Mean( :height, :sex, <回复:从数据列中减去子集平均值的公式?
你好@MarkJSchwab ,
有一种使用 Col Mean() 的简单方法可以做到这一点,但在您看到它之前并不明显。 Col Mean() 采用频率列参数:

通常,这是当您需要使用另一列进行加权时的情况。 但是,在您的示例中,如果我们可以将 Age==14 的值加权为 1,将所有其他值加权为 0,会怎么样? 这将为我们提供年龄==14 的个体的平均值。 我们可以直接用公式来实现:
Col Mean( :height, <<FREQ></FREQ>

这将返回:

现在,对于您的具体问题,以高度的特定平均值为中心,我们可以按照通常的方式将其包装到公式中:
:height - (Col Mean( :height, <<FREQ></FREQ>


我希望这有帮助!
@朱利安
回复:从数据列中减去子集平均值的公式?嗨,马克·施瓦布!
当然,有一种方法可以做你想做的事。JSL将让你自由!
我编写了一个简单的脚本,主要使用 JSL 的功能来为您编写脚本。尝试一下:
// Title: Bigclass Normalization Script for JMP User Community discussion
// Purpose: Demonstrate how to write a very basic script to do "normalizations"
Names Default To Here( 1 );
Bigclass_dt = Open( "$SAMPLE_DATA\Big Class.jmp" );
BigclassSummary_dt = bigclass_dt << Summary( Group( :age, :sex ), Mean( :height ) );
BigclassSummary_dt << Select Where( :Age != 14 ) << Delete Rows;
Bigclass_dt << Join(
With( BigclassSummary_dt ),
Select( :name, :age, :sex, :height ),
SelectWith( :Name( "Mean(height)" ) ),
By Matching Columns( :sex = :sex ),
Drop multiples( 0, 0 ),
Include Nonmatches( 0, 0 ),
Preserve main table order( 1 ),
Output Table( "NormedBigclass by AgeGender" )
);
BigclassJoin_dt = Data Table( "NormedBigclass by AgeGender" ) << New Column( "Normalized",
numeric,
continuous,
Formula( :Name( "height" ) - :Name( "Mean(height)" ) ),
evalFormula
);
Close( BigclassSummary_dt, NoSave );
我制作了一个单独的汇总表,然后将其关闭,但您不必这样做。
当然,有更复杂的方法来编写这样的脚本,特别是因为所有“where”子句都是硬编码的,如果您的数据表很大,您可能会遇到此脚本的问题,但是,即使如此,JSL将是您提高生产力的途径。有一些学习 JSL 的好资源!
祝你好运!