2011-05-10 31 views
10

Tengo un algoritmo que calcula el percentile(85) con Apache Commons de una serie de valores (12 valores), para una evaluación posterior con un umbral para tomar una decisión. El resultado es similar al otorgado por Excel, pero no es igual, y a veces esto es crítico para mi aplicación porque con Excel el resultado no supera el umbral y con Apache Commons Math en Java, así que obtengo salidas diferentes.Java Apache Commons getPercentile() resultado diferente que MS Excel percentil

aquí está un ejemplo: el tráfico de Internet (Mbps) cada 2 horas

32,7076813360000000 41,2580429776000000 45,4453940200000000 48,8044409456000000 46,7462847936000000 49,8028100056000000 54,3719451144000000 41,9708134600000000 29, 4371963240000000 22,4667255616000000 20,0388452248000000 28,7807757104000000

Después de dividir por 1000 Mb (la capacidad del cable) calculo el percentil (85) de la ocupación:

Excel: 0,049153870117

Apache Commons matemática: 0,05003126676104001

he encontrado que es posible cambiar la implementación del percentil (no existe uno oficial) con setPercentileImpl(), pero no pude encuentre algún ejemplo de cómo hacer esto, o el algoritmo de Excel (que es el que me dijeron que debía lograr).

Cualquier ayuda sobre esto será bienvenida.

Gracias.

+1

¿Puede dar un ejemplo de la discrepancia que se ve? Con datos, podemos probarnos a nosotros mismos? –

+0

Claro, editaré mi pregunta con los datos. –

+1

Tenga en cuenta que el motivo de los resultados differet es que el conjunto de valores es 12. Para valores más grandes, ambos algoritmos darían resultados similares. Mi problema es cómo implementar el método de Excel en Java. –

Respuesta

5

La solución fue crear una clase PercentileExcel que es casi una copia del percentil del método de bienes comunes a excepción de un pequeño cambio en la forma de caculate la posición:

pos=(1+p*(n-1))/100; 

Luego hay que añadir esta línea al código con el fin de utilizar la nueva clase de percentil:

setPercentileImpl(PercentileExcel); 
4

No existe una definición única de un percentil calculado a partir de un conjunto de datos. Consulte Wikipedia page para conocer las definiciones más comunes en uso.

+0

Sí, fundé al menos 3 diferentes. –

9

La diferencia es sutil y debido a suposiciones. Es más fácil de explicar con el caso de 3 elementos. Supongamos que tiene tres elementos (N = 3) a=x[0] < b=x[1] < c=x[2]. Tanto el método de Apache como el de Excel dicen que el elemento b es el percentil 50 (la mediana). Sin embargo, difieren para a y c.

El Apache method (y the method referenced by the NIST page) dicen a es el percentil 25 y c es el percentil 75%, ya que divide el espacio arriba en n + 1 bloques, es decir, en cuartos.

El método de Excel dice que a es el percentil 0 y c el percentil 100, ya que el espacio está dividido en N-1 bloques, es decir, en la mitad.

Debido a esto, si quiere el método de Excel y no desea codificarlo usted mismo, puede simplemente eliminar el elemento más pequeño y el más grande de su matriz, y llamar al método de Apache; debe proporcionarle exactamente el mismo resultado excepto en percentiles más allá de los puntos finales.

Si desea codificarlo usted mismo, a continuación se ofrece una manera sencilla. Sé consciente de estos problemas:

  • este ordena la matriz (por lo cambia)
  • esta toma O (log N (N)) el tiempo debido a la clasificación.El método Apache utiliza un algoritmo de selección rápida, por lo que toma O (N) la hora (google "quickselect" si quiere saber más)

Código (no probado o incluso compilado, pero debería darle una idea).

// warning - modifies data 
double excelPercentile(double [] data, double percentile) { array 
    Arrays.sort(data); 
    double index = percentile*(data.length-1); 
    int lower = (int)Math.floor(index); 
    if(lower<0) { // should never happen, but be defensive 
     return data[0]; 
    } 
    if(lower>=data.length-1) { // only in 100 percentile case, but be defensive 
     return data[data.length-1); 
    } 
    double fraction = index-lower; 
    // linear interpolation 
    double result=data[lower] + fraction*(data[lower+1]-data[lower]); 
    return result; 
} 
+0

Gracias. Creo que fundé el código fuente de la implementación de Commons http://www.java2s.com/Open-Source/Java-Document/Science/Apache-commons-math-1.1-src/org/apache/commons/math/stat /descriptive/rank/Percentile.java.htm Lo intentaré cambiando el valor asigned a pos en la línea 199. Esto debería funcionar, y no tendré que cambiar la estructura de mi código. –

+1

Parece que debería funcionar. Supongo que doblar pos = 1+ p * (n - 1)/100; –

+1

Supongo que creará una nueva clase, en lugar de simplemente reemplazar la clase Percentile en su jar de Apache. Esto podría ser peligroso si otras clases de la jarra Apache usan este método, y también significa que tendrá que mantenerlo actualizado con futuras versiones –

2

clase org.apache.commons.math3.stat.descriptive.rank.Percentile ya suppo interpolación estilo RTS Excel, sólo tiene que activarlo con EstimationType.R_7

public class PercentileExcel extends Percentile { 
    public PercentileExcel() throws MathIllegalArgumentException { 

    super(50.0, 
      EstimationType.R_7, // use excel style interpolation 
      NaNStrategy.REMOVED, 
      new KthSelector(new MedianOf3PivotingStrategy())); 
    } 
} 
+0

Nota: Esto no es compatible con commons-math-3.0 o inferior, solo commons-math-3.5 lo tiene. – sichinumi

Cuestiones relacionadas