今月の課題の私の動機は、外れ値の従来の定義を超えて、データの中心から遠く離れた観測値であると考えてもらうことでした(データの変動量と比較して)。 一般に、外れ値は、残りのデータに属さない非代表的なデータポイントと見なすことができます。 ここに真の課題があります。代表をどのように定義するのでしょうか。 以下に示すアプローチは、この問題に対する私の見解です。
以下のアルゴリズムは、ポイント間の距離に基づいて、観測値を類似セットと非類似セットにグループ化します。 クラスタリングへの標準的な凝集アプローチとは異なり、1つのグループから始めます。 カットポイントは、観測値の距離が75の差の3倍を超える場合、最も離れた観測値の中間の値として定義します。 NSゼロ以外のすべての距離の分位数と中央値(距離の広がり)。 カットポイントがない場合は停止します。 それ以外の場合は、既存のグループを2つの新しいグループに置き換えます。 新しいグループまたはデータセット全体からの距離の広がりのいずれか大きい方を使用して、新しいグループごとに上記の手順を繰り返します。 グループにカットポイントが含まれなくなるまで続けます。
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 、Summaryを使用して、データ内の一意の値を同時に検索し、並べ替えています。 距離は、ベクトルを1つオフセットし、それらの差をとることによって求められます。 アルゴリズムは、カットポイントを収集し、カットポイントのないグループを破棄することによって進行します。 これは、グループがなくなるまで続きます。
アルゴリズムはかなり高速で、内のすべてのデータ列を処理するのに約1.6秒かかります。調査私のマシンのサンプルデータデータテーブル。 アルゴリズムの上部に、3倍の乗数と75を変更できるように2つの変数を追加しましたNS分位。 以下に添付されているスクリプトでは、チャレンジ11外れ値スクリーニング、インターフェイスのビットを提供するためにいくつかの追加のウィンドウドレッシングを含めました。これにより、列の選択と、参照線として描画されたカットポイントを含む要約情報とヒストグラムを含むレポートウィンドウの生成が可能になります。
別のスクリプトプロジェクトに取り組むために、JMPチャレンジから少し休憩します。 新規および中級ユーザーがJSLスキルを向上できるように、小規模プロジェクト向けの説明とビデオをまとめます。 テーブルの作成、複数のソースからのデータへのアクセス、カスタムレポートの作成など、一般的な操作に焦点を当てます。 また、式の処理やパターンマッチングなど、より高度な作業も試みます。 価値があると思われるものがあれば、ここに投稿するか、コミュニティメッセージまたはメールを送ってください( don.mccormack@jmp.com )。