Numpy: Méthodes centiles de restructuration

Créé le 12 mars 2018  ·  53Commentaires  ·  Source: numpy/numpy

Comme illustré dans la page Wikipédia: https://en.wikipedia.org/wiki/Percentile#The_nearest -rank_method

00 - Bug 01 - Enhancement high

Tous les 53 commentaires

Je pense que cela existe déjà? En utilisant l'exemple wikipedia:

>>> np.percentile(15, 20, 35, 40, 50], [5, 30, 40, 50, 100], interpolation='lower')
array([15, 20, 20, 35, 50])

Ce ne est pas. Regardez l'exemple 2 sur la page wikipedia:

>>> np.percentile([3, 6, 7, 8, 8, 10, 13, 15, 16, 20], [25,50,75,100], interpolation='lower')
array([ 7,  8, 13, 20])

Quand cela devrait être [7,8,15,20]

Il échoue de la même manière dans le troisième exemple

Le plus proche ressemble beaucoup à "le plus proche"? Bien qu'il y ait toujours un autre point sur le fonctionnement exact des limites.
EDIT: Autrement dit, où sont exactement 0 et 100 considérés comme étant, au point de données ou avant le point de données? (c'est IIRC, de toute façon il y a beaucoup de complexités ennuyeuses ici)

Je ne veux pas le lire, je pense que la différence pourrait être le paramètre C plus bas, donc si quelqu'un qui sait cela veut ajouter ceci ...

Franchement, je pense que l'ajout du paramètre C serait probablement vraiment bien. Mais surtout, une meilleure documentation serait bien, et quelqu'un qui connaît vraiment ce genre de choses est nécessaire ...

Je ne sais pas si cela a quelque chose à voir avec le paramètre C, bien que je convienne que l'option de le choisir pourrait être souhaitable.

J'ai trouvé un autre fil qui a d'ailleurs soulevé ce problème (décembre 2016). Il semble que l'algorithme que je recherche (et que wikipedia appelle le rang le plus proche) soit mentionné dans cet article couramment cité par Hyndman-Fan (H&F) comme étant la définition la plus ancienne et la plus étudiée du percentile (c'est celle que j'ai apprise dans Cours de statistiques). C'est une fonction discontinue, donc je pense que le paramètre C ne s'applique pas ici (je me trompe peut-être).

Voici à quoi cela ressemblerait par rapport aux autres options fournies par numpy qui semblent intuitivement calculer une chose similaire (c'est-à-dire 'inférieur', 'le plus proche'):

percentiles

Pour moi, cela ressemble exactement au paramètre C à première vue, la courbe la plus proche est plus étirée que la courbe H&F, ce qui est attendu puisque numpy utilise 1 et apparemment H&F utilise 0.

Si vous voulez une preuve. Répétez le tout avec les mêmes valeurs répétées 1000 fois, je suppose qu'elles vont converger.
EDIT: Ou peut-être pas, n'avez pas la patience ou le temps de vraiment y penser. Mais je pense toujours que c'est le paramètre C que wikipedia mentionne, alors s'il vous plaît me prouver le contraire :)

Un graphique comme celui-ci serait un excellent ajout aux documents centiles

edit: de préférence un montrant l'ouverture / la fermeture des discontinuités

Note aux lecteurs: pour que ce fil reste gérable, j'ai marqué toutes les discussions ci-dessous sur l'ajout de ce graphique aux documents comme "résolues". Le graphique est maintenant au bas de https://numpy.org/devdocs/reference/generated/numpy.percentile.html.

@ eric-wieser Cela ne me dérange pas de faire ce graphique. Je reviendrai avec quelque chose plus tard aujourd'hui, dois-je le poster ici?

@seberg Je vais être honnête ici, je ne sais pas comment l'interpolation est calculée en fonction du paramètre C. Ce qui me fait penser que ce n'est pas lié, c'est que le paramètre C n'est discuté que dans la section d'interpolation linéaire (Wikipedia), et l'article de Wikipedia et Hyndmand & Fan discutent de l'algorithme que j'ai demandé dans des sections distinctes de celles d'interpolation.

Je ne sais pas s'il existe des paramètres d'interpolation qui donnent toujours les mêmes résultats que l'algorithme qui m'intéresse.

Même s'il y en a, est-ce que cela devrait être le moyen utilisé pour y arriver? Changer un paramètre «étrange» pour obtenir la définition la plus courante du percentile ne semble pas la meilleure façon de l'implémenter à mon humble avis.

@ ricardoV94 , peut-être, mais vous ne pouvez pas simplement changer les valeurs par défaut, aussi mauvaises qu'elles soient. Nous pourrions exposer quelque chose comme method = "H&K" pour remplacer les deux paramètres à la fois.

Le paramètre C est l'endroit où vous définissez 0% et 100% par rapport aux points de données (sur le point de données ou non, etc.). En tant que paramètre C sur wikipedia, il se peut que ce ne soit que pour l'interpolation, mais le même problème cause la différence ici, j'en suis sûr. C est douteux bien sûr, un nom propre pourrait être quelque chose comme range = 'min-max' ou range = 'extrapolated' ou probablement quelque chose de complètement différent. Comme je l'ai dit, refaites les tracés avec de nombreux points de données (éventuellement avec un petit bruit), et je pense que vous les verrez converger, car la définition de la plage devient moins évidente.

@seberg Je suis bien avec method = "H&K" ou peut-être method = "classic". Interpolation = "aucun" pourrait également avoir un sens.

Je ne sais pas quel est le mécanisme pour inclure des images dans les documents, ou s'il existe un précédent pour le faire.

Je sais que vous pouvez exécuter du code matplotlib dans la documentation, c'est ainsi que nous le faisons ailleurs - ce qui garantit également qu'il reste synchronisé avec la réalité.

D'accord, je penserai à la meilleure image de code dans ce cas.

La partie la plus problématique sont les marqueurs ouverts et fermés de discontinuité, car matplotlib n'a pas de fonction intégrée pour cela (afaik). Les coder en dur n'aurait pas de sens dans ce cas.

Peut-être les sauter pour le moment. Ce serait bien si matplotlib avait un support automatique pour ceux-ci.

Espérons que quelqu'un aura une meilleure suggestion, qui est toujours élégante en ce qui concerne la discontinuité.

import matplotlib.pyplot as plt

a = [0,1,2,3]
p = np.arange(101)

plt.step(p, np.percentile(a, p, interpolation='linear'), label='linear')
plt.step(p, np.percentile(a, p, interpolation='higher'), label='higher', linestyle='--')
plt.step(p, np.percentile(a, p, interpolation='lower'), label='lower', linestyle='--')
plt.step(p, np.percentile(a, p, interpolation='nearest'), label='nearest', linestyle='-.',)
plt.step(p, np.percentile(a, p, interpolation='midpoint'), label='midpoint', linestyle='-.',)

plt.title('Interpolation methods for list: ' + str(a))
plt.xlabel('Percentile')
plt.ylabel('List item returned')
plt.yticks(a)
plt.legend()

Image

Je pense que le interpolation = 'linear' devrait être une ligne régulière non étagée, mais sinon, ça a l'air bien. Pouvez-vous faire un PR en ajoutant cela à la documentation?

En fait, step cause généralement des artefacts trompeurs, je serais donc enclin à l'éviter. linspace(0, 100, 60) produirait également des coordonnées intermédiaires plus précises

Je n'ai aucune idée de comment faire un PR.

N'hésitez pas à le faire avec votre compte, en ajoutant ou en discutant des modifications suggérées.

Je pense que vous pouvez changer C avec quelque chose comme ça (testez-le sur quelque chose). Appelez la fonction sur vos percentiles, puis branchez-la dans la version numpy (qui utilise C = 1, qui est un no-op sauf la correction des percentiles liés pour le moment):

def scale_percentiles(p, num, C=0):
     """
     p : float
          percentiles to be used (within 0 and 100 inclusive)
     num : int
         number of data points.
     C : float
         parameter C, should be 0, 0.5 or 1. Numpy uses 1, matlab 0.5, H&K is 0.
     """
     p = np.asarray(p)
     fact = (num-1.+2*C)/(num-1)
     p *= fact
     p -= 0.5 * (fact-1) * 100
     p[p < 0] = 0
     p[p > 100] = 100
     return p

Et voila, avec "le plus proche", vous obtiendrez votre "H&F" et avec linéaire, vous obtiendrez l'intrigue de Wikipedia. (en attendant que je me trompe, mais je suis presque sûr d'avoir bien compris).

Comme je l'ai dit, la différence est l'endroit où vous placez les points de données de 0 à 100 (uniformément) par rapport au dernier point. Pour C = 1, vous mettez min (données) au 0e centile, etc. Je n'ai aucune idée de «ce qui a le plus de sens», cela compte probablement un peu pour la vue générale. Le nom inclusif pour 1 et exclusif pour 0 a un peu de sens, je suppose (quand vous pensez à la plage totale de percentiles, car la plage possible exclusive est en dehors de la plage de données). C = 1/2 est également exclusif dans ce sens.

Je serais pour ajouter le paramètre C, mais je voudrais que quelqu'un propose un nom descriptif si possible. Cela ne me dérangerait pas non plus quelque chose comme une "méthode" ou autre pour rendre les meilleurs défauts évidents (combinaison d'interpolation + C). Ou, nous décidons fondamentalement que la plupart des combinaisons ne sont jamais utilisées et ne sont pas utiles, très bien alors ....

En fin de compte, mon problème est le suivant: je veux qu'un statisticien me dise quelles méthodes ont un consensus (R a des choses, mais la dernière fois que quelqu'un est venu ici, c'était juste une copie de R doc ou similaire sans le mettre dans un contexte numpy à tout cela, il va sans dire que cela ne servait à rien pour un grand public, citer des articles aurait été plus utile).

Je ne veux pas lire cet article de H&F (honnêtement, il n'a pas l'air très facile à lire), mais je pense que vous pourriez aussi le regarder du point de vue du support. La version numpy "la plus proche" (ou toute autre) n'a pas le même support (dans les centiles) pour chaque point de données, H&F a le même support pour "le plus proche" et peut-être pour le point médian ce serait C = 1/2, pas sûr.
Je n'arrête pas de me répéter, je ne sais pas si un tel argument de support (contre C = 1 tel que numpy l'utilise), est en fait une vraie raison.

EDIT: le point médian a le même support (pour la zone entre les points de données, pas pour le point lui-même) dans numpy, donc avec "C = 1"

@seberg Cela ne semble pas fonctionner avec moi. Pouvez-vous poster votre code en montrant qu'il fonctionne?

Eh bien, je me suis trompé de signe, dans ce code là-haut, donc c'était le contraire (C = 0 un no-op pas C = 1):

def scale_percentiles(p, num, C=0):
     """
     p : float
          percentiles to be used (within 0 and 100 inclusive)
     num : int
         number of data points.
     C : float
         parameter C, should be 0, 0.5 or 1. Numpy uses 1, matlab 0.5, H&F is 0.
     """
     p = np.asarray(p)
     fact = (num+1.-2*C)/(num-1)
     p *= fact
     p -= 0.5 * (fact-1) * 100
     p[p < 0] = 0
     p[p > 100] = 100
     return p
plt.figure()
plt.plot(np.percentile([0, 1, 2, 3], scale_percentiles(np.linspace(0, 100, 101), 5, C=0), interpolation='nearest'))
plt.plot(np.percentile([0, 1, 2, 3], scale_percentiles(np.linspace(0, 100, 101), 5, C=1), interpolation='nearest'))
plt.figure()
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=1), interpolation='linear'))
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=0.5), interpolation='linear'))
plt.plot(np.percentile([15, 20, 35, 40, 50], scale_percentiles(np.linspace(0, 100, 101), 5, C=0), interpolation='linear'))

@seberg Fermer mais pas encore là. Pour a = [0,1,2,3] et percentiles = [25, 50, 75, 100] , np.percentile (a, scale_percentiles(percentiles, len(a), C=0), interpolation='nearest) renvoie [0, 2, 3, 3] , alors qu'il doit renvoyer [0,1,2,3] .

J'ai dû créer les centiles dtype=np.float la liste

La fonction de la méthode classique est simple:
Percentile / 100 * N -> Si c'est un nombre entier qui est l'indice, sinon, utilisez le plafond comme indice.

Malgré cela, l'argument C semble fonctionner comme prévu, il pourrait donc être implémenté si les gens veulent l'utiliser pour l'interpolation. Je voudrais toujours une méthode = 'classique' ou une interpolation = 'aucune' qui fonctionnerait comme celle de wikipedia.

Pour le débogage, voici mon implémentation laide et non numpy de la méthode classique:

def percentile (arr, p):
    arr = sorted(arr)

    index = p /100 * len(arr)

    # If index is a whole number, and larger than zero, subtract one unit (due to 0-based indexing)
    if index%1 < 0.0001 and index//1 > 0:
        index -= 1

    return arr[int(index)]

et un plus numpythonique:

def indexes_classic(percentiles, set_size):
    percentiles = np.asarray(percentiles)

    indexes = percentiles / 100* set_size
    indexes[np.isclose(indexes%1, 0)] -= 1
    indexes = np.asarray(indexes, dtype=np.int)
    indexes[indexes < 0] = 0
    indexes[indexes > 100] = 100

    return indexes

Ces différences ressemblent à des problèmes de virgule flottante / d'arrondi (que vous
semble conscient de), et peut-être que ma supposition avec C = 0 était fausse et que vous voulez
C = 0,5.
Mon propos était de dire d'où vient la différence (Le "paramètre C"
IMO, bien qu'il y ait probablement de bonnes raisons de ne pas aimer beaucoup
combinaisons). Ce n'était pas pour vous donner / mettre en œuvre une solution de contournement.

Quant à la méthode "classique", je me fiche franchement peu de ce que le classique
est censé être. Pour tout ce que je sais, classique signifie simplement "pas mal
les gens l'utilisent ".

Solution sage, ma première impression est que "classique" ou autre
nom, ajoute simplement une autre option déroutante avec un nom peu clair. J'espère
que cette discussion pourrait aller dans le sens de rendre tous
bonnes options (courantes) disponibles pour les utilisateurs dans un cadre propre et transparent
façon. Meilleur d'une manière que les gens pourraient réellement comprendre.

Nous pouvons ajouter une méthode de plus, mais franchement, je ne l'aime qu'à moitié. quand nous
a ajouté plus de méthodes pour la dernière fois (je ne me souviens pas de ce qui a changé exactement)
déjà retardé et espérait que quelqu'un sauterait et comprendre
ce que nous devrions avoir. Inutile de dire que cela ne s'est jamais vraiment produit. Et maintenant
J'essaie de souligner les différences et de voir comment cela pourrait convenir
avec ce que nous avons actuellement.

Donc, mon impression est (avec d'éventuels problèmes d'arrondi et
correspondances au centile) nous avons (probablement trop) d'options "d'interpolation"
et nécessiterait le "paramètre C" ou ce que vous voulez appeler
être capable de faire presque tout.
Et je serais vraiment heureux si quelqu'un pouvait me dire comment tout
(commun) Les "méthodes" qui existent dans ces catégories, il semble que
plus alors C = 0,0.5,1 existent même, et peut-être même en dehors de ceux
options ....

Peut-être que je vais dans la mauvaise voie, mais en ajoutant "Méthode 1" avec un
nom peu clair qui ne dit vraiment à personne en quoi il diffère du
les autres méthodes ne me semblent pas utiles (sauf pour quelqu'un qui
il se trouve que vous connaissez déjà le nom "Method1" et que vous le recherchez. Et
s'il vous plaît ne dites pas que le "classique" est celui qui est évident, il y a
beaucoup trop de variance dans les implémentations là-bas.

Une autre façon pourrait être de désapprouver l '"interpolation", mais d'avoir une liste
des méthodes est également beaucoup moins agréable que de faire allusion à une "interpolation linéaire"
pour dire que ce n'est pas un comportement par étapes, etc .... Et si on va par là,
Je veux toujours un aperçu raisonnable.

Vous n'êtes pas obligé de le faire, mais si nous voulons ajouter une nouvelle méthode, nous avons besoin d'un
façon de l'ajouter qui ne déroute pas encore plus tout le monde et c'est clair!

Permettez-moi de le résumer alors:

1) Pour le moment, numpy n'offre qu'une seule méthode utile: interpolation = 'linear', et les autres ne sont que de petites variations autour de lui qui ne semblent vraiment être utilisées par personne. D'autres packages ont de nombreuses options plus pertinentes.

2) Ajouter les autres valeurs pour C = 0 ou C = 0,5, a du sens pour moi. Toutes les méthodes d'interpolation peuvent fonctionner en combinaison avec elles, même si, là encore, elles ne seront probablement jamais utilisées.

3) Si l'un des combos entre les méthodes d'interpolation et l'argument C parvient à reproduire la méthode classique (la référence et wikipedia et mon expérience personnelle conviennent que c'est la méthode la plus couramment enseignée), alors j'en suis satisfait. On peut dire dans la documentation qu'une telle combinaison produit la méthode classique de non-interpolation. Je ne sais pas si cela est uniquement dû à des problèmes de précision du flotteur, mais j'apprécie vos efforts pour y remédier de manière plus intégrée!

4) Si aucun des combos n'obtient le même résultat, je pense qu'une méthode différente aurait du sens. Peut-être appelé interpolation = «aucun» serait le moins déroutant.

En résumé: les options actuelles de numpy.percentile semblent à la fois assez déroutantes et limitées. Le document mentionné ci-dessus offre un bon aperçu d'autres méthodes utiles. Avec la page wikipedia, ils pourraient servir de point de départ pour la conception d'un ensemble d'options plus exhaustif et utile pour numpy.percentile. J'espère que quelqu'un aimerait travailler sur cette tâche.

Le "plus proche" actuel a-t-il un sens dans certains cas? Si la méthode d'espacement ("C") ou quoi que ce soit fait une si grande différence pour l'interpolation linéaire / les trucs fractionnaires, je suis peut-être juste surpris que personne ne l'ait jamais fait pour des approximations non fractionnaires?! Le support constant est-il si important et il y a une raison de vider l'argument inverse CDF pour les méthodes d'interpolation?

Les combos sont inutiles à moins qu'ils ne soient compréhensibles et qu'ils soient faciles à trouver, donc j'en doute. Pour l'interpolation, de nombreuses options semblent exister (par exemple http://mathworld.wolfram.com/Quantile.html Q4 à Q9, je pense que la documentation R est pratiquement identique, mais je pense qu'elle n'est probablement pas complète, par exemple matlab ...) Je n'ai aucune idée si elles ont toutes un sens;).

Le truc, c'est que "l'interpolation" indique ce qu'il faut faire entre des points exactement définis, mais il existe de nombreuses (étrangement nombreuses) façons de placer ces points au moins en utilisant "l'interpolation linéaire", donc cela semble être une mauvaise approche pour y ajouter. Vous vouliez un "rang le plus proche" qui sonne beaucoup (et qui est dans l'esprit) interpolation = "le plus proche", mais le choix de la "position de traçage" exacte semble "non standard", il sera donc impossible de deviner et donc un mauvais choix.

Alors je préférerais même déprécier tout de manière agressive (sauf probablement linéaire).

Mais, si nous abandonnons, je veux que les choses soient correctes à 100%, et cela pourrait nécessiter un peu plus de clarté sur ce qui existe, ce qui devrait exister et ce qui ne devrait définitivement pas exister.

Je suis totalement d'accord avec vous

@ ricardoV94 : avez-vous des opinions sur les définitions de linear pour le cas quantile pondéré proposé en # 9211? Il y a des graphiques dans le même style.

Peut-être que @ ricardoV94 peut commenter (ce serait cool), mais je pense que le problème est assez orthogonal. Les poids sont probablement simplement des poids de type fréquence, en supposant qu'il n'y ait pas d'autres poids raisonnablement définis pour le percentile (je ne vois pas comment), il ne devrait pas y avoir d'ambiguïté lors de leur mise en œuvre, mais je ne sais pas avec certitude.

Vous pouvez également essayer d'envoyer un ping à josef-pkt sur ce PR et espérer qu'il aura un commentaire rapide s'il pense que c'est une bonne idée / raison.

Si quelqu'un veut le prendre à partir d'ici, j'ai écrit une fonction non optimisée qui calcule le
Méthodes d'estimation au 9 percentile / quantile décrites par Hyndman et Fan (1996) et également utilisées dans R.

La méthode 1 correspond à la «méthode classique du rang le plus proche», comme indiqué dans Wikipedia . La méthode 7 est équivalente à l'implémentation actuelle de Numpy (interpolation = 'linear'). Les autres méthodes d'interpolation Numpy ne sont pas incluses (et elles ne semblent pas être utiles de toute façon).

def percentile(x, p, method=7):
    '''
    Compute the qth percentile of the data.

    Returns the qth percentile(s) of the array elements.

    Parameters
    ----------
    x : array_like
        Input array or object that can be converted to an array.
    p : float in range of [0,100] (or sequence of floats)
        Percentile to compute, which must be between 0 and 100 inclusive.
    method : integer in range of [1,9]
        This optional parameter specifies one of the nine sampling methods 
        discussed in Hyndman and Fan (1996). 

        Methods 1 to 3 are discontinuous:
        * Method 1: Inverse of empirical distribution function (oldest
        and most studied method).
        * Method 2: Similar to type 1 but with averaging at discontinuities.
        * Method 3: SAS definition: nearest even order statistic.

        Methods 4 to 9 are continuous and equivalent to a linear interpolation 
        between the points (pk,xk) where xk is the kth order statistic. 
        Specific expressions for pk are given below:
        * Method 4: pk=kn. Linear interpolation of the empirical cdf.
        * Method 5: pk=(k−0.5)/n. Piecewise linear function where the knots 
        are the values midway through the steps of the empirical cdf 
        (Popular amongst hydrologists, used by Mathematica?).
        * Method 6: pk=k/(n+1), thus pk=E[F(xk)]. The sample space is divided
        in n+1 regions, each with probability of 1/(n+1) on average
        (Used by Minitab and SPSS).
        * Method 7: pk=(k−1)/(n−1), thus pk=mode[F(xk)]. The sample space
        is divided into n-1 regions (This is the default method of 
        Numpy, R, S, and MS Excell).
        * Method 8: pk=(k−1/3)/(n+1/3), thus pk≈median[F(xk)]. The resulting
        estimates are approximately median-unbiased regardless of the
        distribution of x (Recommended by Hyndman and Fan (1996)).
        * Method 9: k=(k−3/8)/(n+1/4), thus pk≈F[E(xk)]if x is normal (?).
        The resulting estimates are approximately unbiased for the expected 
        order statistics if x is normally distributed (Used for normal QQ plots).

        References:
        Hyndman, R. J. and Fan, Y. (1996) Sample quantiles in statistical packages, 
        American Statistician 50, 361--365.
        Schoonjans, F., De Bacquer, D., & Schmid, P. (2011). Estimation of population
        percentiles. Epidemiology (Cambridge, Mass.), 22(5), 750.

        '''

    method = method-1    
    x = np.asarray(x)
    x.sort()
    p = np.array(p)/100

    n = x.size  
    m = [0, 0, -0.5, 0, 0.5, p, 1-p, (p+1)/3, p/4+3/8][method]

    npm = n*p+m
    j = np.floor(npm).astype(np.int)
    g = npm-j

    # Discontinuous functions
    if method < 3:
        yg0 = [0, 0.5, 0][method]
        y = np.ones(p.size)
        if method < 2:
            y[g==0] = yg0
        else:
            y[(g==0) & (j%2 == 0)] = yg0      
    # Continuous functions
    else:
        y = g

    # Adjust indexes to work with Python
    j_ = j.copy()
    j[j<=0] = 1
    j[j > n] = n
    j_[j_ < 0] = 0
    j_[j_ >= n] = n-1 

    return (1-y)* x[j-1] + y*x[j_]

Les méthodes continues peuvent également être mises en œuvre plus efficacement de cette manière.

def percentile_continuous(x, p, method=7):
    '''
    Compute the qth percentile of the data.

    Returns the qth percentile(s) of the array elements.

    Parameters
    ----------
    x : array_like
        Input array or object that can be converted to an array.
    p : float in range of [0,100] (or sequence of floats)
        Percentile to compute, which must be between 0 and 100 inclusive.
    method : integer in range of [4,9]
        This optional parameter specifies one of the 5 continuous sampling
        methods discussed in Hyndman and Fan (1996). 
        '''

    x = np.asarray(x)
    x.sort()
    p = np.asarray(p)/100
    n = x.size

    if method == 4:
        r = p * n
    elif method == 5:
        r = p * n + .5
    elif method == 6:
        r = p * (n+1)
    elif method == 7:
        r = p * (n-1) + 1
    elif method == 8:
        r = p * (n+1/3) + 1/3
    elif method == 9:
        r = p * (n+1/4) + 3/8

    index = np.floor(r).astype(np.int)

    # Adjust indexes to work with Python
    index_ = index.copy()
    index[index_ <= 0] = 1
    index[index_  > n] = n
    index_[index_ < 0] = 0
    index_[index_ >= n] = n-1

    i = x[index - 1]
    j = x[index_]

    return i + r%1* (j-i)

Quelqu'un veut le prendre d'ici? Je ne suis pas qualifié pour le faire.

Comme mentionné dans l'article précédent, il semble que l'implémentation par défaut actuelle du quantile par numpy corresponde à celle de R .

En R :

> quantile(c(15, 20, 35, 40, 50), probs=c(0.05, 0.3, 0.4, 0.5, 1))
  5%  30%  40%  50% 100% 
  16   23   29   35   50 
> quantile(c(3, 6, 7, 8, 8, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1))
  25%   50%   75%  100% 
 7.25  9.00 14.50 20.00
> quantile(c(3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1))
 25%  50%  75% 100% 
 7.5  9.0 14.0 20.0 

En np.quantile :

>>> np.quantile([15, 20, 35, 40, 50], q=[0.05, 0.3, 0.4, 0.5, 1])
array([16., 23., 29., 35., 50.])
>>> np.quantile([3, 6, 7, 8, 8, 10, 13, 15, 16, 20], q=[0.25, 0.5, 0.75, 1])
array([ 7.25,  9.  , 14.5 , 20.  ])
>>> np.quantile([3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20], q=[0.25, 0.5, 0.75, 1])
array([ 7.5,  9. , 14. , 20. ])

qui bien sûr ne reproduisent pas les exemples donnés sur Wikipedia:
https://en.wikipedia.org/wiki/Percentile

En fait, si vous allez sur la page d'aide R pour quantile https://www.rdocumentation.org/packages/stats/versions/3.5.0/topics/quantile
vous verrez que la méthode par défaut R (Type 7) définit les conditions aux limites identiques à la façon dont np.quantile définit: p_k = (k-1) / (n-1) , où n est la taille de l'échantillon, et k = 1 désigne le plus petit valeur, tandis que k = n est le plus grand. Cela signifie que la plus petite valeur du tableau trié est épinglée à quantile = 0, et la plus grande est épinglée à quantile = 1.

Comme mentionné dans le post précédent, vous pouvez reproduire les 3 exemples de Wikipédia avec le type 1:

> quantile(c(15, 20, 35, 40, 50), probs=c(0.05, 0.3, 0.4, 0.5, 1), type=1)
  5%  30%  40%  50% 100% 
  15   20   20   35   50 
> quantile(c(3, 6, 7, 8, 8, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1), type=1)
 25%  50%  75% 100% 
   7    8   15   20 
> quantile(c(3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20), probs=c(0.25, 0.5, 0.75, 1), type=1)
 25%  50%  75% 100% 
   7    9   15   20 

Cela soulève des questions intéressantes:

1.) La valeur par défaut de np.quantile doit-elle suivre la valeur par défaut de R.quantile?
2.) np.quantile doit-il passer à l'algorithme de type 1?

Étant donné que même Wikipédia convient qu'il n'y a pas de définition standard du percentile, je pense que tant que l'algorithme est solide et que l'utilisateur est conscient de son fonctionnement, ni (1) ni (2) n'ont autant d'importance. Je suis plus en faveur de (1) parce que Python et R sont deux des plates-formes d'analyse de données les plus populaires, et ce serait bien qu'ils puissent se contrôler mutuellement. Compte tenu de cela, je pense que (2) est inutile.

Oui, R et Numpy utilisent par défaut la méthode 7 et cela devrait être conservé comme ça. La question est d'ajouter ou non les autres méthodes.

Si quelqu'un est intéressé, j'ai mis en place un module indépendant avec les méthodes des 9 centiles, ici . N'hésitez pas à l'utiliser ou à vous adapter à Numpy si vous savez comment.

Merci @ ricardoV94 .

Donc, juste pour les coups de pied, j'ai fait un sondage au travail sur les utilisateurs R. Sur les 20 personnes qui ont répondu, 20 n'utilisent que la méthode par défaut dans quantile . Ils vont des étudiants de maîtrise en santé publique aux doctorants en statistique.

Personnellement, je ne suis pas sûr que cela en vaille la peine pour numpy de prendre en charge 9 façons différentes de calculer le quantile. Je pense que la plupart des utilisateurs utiliseront simplement la valeur par défaut.

Pour ce que ça vaut, il y a la fonction scipy.stats.mstats.mquantiles qui supporte 6 des 9 méthodes (les continues) et la doc énonce très explicitement les liens avec l'implémentation R.

@albertcthomas ah, c'est bon à savoir. Bien que, je pense que dans l'idéal, nous cacherions un peu cette complexité de manière numpy. Et nous devons surtout corriger les versions non contiguës IIRC. Parce que ceux-ci ne donnent fondamentalement pas les méthodes les plus courantes.

Oui, en effet, numpy ne devra pas nécessairement prendre en charge ces méthodes si elles sont implémentées dans le module scipy stats.

Personnellement, je serais favorable à une méthode de calcul du quantile à partir de l'inverse généralisé de la fonction de distribution cumulative. Le fait qu'une telle méthode ne soit pas disponible m'amène à ce problème :).

@albertcthomas si vous avez des indices / connaissances à ce sujet, dites-le! Nous sommes un peu coincés à cause d'un manque de clarté ce qui est en fait un bon défaut. Et je pense que c'est un problème assez ennuyeux.

Plus important encore, nous avons besoin de quelques bons défauts. Et cela signifie probablement implémenter 2-3 méthodes (réorganiser complètement les méthodes non contiguës). Je suis d'accord pour supporter des trucs plus ou plus complexes, mais j'aimerais beaucoup que nous puissions choisir quelques "typiques / bons".

Je dirais que la méthode linéaire (par défaut actuelle) et l'inverse de la fonction de distribution cumulative (que je recherchais lorsque j'ai créé ce numéro, ainsi que @albertcthomas si je comprends bien) suffiraient. Fondamentalement, cela permet de choisir s'il veut ou non une interpolation.

Et les autres alternatives actuellement mises en œuvre devraient définitivement être supprimées.

Il faut absolument ajouter l'inverse de la fonction de distribution cumulative. C'est l'un des estimateurs les plus populaires d'un quantile d'un échantillon donné d'observations en statistique.

Et les autres alternatives actuellement mises en œuvre devraient définitivement être supprimées.

@ ricardoV94 est-ce que vous dites cela parce qu'aucune des alternatives n'est référencée dans Wikipedia ni dans l'article de Hyndman et Fan?

Oui, afaik ils ne sont implémentés dans aucun autre package.

Je ne vois pas pourquoi quelqu'un voudrait utiliser ces méthodes, et leurs noms sont
également potentiellement trompeur.

Albert Thomas [email protected] escreveu no dia quarta, 2/01/2019
à (s) 14:18:

Et les autres alternatives actuellement mises en œuvre devraient certainement être
supprimé.

@ ricardoV94 https://github.com/ricardoV94 dites-vous cela parce que
aucune des alternatives n'est référencée dans Wikipédia ni dans Hyndman et
Le papier de Fan?

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/numpy/numpy/issues/10736#issuecomment-450861068 , ou muet
le fil
https://github.com/notifications/unsubscribe-auth/AbpAmfUoJNk3YHOSHNeVN03Va5wtvkHQks5u_LGugaJpZM4SnVpE
.

Merci! Pourquoi ne pas ouvrir un PR pour ajouter l'inverse de la distribution cumulative comme méthode disponible dans np.percentile? tout en gardant ce problème ouvert si nous voulons continuer à discuter des alternatives (sauf la valeur par défaut actuelle qui devrait rester la valeur par défaut). Comment la dépréciation est-elle gérée dans numpy?

Quelques informations supplémentaires ici - Python 3.8 a ajouté statistics.quantiles - nous devrions envisager d'ajouter un mode équivalent à np.quantile

La voie à suivre ici est probablement d'ajouter un method kwarg reflétant le statistics un, et possible d'ajouter 0-2 de plus (dans ce cas, il serait bon d'envoyer un ping aux auteurs originaux sur python) .

Je ne sais pas si les valeurs par défaut correspondent aux nôtres et aux leurs, ce qui serait dommage si elles ne le font pas, mais cela semble toujours être la meilleure idée (et à peu près ce que nous avions en tête de toute façon). 0-2 nouvelles "méthodes" seraient également acceptables. Dans ce cas, il serait bon d'envoyer un ping aux statistiques python sur les noms réels ...

Les RP sont les bienvenus, j'aimerais que cela aille de l'avant, mais je ne le ferai pas dans un avenir immédiat.

@ eric-wieser Je note que vous avez quelques PR connexes en suspens, est-ce que l'un d'entre eux s'occupe de cela?

Je vais pousser cela à 1.19 donc ce n'est pas un bloqueur. Mais cela ne veut pas dire qu'il ne peut pas être corrigé pour 1.18 :)

@charris : Quels PR avez-vous en tête?

Je ne pense pas qu'il y en ait encore dans ce sens, malheureusement.

Cette page vous a été utile?
0 / 5 - 0 notes