嗨,我是使用任何语言编写脚本的初学者。我目前正在研究我认为简单的练习任务。我正在使用 JMP18。我的目标是自动执行我随时间推移处理不断增长的数据集的常规操作。常规操作是首先确定时间尺度,然后显示大型数据集随时间的变化。我处理此问题的基本方法是创建新列以填充所有初始数据,并在更多列上使用公式来获取差异。如果有人有更好的建议,我将不胜感激。以下是我目前的情况:
本质上,我有一组数据,我想实现以下目标。
1) 我希望获取日期和时间列,将它们合并为一列,然后找到最小值,并使用它来创建开始日期。然后我可以减去时间以查看数据之间的时间差异。使用 formula() 函数,这一切都很简单。这里的一切都很好用。
2) 我想对几个数据列执行类似操作,但我无法像以前那样找到初始值。初始数据由我之前为第三列中的每个唯一项(在下面的代码中称为 Unique_Fruit)找到的最短时间决定。为了这个论坛的利益,对于每个 unique_fruit,我想创建一个包含该水果数据初始值的列,这样我就可以快速计算出实际数据列的变化。
我当前的 JSL 脚本如下。我有一个虚拟代码公式,但我还不知道该怎么做。这是我使用 If 函数的步骤,发现时间相等,然后只为这些单元格设置值。我最初的想法是尝试使用 for 循环并在公式中进行迭代,但这似乎不起作用。
DataTable = Current Data Table();
New Column( "Date Number Format", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Date Number Format[i] = Num( DataTable:Key_Date[i] );
);
New Column( "Time Number Format", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Time Number Format[i] = Num( DataTable:Key_Time[i] );
);
New Column( "Current_Time", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Current_Time[i] = DataTable:Date Number Format[i] + DataTable:Time Number Format[i];
);
New Column( "Unique_Fruit", Character, "Nominal" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Unique_Fruit[i] = DataTable:Fruit[i] || "-" || DataTable:Type[i];
);
New Column( "Starting_Date_Number_Format", Numeric, "Continuous",
Formula( Col Minimum( :Current_Time, :Unique_Fruit ) )
);
New Column( "Minutes", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Minute", "fractional" ) )
);
New Column( "Days", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Day", "fractional" ) )
);
New Column( "Weeks", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Week", "fractional" ) )
);
New Column( "Months", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Month", "fractional" ) )
);
New Column( "Initial_Taste", Numeric, "Continuous",
Formula(
If( :Current_Time == :Starting_Date_Number_Format, :Key_Taste, . )
)
);
For( i = 1, i <= N Rows( DataTable ), i++,
If( DataTable:Current_Time[i] == DataTable:Starting_Date_Number_Format[i],
DataTable:Initial_Taste[i] = DataTable:Key_Taste[i];
);
);
New Column( "Delta_Taste", Numeric, "Continuous",
Formula( :Key_Taste - :Initial_Taste )
);
New Column( "%_Change_Taste", Numeric, "Continuous",
Formula( ( :Delta_Taste / :Initial_Taste ) * 100 + 100 )
);</CODE></P><BR /></LINGO-BODY><LINGO-LABS id="lingo-labs-844919" slang="en-US" mode="CREATE"><LINGO-LABEL>自动化和脚本</LINGO-LABEL></LINGO-LABS><LINGO-SUB id="lingo-sub-844929" slang="en-US" mode="CREATE">回复:初学者尝试编写脚本/如何在公式函数内进行迭代?</LINGO-SUB><LINGO-BODY id="lingo-body-844929" slang="en-US" mode="CREATE"><P>您能提供带有正确答案的示例数据集 + 列吗?您很可能可以使用类似这样的方法获取初始值,但您必须修改比较,因为这个方法会获取每个类别的第一个值</P>
<BR />
<PRE><CODE class=" language-jsl">Col Cumulative Sum(If(Row() == Col Min(Row(), :age), :height, .), :age)
其中 :age 是 unique_fruit,:height 是您的值列。您还可以利用 Lag() 和变量。
我还会对你的脚本做一些修改,使其更加健壮。
- 使用名称默认为此处 (1) 启动脚本;
- 正如您引用数据表一样,使用它
- 数据表<<新列(...
- 我还会考虑将 DataTable 更改为 dt 或类似名称,因为 JMP 具有名为 Datatable() 的函数
- 循环遍历数据表时使用 For Each Row 而不是 For,因为这是它的特殊用例
- 当您希望在 JMP 表中添加新列而不使用公式时,您有以下几种选择:
- 使用新建列 + 公式 + 运行公式 + 删除公式组合
- 创建新列并循环遍历数据表(就像您正在做的那样)
- 然后有一点挑剔的方法,使用<<应用公式,但我会首先坚持这些(通常我使用第一个)
感谢您的建议。我正在尝试模拟数据集以及我目前手动执行的操作。要设置初始值,我会查看每个唯一项并从该单元格中调用数据并填充整个列,这样我就可以继续进行计算的下一部分。我也会尝试使用您的建议更新脚本的其余部分,但我认为主要问题尚未解决(或者我还没有明白)。
这个问题没有得到解决,因为创建模型数据通常比回答正确问题花费的时间更多。您应该能够利用类似这样的方法获取初始值
Col Min(If(:Date Number Format == Col Min(:Date Number Format, :Unique_Fruit), :Key_Taste, .), :Unique_Fruit)
这不是构建这些的唯一方法,但这样的方法确实经常有效
非常感谢。只是澄清一下,我并不是想把责任归咎于你的第一次回复,更多的是,我试图在几次迭代中实现它,但我认为我仍然缺少一些东西。我应该继续下去,因为我可能最终会得到你在这里展示的答案(最终),但正如我之前所说,我对编写这些内容的脚本还很陌生,所以进展很慢。
出于好奇,为什么 else 中有一个“。”?
缺失值是为了尝试“强制”Col Min 只有一个选项可供选择,因为它将忽略缺失值。
您可以将此类公式分解为多个部分,以便更好地理解它们(有时它们仍然可能非常隐晦)
//col1
Col Min(:Date Number Format, :Unique_Fruit)
//col2
:Date Number Format == :col1
//col3
If(:col2, :Key_Taste, .)
//col4
Col Min(:col3, :Unique_Fruit)

嘿,我在玩这个的时候又想到了一个新主意。如果我想做一些更接近我最初发布这篇文章时认为必须做的事情,该怎么做?我现在的做法是编写一个存储列表的变量,然后尝试让代码遍历该列表来填充公式。而不是填充变量,而是将其保留在公式中,而不是更新为列表值之一。这是可以在公式函数中完成的事情吗?
谢谢你的解释。我正在尝试这个方法,继续我自己的小项目,看看我能把它带到哪里。
您可以在公式中获取值列表/收集值列表,但您必须小心更新值的方式(使用 As Constant 或 If(Row() == 1,...) 会有所帮助)。此外,您可能希望避免公式中的循环,因为它们确实会经常触发。
您可以使用 Lag(),但这需要对数据进行排序(无需排序即可完成,但很快就会变得复杂),但通常的想法有点像这样
If(Row() == 1,
init_taste = :Key_Taste
);
If(:Unique_Fruit != Lag(:Unique_Fruit),
init_taste = :Key_Taste;
);
init_taste;
请注意,我确实按日期数字格式和Unique_Fruit对数据进行了排序。