Mi motivación para el desafío de este mes fue hacer que piense más allá de la definición tradicional de valores atípicos como observaciones que caen lejos del centro de los datos (en relación con la cantidad de variabilidad de los datos). En general, podemos considerar un valor atípico como un punto de datos no representativo, algo que no pertenece al resto de los datos. Aquí radica el verdadero desafío: ¿Cómo definimos representante? El enfoque que proporciono a continuación es mi opinión sobre el problema.
El algoritmo siguiente agrupa las observaciones en conjuntos similares y diferentes según las distancias entre los puntos. A diferencia del enfoque aglomerativo estándar para la agrupación, comience con un grupo. Defina un punto de corte como el valor a medio camino entre las observaciones más alejadas, siempre que su distancia exceda tres veces la diferencia entre las 75 th cuantil y mediana de todas las distancias distintas de cero (la dispersión de distancia). Si no hay puntos de corte, deténgase. De lo contrario, reemplace el grupo existente con los dos nuevos grupos. Repita el procedimiento anterior con cada grupo nuevo, utilizando la distancia entre el grupo nuevo o todo el conjunto de datos, lo que sea mayor. Continúe hasta que ningún grupo contenga un punto de corte.
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;
);
Para empezar, se necesita un poco de limpieza para omitir datos con un solo valor. Basado en los resultados de Desafío 9 , Estoy usando Resumen para buscar simultáneamente los valores únicos en los datos y ordenarlos. Las distancias se encuentran compensando el vector en uno y tomando su diferencia. El algoritmo procede mediante la recopilación de puntos de corte y la eliminación de grupos sin puntos de corte. Esto continúa hasta que no quedan grupos.
El algoritmo es bastante rápido, necesita alrededor de 1,6 segundos para procesar todas las columnas de datos en el Investigacion Datos de muestra Tabla de datos en mi máquina. En la parte superior del algoritmo, agregué dos variables para permitirle cambiar el multiplicador 3x y el 75 th cuantil. En el guión adjunto a continuación, Desafío 11 Detección de valores atípicos , He incluido algunos diseños de ventana adicionales para proporcionar un poco de interfaz, lo que permite la selección de columnas y la generación de una ventana de informe que contiene información resumida e histogramas con los puntos de corte dibujados como líneas de referencia.
Me tomaré un pequeño descanso del Desafío JMP para trabajar en otro proyecto de secuencias de comandos. Reuniré instrucciones escritas y videos para proyectos pequeños a fin de ayudar a los usuarios nuevos e intermedios a mejorar sus habilidades de JSL. Me centraré en operaciones comunes como armar tablas, acceder a datos de múltiples fuentes, crear informes personalizados, etc. También intentaré trabajar en algunas cosas más avanzadas, como el manejo de expresiones y la coincidencia de patrones. Si hay algo que crea que valdría la pena, hágamelo saber publicándolo aquí o enviándome un mensaje o correo electrónico de la comunidad ( don.mccormack@jmp.com ).