valores - mostrar elementos de un arraylist java
Cómo detectar valores atípicos en una ArrayList (6)
Estoy tratando de pensar en algún código que me permita buscar en mi ArrayList y detectar cualquier valor fuera del rango común de "buenos valores".
Ejemplo: 100 105 102 13 104 22 101
¿Cómo podría escribir el código para detectar que (en este caso) 13 y 22 no caen dentro de los "buenos valores" de alrededor de 100?
Es solo una implementación muy simple que obtiene la información cuyos números no están dentro del rango:
List<Integer> notInRangeNumbers = new ArrayList<Integer>();
for (Integer number : numbers) {
if (!isInRange(number)) {
// call with a predefined factor value, here example value = 5
notInRangeNumbers.add(number, 5);
}
}
Además, dentro del método isInRange
debe definir qué quiere decir con ''buenos valores'' . A continuación encontrará una implementación ejemplar.
private boolean isInRange(Integer number, int aroundFactor) {
//TODO the implementation of the ''in range condition''
// here the example implementation
return number <= 100 + aroundFactor && number >= 100 - aroundFactor;
}
Existen varios criterios para detectar valores atípicos. Los más simples, como el criterio de Chauvenet , usan la media y la desviación estándar calculada a partir de la muestra para determinar un rango "normal" para los valores. Cualquier valor fuera de este rango se considera un valor atípico.
Otros criterios son la prueba de Grubb y la prueba Q de Dixon, y pueden dar mejores resultados que los de Chauvenet, por ejemplo, si la muestra proviene de una distribución oblicua.
- encuentra el valor medio para tu lista
- crea un
Map
que mapea el número a la distancia de la media - ordenar los valores por la distancia de la media
- y diferenciar el último
n
número, asegurándote de que no haya injusticia con la distancia
Usa este algoritmo. Este algoritmo usa el promedio y la desviación estándar. Estos 2 valores opcionales numéricos (2 * desviación estándar).
public static List<int> StatisticalOutLierAnalysis(List<int> allNumbers)
{
if (allNumbers.Count == 0)
return null;
List<int> normalNumbers = new List<int>();
List<int> outLierNumbers = new List<int>();
double avg = allNumbers.Average();
double standardDeviation = Math.Sqrt(allNumbers.Average(v => Math.Pow(v - avg, 2)));
foreach (int number in allNumbers)
{
if ((Math.Abs(number - avg)) > (2 * standardDeviation))
outLierNumbers.Add(number);
else
normalNumbers.Add(number);
}
return normalNumbers;
}
Una implementación de la prueba de Grubb se puede encontrar en MathUtil.java . Encontrará un valor atípico único, que puede eliminar de su lista y repetir hasta que haya eliminado todos los valores atípicos.
Depende de commons-math
, así que si estás usando Gradle:
dependencies {
compile ''org.apache.commons:commons-math:2.2''
}
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Double> data = new ArrayList<Double>();
data.add((double) 20);
data.add((double) 65);
data.add((double) 72);
data.add((double) 75);
data.add((double) 77);
data.add((double) 78);
data.add((double) 80);
data.add((double) 81);
data.add((double) 82);
data.add((double) 83);
Collections.sort(data);
System.out.println(getOutliers(data));
}
public static List<Double> getOutliers(List<Double> input) {
List<Double> output = new ArrayList<Double>();
List<Double> data1 = new ArrayList<Double>();
List<Double> data2 = new ArrayList<Double>();
if (input.size() % 2 == 0) {
data1 = input.subList(0, input.size() / 2);
data2 = input.subList(input.size() / 2, input.size());
} else {
data1 = input.subList(0, input.size() / 2);
data2 = input.subList(input.size() / 2 + 1, input.size());
}
double q1 = getMedian(data1);
double q3 = getMedian(data2);
double iqr = q3 - q1;
double lowerFence = q1 - 1.5 * iqr;
double upperFence = q3 + 1.5 * iqr;
for (int i = 0; i < input.size(); i++) {
if (input.get(i) < lowerFence || input.get(i) > upperFence)
output.add(input.get(i));
}
return output;
}
private static double getMedian(List<Double> data) {
if (data.size() % 2 == 0)
return (data.get(data.size() / 2) + data.get(data.size() / 2 - 1)) / 2;
else
return data.get(data.size() / 2);
}
}
Salida: [20.0]
Explicación:
- Ordena una lista de enteros, de menor a mayor
- Divida una lista de enteros en 2 partes (por un medio) y colóquelos en 2 nuevos ArrayLists separados (llámelos "izquierda" y "derecha")
- Encuentra un número medio (mediana) en las nuevas ArrayLists
- Q1 es una mediana desde el lado izquierdo, y Q3 es la mediana desde el lado derecho
- Aplicando fórmula matemática:
- IQR = Q3 - Q1
- LowerFence = Q1 - 1.5 * IQR
- UpperFence = Q3 + 1.5 * IQR
- Más información sobre esta fórmula: http://www.mathwords.com/o/outlier.htm
- Pasa por todos mis elementos originales, y si alguno de ellos es más bajo que una valla inferior, o más alto que una valla superior, agrégalos a ArrayList de "salida".
- Esta nueva ArrayList de "salida" contiene los valores atípicos