Meine Motivation für die Herausforderung dieses Monats bestand darin, Sie dazu zu bringen, über die traditionelle Definition von Ausreißern hinauszudenken, da es sich nur um Beobachtungen handelt, die weit vom Zentrum der Daten entfernt sind (relativ zur Menge der Datenvariabilität). Im Allgemeinen können wir einen Ausreißer als nicht repräsentativen Datenpunkt betrachten, der nicht zu den restlichen Daten gehört. Hier liegt die wahre Herausforderung: Wie definieren wir repräsentativ? Der Ansatz, den ich unten vorstelle, ist meine Sicht auf das Problem.
Der folgende Algorithmus gruppiert Beobachtungen basierend auf den Abständen zwischen den Punkten in gleiche und unähnliche Sätze. Beginnen Sie im Gegensatz zum standardmäßigen agglomerativen Clustering-Ansatz mit einer Gruppe. Definieren Sie einen Schnittpunkt als den Wert auf halbem Weg zwischen den am weitesten auseinander liegenden Beobachtungen, vorausgesetzt, ihr Abstand überschreitet das Dreifache der Differenz zwischen den 75 NS Quantil und Median aller Distanzen ungleich Null (die Distanzstreuung). Wenn keine Schnittpunkte vorhanden sind, stoppen Sie. Andernfalls ersetzen Sie die vorhandene Gruppe durch die beiden neuen Gruppen. Wiederholen Sie das obige Verfahren mit jeder neuen Gruppe, wobei Sie die Distanzspreizung der neuen Gruppe oder des gesamten Datensatzes verwenden, je nachdem, welcher Wert größer ist. Fahren Sie fort, bis keine Gruppe einen Schnittpunkt 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;
);
Zu Beginn ist ein wenig Ordnungsarbeit erforderlich, um Daten mit einem einzigen Wert zu umgehen. Basierend auf den Ergebnissen von Herausforderung 9 , verwende ich Zusammenfassung, um gleichzeitig die eindeutigen Werte in den Daten zu finden und zu sortieren. Entfernungen werden gefunden, indem der Vektor um eins versetzt und ihre Differenz gebildet wird. Der Algorithmus fährt fort, indem er Schnittpunkte sammelt und Gruppen ohne Schnittpunkte auswirft. Dies wird so lange fortgesetzt, bis keine Gruppen mehr übrig sind.
Der Algorithmus ist ziemlich schnell und benötigt etwa 1,6 Sekunden, um alle Datenspalten im Sonde Beispieldaten Datentabelle auf meinem Computer. Oben im Algorithmus habe ich zwei Variablen hinzugefügt, damit Sie den 3x-Multiplikator und den 75 . ändern können NS Quantil. Im unten angehängten Skript Herausforderung 11 Ausreißer-Screening , habe ich einige zusätzliche Fensterdekorationen eingefügt, um eine gewisse Benutzeroberfläche zu bieten, die die Spaltenauswahl und die Erstellung eines Berichtsfensters mit zusammenfassenden Informationen und Histogrammen mit den Schnittpunkten als Referenzlinien ermöglicht.
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 konzentriere mich auf allgemeine Vorgänge wie das Zusammenstellen von Tabellen, den Zugriff auf Daten aus mehreren Quellen, das Erstellen benutzerdefinierter Berichte und so weiter. Ich werde auch versuchen, in einigen fortgeschritteneren Dingen zu arbeiten, wie zum Beispiel Ausdrucksbehandlung und Mustervergleich. Wenn es etwas gibt, das Ihrer Meinung nach lohnenswert ist, lassen Sie es mich wissen, indem Sie es hier posten oder mir eine Community-Nachricht oder E-Mail senden ( don.mccormack@jmp.com ).