Numpy: Reestructurar los métodos de percentiles

Creado en 12 mar. 2018  ·  53Comentarios  ·  Fuente: numpy/numpy

Como se ejemplifica en la página de Wikipedia: https://en.wikipedia.org/wiki/Percentile#The_nearest -rank_method

00 - Bug 01 - Enhancement high

Todos 53 comentarios

¿Creo que esto ya existe? Usando el ejemplo de wikipedia:

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

No es asi. Mira el ejemplo 2 en la página de wikipedia:

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

Cuando debería ser [7,8,15,20]

De manera similar falla en el tercer ejemplo.

¿Más cercano suena mucho a "más cercano"? Aunque siempre hay otro punto sobre cómo funcionan exactamente los límites.
EDITAR: Es decir, ¿dónde se considera exactamente que están 0 y 100, en el punto de datos o antes del punto de datos? (eso es IIRC, de todos modos hay muchas complejidades molestas aquí)

no quiero leerlo, creo que la diferencia podría ser el parámetro C más abajo, así que si alguien que sabe esto quiere agregar esto ...

Francamente, creo que agregar el parámetro C probablemente sería realmente bueno. Pero en general, una mejor documentación estaría bien, y se necesita alguien que realmente sepa esto ...

No sé si esto tiene algo que ver con el parámetro C, aunque estoy de acuerdo en que la opción de elegirlo podría ser deseable.

Encontré otro hilo que, por cierto, trajo a colación este problema (diciembre de 2016). Parece que el algoritmo que estoy buscando (y que wikipedia llama rango más cercano) se menciona en este artículo comúnmente citado por Hyndman-Fan (H&F) como la definición de percentil más antigua y estudiada (fue la que aprendí en Curso de estadísticas). Es una función discontinua, así que creo que el parámetro C no se aplica aquí (puedo estar equivocado).

Así es como se vería en comparación con las otras opciones proporcionadas por numpy que intuitivamente parecen calcular algo similar (es decir, 'más bajo', 'más cercano'):

percentiles

Para mí, se ve exactamente como el parámetro C a primera vista, la curva más cercana está más estirada que la curva H&F, lo que se espera ya que numpy usa 1 y aparentemente H&F usa 0.

Si quieres una prueba. Repita todo con los mismos valores repetidos 1000 veces, supongo que convergerán.
EDITAR: O tal vez no, no tengo la paciencia o el tiempo para pensarlo realmente. Pero sigo pensando que es el parámetro C que menciona wikipedia, así que pruébame que estoy equivocado :)

Un gráfico como ese sería una gran adición a los documentos de percentiles

editar: preferiblemente uno que muestre la apertura / cierre de las discontinuidades

Nota para los lectores: Para mantener este hilo manejable, he marcado todas las discusiones a continuación sobre cómo agregar este gráfico a los documentos como "resuelto". El gráfico está ahora en la parte inferior de https://numpy.org/devdocs/reference/generated/numpy.percentile.html.

@ eric-wieser No me importa hacer ese gráfico. Volveré con algo más tarde hoy, ¿debería publicarlo aquí?

@seberg Seré honesto aquí, no sé cómo se calcula la interpolación en función del parámetro C. Lo que me hace pensar que no está relacionado es que el parámetro C solo se discute en la sección de interpolación lineal (Wikipedia), y tanto el artículo de Wikipedia como Hyndmand & Fan discuten el algoritmo que solicité en secciones separadas de las de interpolación.

No sé si hay algún parámetro de interpolación que siempre dé los mismos resultados que el algoritmo que me interesa.

Incluso si los hay, ¿debería ser esta la forma de llegar a él? Cambiar un parámetro 'extraño' para obtener la definición más común de percentil no parece la mejor manera de implementarlo en mi humilde opinión.

@ ricardoV94 , tal vez, pero no puedes simplemente cambiar los valores predeterminados, sin importar cuán malos sean. Podríamos exponer algo como method = "H&K" para anular ambos parámetros a la vez.

Los parámetros C es donde define 0% y 100% con respecto a los puntos de datos (en el punto de datos o no, etc.). Como parámetro C en wikipedia, puede que sea solo para interpolación, pero el mismo problema causa la diferencia aquí, estoy seguro. C es dudoso, por supuesto, un nombre propio podría ser algo como range = 'min-max' o range = 'extrapolated' o probablemente algo completamente diferente. Como dije, rehaga los gráficos con muchos puntos de datos (posiblemente con un ruido mínimo) y creo que los verá converger, ya que la definición del rango se vuelve menos obvia.

@seberg Estoy bien con method = "H&K" o tal vez method = "classic". Interpolation = "none" también podría tener sentido.

No estoy seguro de cuál es el mecanismo para incluir imágenes en los documentos, o si hay algún precedente para hacerlo.

Sé que puede ejecutar código matplotlib dentro de los documentos, que es como lo hacemos en otros lugares, lo que también garantiza que permanezca sincronizado con la realidad.

Bien, pensaré en la mejor imagen de código en ese caso.

La parte más problemática son los marcadores abiertos y cerrados de discontinuidad, ya que matplotlib no tiene una función incorporada para eso (afaik). Codificarlos de forma rígida tendría poco sentido en ese caso.

Tal vez omita esos por ahora. Sería bueno si matplotlib tuviera algún soporte automático para esos.

Con suerte, alguien tendrá una sugerencia mejor, que aún sea elegante con respecto a la discontinuidad.

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

Creo que interpolation = 'linear' debería ser una línea regular no escalonada, pero por lo demás se ve bien. ¿Puedes hacer un PR agregando eso a los documentos?

De hecho, step está causando artefactos engañosos en general, por lo que me inclinaría a evitarlo. linspace(0, 100, 60) también produciría coordenadas intermedias más precisas

No tengo idea de cómo hacer relaciones públicas.

Siéntase libre de hacerlo con su cuenta, agregando o discutiendo los cambios sugeridos.

Creo que puedes cambiar C con algo como esto (pruébalo en algo). Llame a la función en sus percentiles, luego conéctela a la versión numpy (que usa C = 1, que es una operación no operativa excepto la corrección de percentiles fuera de límite en este momento):

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

Y listo, con "más cercano" obtendrás tu "H&F" y con lineal obtendrás la trama de Wikipedia. (a la espera de que haya algo mal, pero estoy bastante seguro de que lo hice bien).

Como dije, la diferencia es donde colocas los puntos de datos de 0 a 100 (uniformemente) con respecto al último punto. Para C = 1, pones min (datos) en el percentil 0, etc. No tengo ni idea de "qué tiene más sentido", probablemente importe un poco de la vista general. El nombre inclusivo para 1 y exclusivo para 0 tiene un poco de sentido, supongo (cuando piensas en el rango total de percentiles, ya que exclusivo, el rango posible está fuera del rango de datos). Sin embargo, C = 1/2 también es exclusivo en ese sentido.

Yo estaría a favor de agregar el parámetro C, pero me gustaría que alguien inventara un nombre descriptivo si es posible. Tampoco me importaría algo como un "método" o algo así para hacer obvios los mejores valores predeterminados (combinación de interpolación + C). O, básicamente, decidimos que la mayoría de las combinaciones nunca se usan y no son útiles, entonces está bien ...

Al final, mi problema es: quiero que un estadístico me diga qué métodos tienen consenso (R tiene algunas cosas, pero la última vez que alguien vino por aquí fue solo una copia pasada de R doc o similar sin establecerlo en un contexto numpy en todo, no hace falta decirlo, fue inútil para una audiencia general, citar artículos habría sido más útil).

No quiero leer ese artículo de H&F (honestamente, tampoco se ve muy hábil de leer), pero creo que también podría verlo desde un punto de vista de apoyo. La numerosa versión "más cercana" (o cualquier otra) no tiene soporte idéntico (en los percentiles) para cada punto de datos, H&F tiene el mismo soporte para "más cercano" y tal vez para el punto medio sería C = 1/2, no estoy seguro.
Sigo repitiéndome, no sé si tal argumento de apoyo (contra C = 1, como lo usa Numpy), es en realidad una razón real.

EDITAR: el punto medio tiene el mismo soporte (para el área entre los puntos de datos, no para el punto en sí) en número, así que con "C = 1"

@seberg No parece funcionar conmigo. ¿Puedes publicar tu código mostrando que funciona?

Bueno, me equivoqué en el letrero, en ese código de ahí arriba, por lo que era opuesto (C = 0 a no-op not 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 Cerca, pero todavía no. Para a = [0,1,2,3] y percentiles = [25, 50, 75, 100] , np.percentile (a, scale_percentiles(percentiles, len(a), C=0), interpolation='nearest) devuelve [0, 2, 3, 3] , cuando debería devolver [0,1,2,3] .

Tuve que hacer la lista de percentiles dtype=np.float o su función daría un error, pero no creo que ese sea el problema.

La función del método clásico es simple:
Percentil / 100 * N -> Si es un número entero el índice, si no, use el techo como índice.

A pesar de eso, el argumento C parece estar funcionando como se esperaba, por lo que podría implementarse si la gente quiere usarlo para la interpolación. Todavía me gustaría un método = 'clásico' o interpolación = 'ninguno' que funcione como el de wikipedia.

Para la depuración, esta es mi desagradable implementación no numpy del método clásico:

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)]

y uno más numpythonic:

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

Esas diferencias suenan como problemas de redondeo / punto flotante (que usted
parece consciente), y tal vez mi conjetura con C = 0 estaba equivocada y quieres
C = 0,5.
Mi punto era decir de dónde proviene la diferencia (el "parámetro C"
En mi opinión, aunque probablemente haya buenas razones para que no te gusten muchos
combinaciones). No fue para darle / implementar una solución.

En cuanto al método "clásico", francamente no me importa mucho lo
supuestamente es. Por lo que sé, clásico significa "bastantes
la gente lo usa ".

En cuanto a la solución, mi primera impresión es que "clásico" o lo que sea
name, simplemente agrega otra opción confusa con un nombre poco claro. espero
que esta discusión podría ir en la dirección de hacer que todos
Buenas opciones (comunes) disponibles para los usuarios de forma limpia y transparente.
camino. Mejor de una manera que la gente realmente pueda entender.

Podemos agregar un método más, pero, francamente, solo me gusta la mitad. Cuando nosotros
La última vez que agregué más métodos (no recuerdo qué cambió exactamente)
ya retrasado y esperaba que alguien saltara y descubriera
lo que deberíamos tener. No hace falta decir que nunca sucedió realmente. Y ahora
Estoy tratando de señalar las diferencias y tratar de ver cómo encajan
con lo que tenemos actualmente.

Entonces, mi impresión es (con posibles problemas con el redondeo y
coincidencias de percentiles) tenemos (probablemente demasiado) muchas opciones de "interpolación"
y requeriría el "parámetro C" o lo que quieras llamarlo
ser capaz de hacer casi cualquier cosa.
Y sería muy feliz si alguien pudiera decirme cómo todos
"Métodos" (comunes) que se encuentran en esas categorías, parece que
más de C = 0,0.5,1 existen incluso, y tal vez algunos incluso fuera de esos
opciones ....

Tal vez voy por el carril equivocado, pero agrego "Método1" con un
nombre poco claro que realmente no le dice a nadie en qué se diferencia del
otros métodos no me parecen útiles (excepto para alguien que
da la casualidad de que ya conoce el nombre "Method1" y lo está buscando. Y
no digas que el "clásico" es el obvio, hay
demasiada variación en las implementaciones.

Otra forma podría ser la obsoleta "interpolación", pero tener una lista
de métodos también es mucho menos agradable que insinuar "interpolación lineal"
decir que no es un comportamiento de pasos, etc .... Y si vamos por ese camino,
Todavía quiero una visión general razonable.

No tiene que hacerlo, pero si queremos agregar un nuevo método, necesitamos un
¡Manera de agregarlo que no confunda aún más a todos y es claro!

Déjame resumirlo entonces:

1) En este momento, numpy ofrece solo un método útil: interpolación = 'lineal', y los otros son solo pequeñas variaciones que no parecen ser utilizadas por nadie. Otros paquetes tienen muchas opciones más relevantes.

2) Sumar los otros valores para C = 0 o C = 0.5, tiene sentido para mí. Todos los métodos de interpolación pueden funcionar en combinación con ellos, aunque de nuevo probablemente nunca se utilizarán.

3) Si uno de los combos entre los métodos de interpolación y el argumento C logra replicar el método clásico (la referencia, wikipedia y mi experiencia personal están de acuerdo en que es el método más comúnmente enseñado), entonces estoy contento con él. Se puede afirmar en los documentos que dicho combo produce el método clásico de no interpolación. No estoy seguro de si se debe solo a problemas de precisión del flotador, ¡pero agradezco su esfuerzo por abordarlo de una manera más integrada!

4) Si ninguno de los combos logra el mismo resultado, creo que tendría sentido un método diferente. Posiblemente llamado interpolación = 'ninguno' sería menos confuso.

En resumen: las opciones actuales de numpy.percentile parecen bastante confusas y limitadas. El documento mencionado anteriormente ofrece una buena descripción general de otros métodos útiles. Junto con la página de wikipedia, podrían funcionar como un punto de partida para el diseño de un conjunto de opciones más exhaustivo y útil para numpy.percentile. Con suerte, a alguien le gustaría trabajar en esta tarea.

¿Tiene sentido el "más cercano" actual en algunos o en algunos casos? Si el método de espaciado ("C") o lo que sea hace una gran diferencia para la interpolación lineal / cosas fraccionarias, tal vez me sorprenda que nadie lo haya hecho para aproximaciones no fraccionales. ¿Es el soporte constante tan importante, y hay una razón para descartar el argumento inverso CDF para los métodos de interpolación?

Los combos son inútiles a menos que sean comprensibles y los de uso común sean fáciles de encontrar, así que lo dudo. Para la interpolación parecen existir muchas opciones (por ejemplo, http://mathworld.wolfram.com/Quantile.html Q4 a Q9, creo que la documentación de R es prácticamente idéntica, pero creo que es probable que no esté completa, por ejemplo, matlab ...) No tengo ni idea de si en realidad todos tienen sentido;).

La cuestión es que la "interpolación" apunta a qué hacer entre puntos exactamente definidos, pero hay muchas (curiosamente muchas) formas de colocar esos puntos al menos cuando se usa la "interpolación lineal", por lo que parece un mal enfoque agregarle. Quería un "rango más cercano" que suene mucho (y en espíritu) interpolación = "más cercano", pero la elección de la "posición de trazado" exacta parece "no estándar", por lo que será imposible de adivinar y, por lo tanto, una mala elección.

Entonces incluso preferiría desaprobar agresivamente todo (excepto probablemente lo lineal).

Pero, si lo desaprobamos, quiero hacerlo bien al 100%, y eso podría necesitar un poco más de claridad en cuanto a lo que existe, lo que debería existir y lo que definitivamente no debería existir.

estoy totalmente de acuerdo contigo

@ ricardoV94 : ¿tiene alguna opinión sobre las definiciones de linear para el caso de cuantiles ponderados propuesto en # 9211? Hay algunos gráficos con el mismo estilo.

Tal vez @ ricardoV94 pueda comentarlo (eso sería genial), pero creo que el tema es bastante ortogonal. Las ponderaciones probablemente sean simplemente ponderaciones de tipo frecuencia, asumiendo que no hay otras ponderaciones razonablemente definidas para el percentil (no veo cómo), no debería haber ninguna ambigüedad al implementarlas, pero no lo sé con certeza.

También puede intentar hacer ping a josef-pkt en ese PR y esperar que tenga un comentario rápido si cree que es una buena idea / correcta.

Si alguien quiere tomarlo desde aquí, escribí una función no optimizada que calcula el
9 métodos de estimación de percentiles / cuantiles descritos por Hyndman y Fan (1996) y también utilizados en R.

El método 1 corresponde al 'método clásico de rango más cercano' como se describe en Wikipedia . El método 7 es equivalente a la implementación actual de Numpy (interpolación = 'lineal'). Los métodos restantes de interpolación de Numpy no están incluidos (y no parecen ser útiles de todos modos).

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_]

Los métodos continuos también se pueden implementar de manera más eficiente de esta manera.

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)

¿Alguien quiere sacarlo de aquí? No estoy calificado para hacerlo.

Como se mencionó en la publicación anterior, parece que la implementación predeterminada actual de cuantiles de numpy coincide con la 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. ])

que por supuesto no reproducen los ejemplos dados en Wikipedia:
https://en.wikipedia.org/wiki/Percentile

De hecho, si va a la página de ayuda de R para cuantiles https://www.rdocumentation.org/packages/stats/versions/3.5.0/topics/quantile
vería que el método predeterminado de R (Tipo 7) establece las condiciones de límite idénticas a cómo np.quantile establece: p_k = (k-1) / (n-1) , donde n es el tamaño de la muestra, y k = 1 denota el más pequeño valor, mientras que k = n el más grande. Eso significa que el valor más pequeño en la matriz ordenada se fija en el cuantil = 0, y el más grande se fija en el cuantil = 1.

También como se mencionó en la publicación anterior, podría reproducir los 3 ejemplos en Wikipedia con Tipo 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 

Eso plantea algunas preguntas interesantes:

1.) ¿Debería el valor predeterminado de np.quantile rastrear el valor predeterminado de R.quantile?
2.) ¿Debería np.quantile cambiar al algoritmo de Tipo 1?

Dado que incluso la propia Wikipedia está de acuerdo en que no existe una definición estándar de percentil, creo que mientras el algoritmo sea sólido y el usuario sepa cómo funciona, ni (1) ni (2) importan demasiado. Estoy más a favor de (1) porque Python y R son dos de las plataformas de análisis de datos más populares que existen, y sería bueno si pudieran examinarse entre sí. Dado eso, creo que (2) es innecesario.

Sí, tanto R como Numpy utilizan el método 7 de forma predeterminada y debería mantenerse así. La pregunta es sobre agregar los otros métodos o no.

Si alguien está interesado, presento un módulo independiente con los métodos del percentil 9, aquí . Siéntete libre de usarlo o adaptarte a Numpy si sabes cómo.

Gracias @ ricardoV94 .

Entonces, solo por diversión, hice una encuesta en el trabajo sobre los usuarios de R. De las 20 personas que respondieron, 20 usan solo el método predeterminado en quantile . Van desde estudiantes de maestría en salud pública hasta investigadores de doctorado en estadística.

Personalmente, no estoy seguro de si vale la pena el esfuerzo de numpy para admitir 9 formas diferentes de calcular cuantiles. Creo que la mayoría de los usuarios usarán el predeterminado.

Por lo que vale, existe la función scipy.stats.mstats.mquantiles que admite 6 de los 9 métodos (los continuos) y el documento establece de manera muy explícita los enlaces con la implementación de R.

@albertcthomas ah, es bueno saberlo. Aunque, creo que idealmente esconderíamos un poco esta complejidad en numpy. Y sobre todo necesitamos arreglar las versiones no contiguas IIRC. Porque esos básicamente no dan los métodos más comunes.

Sí, de hecho, es posible que numpy no tenga que admitir necesariamente estos métodos si se implementan en el módulo de estadísticas de scipy.

Personalmente, yo estaría a favor de tener un método que calcule el cuantil a partir del inverso generalizado de la función de distribución acumulativa. El hecho de que dicho método no esté disponible me lleva a este problema :).

@albertcthomas si tiene alguna

Lo más importante es que necesitamos algunos buenos valores predeterminados. Y eso probablemente significa implementar 2-3 métodos (renovando por completo los no contiguos). Estoy de acuerdo con apoyar cosas más o más complejas, pero me encantaría que pudiéramos decidirnos por algunas "típicas / buenas".

Diría que el método lineal (valor predeterminado actual) y la inversa de la función de distribución acumulativa (que estaba buscando cuando creé este problema, así como @albertcthomas si entiendo correctamente) serían suficientes. Básicamente, le permite a uno elegir si quiere interpolación o no.

Y las otras alternativas actualmente implementadas definitivamente deberían eliminarse.

Definitivamente debe agregarse la inversa de la función de distribución acumulativa. Es uno de los estimadores más populares de un cuantil de una muestra determinada de observaciones en estadística.

Y las otras alternativas actualmente implementadas definitivamente deberían eliminarse.

@ ricardoV94, ¿estás diciendo esto porque ninguna de las alternativas está referenciada en Wikipedia ni en el artículo de Hyndman y Fan?

Sí, afaik no están implementados en ningún otro paquete.

No veo por qué alguien querría usar esos métodos, y sus nombres son
también potencialmente engañoso.

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

Y las otras alternativas actualmente implementadas definitivamente deberían ser
remoto.

@ ricardoV94 https://github.com/ricardoV94 estás diciendo esto porque
ninguna de las alternativas se hace referencia en Wikipedia ni en Hyndman y
¿Papel de fan?

-
Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/numpy/numpy/issues/10736#issuecomment-450861068 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AbpAmfUoJNk3YHOSHNeVN03Va5wtvkHQks5u_LGugaJpZM4SnVpE
.

¡Gracias! ¿Por qué no abrir un PR para agregar la inversa de la distribución acumulativa como un método disponible en np.percentile? mientras mantenemos este problema abierto si queremos seguir discutiendo sobre alternativas (excepto el valor predeterminado actual que debería permanecer como predeterminado). ¿Cómo se maneja la desaprobación en numpy?

Más información aquí - Python 3.8 agregó statistics.quantiles - deberíamos considerar agregar un modo equivalente a np.quantile

El camino a seguir aquí es probablemente agregar un method kwarg que refleje el statistics uno, y posiblemente agregar 0-2 más (en cuyo caso sería bueno hacer ping a los autores originales en Python) .

No estoy seguro de si los valores predeterminados coinciden entre los nuestros y los de ellos, lo cual sería una pena si no lo hicieran, pero aún así parece la mejor idea (y más o menos lo que teníamos en mente de todos modos). También estaría bien añadir 0-2 nuevos "métodos". En cuyo caso, sería bueno hacer ping a las personas de estadísticas de Python sobre los nombres reales ...

RP muy bienvenidos, me gustaría que esto siguiera adelante, pero no lo haré en el futuro inmediato.

@ eric-wieser Observo que tiene un par de relaciones públicas pendientes pendientes, ¿alguno de ellos se ocupa de esto?

Voy a empujar esto a 1,19 para que no sea un bloqueador. Pero eso no significa que no se pueda arreglar para 1.18 :)

@charris : ¿Qué relaciones

Desafortunadamente, no creo que haya ninguno en esta dirección.

¿Fue útil esta página
0 / 5 - 0 calificaciones