“获取行”的时间太长我有一个参考表,其中每一列都是主数据表列的名称,行中的值是主表中该列的错误数据的部件号。例如,在主表中,第 1 列是零件编号,第 2 列是“Temp”。假设行号等于部件号,因此第 1 行是部件“1”,并且假设“Temp”列中的值为 65。第 2 部分的温度为 -100,因此是坏数据。因此,在名为“Temp”的列下的参考表中,第 1 行的值为“2”。对主表中具有错误数据的所有零件编号重复此操作,然后对每一列也重复此操作。
这给了我一个错误的数据引用表,然后我可以循环遍历以在每次为主表提取最新数据时自动删除错误数据。我有有效的代码,但是行:
(其中 vlist 包含参考表中的所有零件编号,dt2 是主数据表)
try(rowindex=dt2 << Get Rows Where(contains(vlist,:WORKORDERNO )));
超级慢。完成需要 22 秒。由于我有 196 个专栏要浏览,这需要很长时间。任何有关如何加快速度的建议将不胜感激!
完整代码在这里:
names default to here(1);
dt=open("J:\Public\Ti Process Control\Dashboard Files\JMP data for CC's\Limits\master_data_table_clean_up.jmp", invisible(1)); //this is the reference table
dt<<BEGIN data="https://community.jmp.com/" update=""></BEGIN>自动化和脚本编写视窗回复:“获取行”的时间太长考虑 JMP 将如何进行名称解析。当你运行一个获取行Where()函数,它将逐行遍历表格,评估在哪里表达。每次评估都需要对定义的所有变量进行名称解析,并且由于您的视频列表vairable 是在运行循环之外定义的,每次迭代都必须进行一些范围遍历,从而导致大量浪费的工作。
为了解决这个问题,请考虑预先评估在整个查找过程中保持不变的任何名称,如下所示:
Names Default To Here( 1 );
dt = Open(
"J:\Public\Ti Process Control\Dashboard Files\JMP data for CC's\Limits\master_data_table_clean_up.jmp",
invisible( 1 )
); //this is the reference table
dt << begin data update;
cols = dt << get column names();
dt2 = Data Table( "Master data pull daily download" ); //this is the main table
dt2 << begin data update;
dt2 << Clear Select();
cols2 = dt2 << get column names();
vlist = {};
For( i = 1, i <= 2 /*N items(cols)*/, i++,
Try( vlist = Column( dt, cols[i] ) << get values );
starttime = Tick Seconds();
Eval( Eval Expr(
Try( rowindex = dt2 << Get Rows Where( Contains( Expr( vlist ), :WORKORDERNO ) ) );
) );
endtime = Tick Seconds();
Print( "run time", Eval Insert( "Analysis took ^round(endtime - starttime)^ seconds" ) );
Try( Column( dt2, cols[i] )[rowindex] = . );
);
dt2 << end data update;
dt << end data update;
Close( dt, nosave );注意评估(评估表达式(... Expr( vlist ) ... ) )表达式——即预评估视频列表因为它在整个循环中是一个常数。
回复:“获取行”的时间太长我相信您可以使用 AsConstant(vList) 来达到相同的效果,名称“vlist”只应为每个 GetRowsWhere 调用评估一次。
回复:“获取行”的时间太长谢谢回复@ErraticAttack ,我将您的代码修改弹出,代码执行时间为 21 秒 vs 22 秒。所以好一点,但不是我需要的地方。任何其他想法将不胜感激!
回复:“获取行”的时间太长我还发现,如果您能找到一种使用 Loc 的方法,在大多数情况下使用 Loc 会更快。 可能有比这更好的方法,但您可以尝试类似的方法来替换 GetRowsWhere 调用。
dt = New Table( "BadTable",
Add Rows( 100 ),
New Column( "BadPartNumbers",
Formula( Random Integer( 1000 ) ),
),
);
dt2 = New Table( "FullTable",
Add Rows( 10000 ),
New Column( "NewPartNumbers",
Formula( Random Integer( 1000 ) ),
),
);
newPNumbers = dt2:NewPartNumbers<< GetValues;
badPNumbers = AssociativeArray(dt:BadPartNumbers << GetValues);
rowIndex = Loc(Matrix(badPNumbers << GetValues(AsList(newPNumbers))));
我不太确定你的表是如何设置的,但基本上它是将坏零件号转换为关联数组,其中坏零件号返回 1,其他任何值都返回 0。 当您将所有部件号的列表传递给 GetValues 时,它会为每行返回一个由 1 和 0 组成的列表。 对此调用 Loc 返回找到 1 的索引,该索引应对应于具有错误部件号的行。
回复:“获取行”的时间太长@ErraticAttack因此,我制作了一个测试主数据表和参考表来尝试共享,以便人们可以一起玩,但是当我这样做时,脚本运行得非常快,不到一秒钟。所以现在我想知道这是否与我的实际数据表有关?
这是测试表

回复:“获取行”的时间太长根据您的数据,您可以使用许多不同的方法来执行这些检查(连接/更新、定位、获取行、关联数组、汇总表...)。 你的表有多少行? 您的参考表列中最多有多少个不同的值? 大多数值是否为空(在执行比较之前删除空值以使列表更小或仅将其包含一次)?
回复:“获取行”的时间太长嘿@jthi ,
以下是主表的概述:

这是参考表:

以下是参考表中每列有多少数据:(来自缺失数据筛选器输出)
号码缺失
0
0
0
0
3115
6075
12237
16591
16591
16591
16591
16772
17038
17093
17095
17095
17099
17099
17109
17110
17113
21542
22781
23634
24792
24792
25058
25172
25280
25341
25356
25376
25376
25827
25863
25875
25893
25894
25897
25905
25942
25957
25963
25963
25963
25965
25968
25968
25968
25968
26367
26564
27190
27404
27414
27420
27437
27453
27465
27474
27478
27493
27503
27522
27547
27553
27573
27592
27597
27597
27597
27597
27619
27626
27628
27628
27629
27629
27629
27629
因此,由于少数列包含大量错误数据,大多数列都充满了“缺失数据”/空白。
让我想知道 vlist 中的所有这些空白是否会导致速度变慢:

回复:“获取行”的时间太长我怀疑所有的空白都会导致你的代码变慢。这是一个解决方法。只需将您创建的 vlist 替换为
Try( vlist = Associative Array( As Column( cols[i] ) ) << get keys );
If( vlist[1] == "",
Remove From( vlist, 1, 1 )
);
回复:“获取行”的时间太长它很可能会导致速度变慢,尤其是在列表中找不到该值的情况下
Names Default To Here(1);
test = {"a", "b", "c", "d", "e", "f"};
test2 = test || Repeat({""}, 27629);
lookup_val = "a";
repeats = 200;
tests = {};
For(i = 1, i <= repeats, i++,
start = HP Time();
Contains(test, lookup_val);
wait(0);
end = HP Time();
Insert Into(tests, (end-start)/1e6);
);
tests2 = {};
For(i = 1, i <= repeats, i++,
start = HP Time();
Contains(test2, lookup_val);
wait(0);
end = HP Time();
Insert Into(tests2, (end-start)/1e6);
);
Show(Mean(tests), Std Dev(tests), Mean(tests2), Std Dev(tests2));
Show(Median(tests2)/Median(tests));
编辑:
这两个测试脚本都写得相当快,因此可能会出现一些错误
Names Default To Here(1);
Random Reset(1);
dt_data = New Table("Data",
Add Rows(30000),
New Column("first", Numeric, Nominal, << Set Each Value(Row())),
New Column("second", Numeric, Nominal, << Set Each Value(Row())),
invisible
);
Column(dt_data, "first") << Set Data Type("Character");
Column(dt_data, "second") << Set Data Type("Character");
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("first", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::10])),
New Column("second", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::500])),
invisible
);
Column(dt_lookup, "first") << Set Data Type("Character");
Column(dt_lookup, "second") << Set Data Type("Character");
start = HP Time();
dt_data << Get Rows Where(Contains(As Constant(dt_lookup[0, "first"]), :first));
dt_data << Get Rows Where(Contains(As Constant(dt_lookup[0, "second"]), :second));
end = HP Time();
show((end - start)/1e6);
wait(0);
start = HP Time();
dt_data << Get Rows Where(Contains(As Constant(Associative Array(dt_lookup[0, "first"]) << get keys), :first));
dt_data << Get Rows Where(Contains(As Constant(Associative Array(dt_lookup[0, "second"]) << get keys), :second));
end = HP Time();
show((end - start) / 1e6);
Close(dt_data, no save);
Close(dt_lookup, no save);
根据您有多少个值以及它们是否是字符(我认为在您的情况下它们是),使用 Summarize() 而不是 Associative Array() 来获取唯一值会更快,但这很可能不会那么大在这种情况下的效果
Names Default To Here(1);
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("test", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::500])),
invisible
);
Column(dt_lookup, "test") << Set Data Type("Character");
start = HP Time();
Summarize(dt_lookup, uniq_vals = by(Column(dt_lookup, "test")));
end = HP Time();
show((end - start) / 1e6);
start = HP Time();
uniq_vals2 = Associative Array(Column(dt_lookup, "test")) << get keys;
end = HP Time();
show((end - start) / 1e6);
Show(N Items(uniq_vals), N Items(uniq_vals2));
Close(dt_lookup, no save);回复:“获取行”的时间太长这很可能属于过早优化的类别,但 JMP 的更新有时可能非常快,并且很可能在此处使用某些列重命名并向充满空值的查找表添加新列
Names Default To Here(1);
dt_data = New Table("Data",
Add Rows(30000),
New Column("first", Numeric, Nominal, << Set Each Value(Row())),
New Column("second", Numeric, Nominal, << Set Each Value(Row())),
invisible
);
Column(dt_data, "first") << Set Data Type("Character");
Column(dt_data, "second") << Set Data Type("Character");
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("first", Numeric, Nominal, Values(Random Shuffle(1::30000)[1::500])),
invisible
);
Column(dt_lookup, "first") << Set Data Type("Character");
/*
start = HP Time();
Summarize(dt_lookup, uniq_vals = by(:first));
r = dt_data << Get Rows Where(Contains(As Constant(uniq_vals), :first));
dt_data[r, "second"] = "";
end = HP Time();
Show((end-start)/1e6);
*/
missing_col = dt_lookup << New Column("missing_vals", Numeric, Nominal);
start = HP Time();
i = 1;
Column(dt_lookup, "first") << Set Name(Char(i));
missing_col << Set Name("second");
dt_data << Update(With(dt_lookup), Match Columns(:first = Eval(Char(i))), Replace Columns in Main Table(:second));
end = HP Time();
Show((end-start)/1e6);
Close(dt_data, no save);
Close(dt_lookup, no save);回复:“获取行”的时间太长这非常有效,谢谢!
谢谢@jthi还有!没有深入研究他在上面发布的代码,因为 txnelson 代码的复制和粘贴工作完美,但我很感谢他花时间制作它。