Étant donné le long éventail de latences exprimées en millisecondes, je souhaite calculer leur percentile. J'ai la méthode ci-dessous qui fait le travail mais je ne sais pas comment je peux vérifier si cela me donne un résultat précis?
public static long[] percentiles(long[] latencies, double... percentiles) {
Arrays.sort(latencies, 0, latencies.length);
long[] values = new long[percentiles.length];
for (int i = 0; i < percentiles.length; i++) {
int index = (int) (percentiles[i] * latencies.length);
values[i] = latencies[index];
}
return values;
}
J'aimerais obtenir les 50e, 95e, 99e et 99,9e centiles du tableau latencies
.
long[] percs = percentiles(latencies, 0.5, 0.95, 0.99, 0.999);
Est-ce la bonne façon d’obtenir des centiles avec une longue gamme de latences? Je travaille avec Java 7.
C'est ce que vous recherchez:
class Program
{
static void Main(string[] args)
{
List<long> latencies = new List<long>() { 3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20 };
Console.WriteLine(Percentile(latencies,25));
Console.WriteLine(Percentile(latencies, 50));
Console.WriteLine(Percentile(latencies, 75));
Console.WriteLine(Percentile(latencies, 100));
Console.ReadLine();
}
public static long Percentile(List<long> latencies, double Percentile)
{
latencies.Sort();
int Index = (int)Math.Ceiling(((double)Percentile / (double)100) * (double)latencies.Count);
return latencies[Index-1];
}
}
Selon Wikipedia , il n’existe pas de définition standard du percentile; Cependant, ils donnent quelques définitions possibles. Le code que vous avez posté semble être le plus proche de la méthode de classement le plus proche, mais ce n'est pas tout à fait la même chose.
La formule qu'ils donnent est
n = ceiling((P / 100) x N)
où N
est la longueur de la liste, P
est le centile et n
sera le rang ordinal. Vous avez déjà fait la division par 100. En regardant les exemples qu'ils donnent, il est clair que le "rang ordinal" est l'indice dans la liste, mais c'est 1 relatif. Ainsi, pour obtenir un index dans un tableau Java, vous devez soustraire 1. Par conséquent, la formule correcte doit être
n = ceiling(percentile * N) - 1
En utilisant les variables de votre code, l’équivalent Java serait:
(int) Math.ceil(percentiles[i] * latencies.length) - 1
Ce n'est pas tout à fait le code que vous avez écrit. Lorsque vous transformez une double
en une int
, le résultat est arrondi à 0, c'est-à-dire qu'il équivaut à la fonction "floor". Donc, votre code calcule
floor(percentiles[i] * latencies.length)
Si percentiles[i] * latencies.length
n'est pas un entier, le résultat est le même dans les deux cas. Cependant, s'il s'agit d'un entier, de sorte que "plancher" et "plafond" aient la même valeur, le résultat sera alors différent.
Un exemple de Wikipedia consiste à calculer le 40e centile lorsque la liste est {15, 20, 35, 40, 50}. Leur réponse est de trouver le deuxième élément de la liste, à savoir 20, car 0,40 * 5 = 2,0 et plafond (2,0) = 2,0.
Cependant, votre code:
int index = (int) (percentiles[i] * latencies.length);
index
sera égal à 2, ce qui n'est pas ce que vous voulez, car cela vous donnera le troisième élément de la liste, au lieu du deuxième.
Donc, afin de correspondre à la définition de Wikipedia, votre calcul de l'index devra être légèrement modifié. (D'un autre côté, je ne serais pas surpris si quelqu'un se présente et dit que votre calcul est correct et que Wikipedia a tort. Nous verrons ...)