Meine Motivation für die Herausforderung dieses Monats bestand darin, Sie dazu zu bringen, über die traditionelle Definition von Ausreißern hinauszudenken, bei der es sich lediglich um Beobachtungen handelt, die weit vom Zentrum der Daten entfernt liegen (im Verhältnis zur Menge der Datenvariabilität). Im Allgemeinen können wir einen Ausreißer als einen nicht repräsentativen Datenpunkt betrachten, der nicht zum Rest der Daten gehört. Hier liegt die wahre Herausforderung: Wie definieren wir repräsentativ? Der unten aufgeführte Ansatz ist meine Sicht auf das Problem.
Der folgende Algorithmus gruppiert Beobachtungen basierend auf den Abständen zwischen den Punkten in gleiche und unähnliche Mengen. Beginnen Sie im Gegensatz zum standardmäßigen agglomerativen Clustering-Ansatz mit einer Gruppe. Definieren Sie einen Schnittpunkt als den Wert in der Mitte zwischen den am weitesten voneinander entfernten Beobachtungen, sofern deren Abstand das Dreifache der Differenz zwischen den 75 übersteigt Th Quantil und Median aller Abstände ungleich Null (die Abstandsverteilung). Wenn keine Schnittpunkte vorhanden sind, stoppen Sie. Andernfalls ersetzen Sie die vorhandene Gruppe durch die beiden neuen Gruppen. Wiederholen Sie den obigen Vorgang mit jeder neuen Gruppe und verwenden Sie dabei die Distanzspanne von der neuen Gruppe oder vom gesamten Datensatz, je nachdem, welcher Wert größer ist. Fahren Sie fort, bis keine Gruppe einen Schnittpunkt mehr enthält.
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;
);
Zunächst ist ein wenig Aufwand erforderlich, um Daten mit einem einzelnen Wert zu umgehen. Basierend auf den Ergebnissen von Herausforderung 9 verwende ich Summary, um gleichzeitig die eindeutigen Werte in den Daten zu finden und sie zu sortieren. Entfernungen werden ermittelt, indem der Vektor um eins versetzt und deren Differenz gebildet wird. Der Algorithmus fährt fort, indem er Schnittpunkte sammelt und Gruppen ohne Schnittpunkte verwirft. Dies wird so lange fortgesetzt, bis keine Gruppen mehr vorhanden sind.
Der Algorithmus ist ziemlich schnell und benötigt etwa 1,6 Sekunden, um alle Datenspalten im zu verarbeiten Sonde Beispieldaten-Datentabelle auf meinem Computer. Oben im Algorithmus habe ich zwei Variablen hinzugefügt, damit Sie den 3x-Multiplikator und den 75er ändern können Th Quantil. Im unten angehängten Skript Herausforderung 11: Ausreißer-Screening , habe ich einige zusätzliche Fensterdekorationen eingefügt, um eine Art Schnittstelle bereitzustellen, die die Spaltenauswahl und die Erstellung eines Berichtsfensters mit zusammenfassenden Informationen und Histogrammen ermöglicht, wobei die Schnittpunkte als Referenzlinien gezeichnet werden.
Ich werde eine kleine Pause von der JMP Challenge einlegen, um an einem anderen Skriptprojekt zu arbeiten. Ich werde schriftliche Anleitungen und Videos für kleine Projekte zusammenstellen, um neuen und fortgeschrittenen Benutzern zu helfen, ihre JSL-Kenntnisse zu verbessern. Ich werde mich auf allgemeine Vorgänge wie das Zusammenstellen von Tabellen, den Zugriff auf Daten aus mehreren Quellen, das Erstellen benutzerdefinierter Berichte usw. konzentrieren. Ich werde auch versuchen, mich mit etwas fortgeschritteneren Dingen zu befassen, etwa mit der Handhabung von Ausdrücken und dem Mustervergleich. Wenn es Ihrer Meinung nach etwas gibt, das sich lohnen würde, lassen Sie es mich bitte wissen, indem Sie es hier posten oder mir eine Community-Nachricht oder E-Mail senden ( don.mccormack@jmp.com ).