我参加本月挑战的动机是让您超越传统的异常值定义,将其视为远离数据中心的观察值(相对于数据可变性的数量)。 通常,我们可以将异常值视为不具有代表性的数据点,它不属于其余数据。 这才是真正的挑战:我们如何定义代表性? 我在下面提供的方法是我对这个问题的看法。
下面的算法根据点之间的距离将观察分为相似和不同的集合。 与聚类的标准凝聚方法不同,从一组开始。 将分割点定义为距离最远的观测值的中间值,前提是它们的距离超过 75 个观测值之间的差值的三倍日所有非零距离的分位数和中位数(距离传播)。 如果没有切点,则停止。 否则,用两个新组替换现有组。 对每个新组重复上述过程,使用新组或整个数据集的距离传播,以较大者为准。 继续直到没有组包含切割点。
findOutliers = Function({vals},{Default Local},
q1 = 3; //Spread Multiplier
q2 = 0.75; //Quantile to define upper bound of spread
distSpread = 0;
nMissing = 0;
tmpTbl = New Table("tmp",New Column("C1",Values(vals)),Private);
sumTbl = tmpTbl << Summary(Group(:C1),Private);
vals = Column(sumTbl,1) << Get Values;
freqs = Column(sumTbl,2) << Get Values;
If(N Row(Loc(vals)) == 1, Return([]));
Close(tmpTbl,No Save);
If(Is Missing(vals[1]),
nMissing = freqs[1];
freqs = freqs[2::N Row(vals)];
vals = vals[2::N Row(vals)];
);
vals = Sort Ascending(vals[Loc Nonmissing(vals)]);
groups = Eval List({vals});
cutPoints = [];
While(N Items(groups) > 0,
newGroups = {};
For Each({nextVals},groups,
distances = nextVals[2::N Row(nextVals)] - nextVals[1::(N Row(nextVals)-1)];
distSpread = Max(distSpread,Median(distances[Loc(distances>0)]) + q1*(Quantile(q2,distances[Loc(distances>0)]) - Median(distances[Loc(distances>0)])));
maxDist = Maximum(distances);
If(maxDist>distSpread,
cutID = Loc(distances==maxDist)[1];
cutPoints |/= (nextVals[cutID+1]+nextVals[cutID])/2;
If(cutID == 1,
Insert Into(newGroups,nextVals[2::N Row(nextVals)]),//ELSE
If(cutID == N Row(distances),
Insert Into(newGroups,nextVals[1::cutID]),
//ELSE
Insert Into(newGroups,nextVals[1::cutID]);
Insert Into(newGroups,nextVals[(cutID+1)::N Row(nextVals)]);
)
)
);
);
groups = newGroups;
);
cutPoints = Sort Ascending(cutPoints);
cutPoints;
);
首先,需要一些内务处理来绕过具有单个值的数据。 根据来自的结果挑战 9 ,我正在使用摘要同时查找数据中的唯一值并对其进行排序。 通过将向量偏移一并取其差来找到距离。 该算法通过收集切割点并丢弃没有切割点的组来进行。 这一直持续到没有组剩下。
该算法相当快,大约需要 1.6 秒来处理所有数据列探测我机器上的示例数据数据表。 在算法的顶部,我添加了两个变量,让您更改 3x 乘数和 75日分位数。 在下面附加的脚本中,挑战 11 异常值筛选,我添加了一些额外的窗口装饰来提供一些界面,允许列选择和生成包含摘要信息和直方图的报告窗口,并将切割点绘制为参考线。
我将从 JMP 挑战赛中稍作休息,以从事另一个脚本项目。 我将为小型项目整理书面说明和视频,以帮助新用户和中级用户提高他们的 JSL 技能。 我将专注于常见操作,例如将表放在一起、访问来自多个源的数据、构建自定义报告等。 我还将尝试研究一些更高级的东西,比如表达式处理和模式匹配。 如果有任何您认为值得的事情,请通过将它们张贴在这里告诉我,或者向我发送社区消息或电子邮件( don.mccormack@jmp.com )。