2010-03-03 159 views
135

¿Existe una forma conveniente de calcular los percentiles para una secuencia o una matriz numpy unidimensional?¿Cómo calculo los percentiles con python/numpy?

Estoy buscando algo similar a la función percentil de Excel.

Miré en la referencia de estadísticas de NumPy, y no pude encontrar esto. Todo lo que pude encontrar es la mediana (percentil 50), pero no algo más específico.

Respuesta

182

Puede que le interese el paquete SciPy Stats. Tiene the percentile function que busca y muchos otros extras estadísticos.

percentile()is available en numpy también.

import numpy as np 
a = np.array([1,2,3,4,5]) 
p = np.percentile(a, 50) # return 50th percentile, e.g median. 
print p 
3.0 

This ticket me lleva a creer que no se integran en percentile() numpy en cualquier momento pronto.

+2

Gracias! Entonces ahí es donde se ha estado escondiendo. Estaba al tanto de lo simple, pero supongo que asumí cosas simples como que los percentiles se construirían en numpy. – Uri

+14

Por ahora, existe una función de percentil en numpy: http://docs.scipy.org/doc/numpy/reference/generated/numpy.percentile.html – Anaphory

+1

También puede usarlo como una función de agregación, p. para calcular el décimo percentil de cada grupo de una columna de valor por clave, use 'df.groupby ('clave') [['' valor ']]. agg (lambda g: np.percentile (g, 10))' – patricksurry

51

Por cierto, hay a pure-Python implementation of percentile function, en caso de que uno no quiera depender de scipy. La función se copia a continuación:

## {{{ http://code.activestate.com/recipes/511478/ (r1) 
import math 
import functools 

def percentile(N, percent, key=lambda x:x): 
    """ 
    Find the percentile of a list of values. 

    @parameter N - is a list of values. Note N MUST BE already sorted. 
    @parameter percent - a float value from 0.0 to 1.0. 
    @parameter key - optional key function to compute value from each element of N. 

    @return - the percentile of the values 
    """ 
    if not N: 
     return None 
    k = (len(N)-1) * percent 
    f = math.floor(k) 
    c = math.ceil(k) 
    if f == c: 
     return key(N[int(k)]) 
    d0 = key(N[int(f)]) * (c-k) 
    d1 = key(N[int(c)]) * (k-f) 
    return d0+d1 

# median is 50th percentile. 
median = functools.partial(percentile, percent=0.5) 
## end of http://code.activestate.com/recipes/511478/ }}} 
+39

Soy el autor de la receta anterior.Un comentarista en ASPN ha señalado que el código original tiene un error. La fórmula debería ser d0 = key (N [int (f)]) * (c-k); d1 = tecla (N [int (c)]) * (k-f). Se corrigió en ASPN. –

+6

@Wai Yip Tung, solucioné el error en el código –

+1

¿Cómo sabe 'percentile' qué usar para' N'? No está especificado en la llamada a la función. – Richard

7

cheque por módulo scipy.stats:

scipy.stats.scoreatpercentile 
8

La definición de percentil suelo ver espera como resultado el valor de la lista suministrada por debajo del cual P por ciento de los valores se encuentran ... lo que significa que el resultado debe ser del conjunto, no una interpolación entre los elementos del conjunto. Para obtener eso, puedes usar una función más simple.

def percentile(N, P): 
    """ 
    Find the percentile of a list of values 

    @parameter N - A list of values. N must be sorted. 
    @parameter P - A float value from 0.0 to 1.0 

    @return - The percentile of the values. 
    """ 
    n = int(round(P * len(N) + 0.5)) 
    return N[n-1] 

# A = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
# B = (15, 20, 35, 40, 50) 
# 
# print percentile(A, P=0.3) 
# 4 
# print percentile(A, P=0.8) 
# 9 
# print percentile(B, P=0.3) 
# 20 
# print percentile(B, P=0.8) 
# 50 

Si prefiere obtener el valor de la lista suministrada en o por debajo de la cual p por ciento de los valores se encuentran, a continuación, utilizar esta sencilla modificación:

def percentile(N, P): 
    n = int(round(P * len(N) + 0.5)) 
    if n > 1: 
     return N[n-2] 
    else: 
     return N[0] 

O con la simplificación sugerida por @ijustlovemath :

def percentile(N, P): 
    n = max(int(round(P * len(N) + 0.5)), 2) 
    return N[n-2] 
+0

gracias, también espero que el percentil/mediana dé como resultado valores reales de los conjuntos y no las interpolaciones – hansaplast

+0

Hola @mpounsett. Gracias por el código superior. ¿Por qué su percentil siempre devuelve valores enteros? La función percentil debe devolver el percentil N-ésimo de una lista de valores, y este también puede ser un número flotante. Por ejemplo, la función '' 'PERCENTILE''' de Excel devuelve los siguientes percentiles para los ejemplos superiores:' '' 3.7 = percentil (A, P = 0.3) '' ',' '' 0.82 = percentil (A, P = 0.8) '' ',' '' 20 = percentil (B, P = 0.3) '' ',' '' 42 = percentil (B, P = 0.8) '' '. – marco

+0

Se explica en la primera oración. La definición más común de percentil es que es el número en una serie por debajo del cual se encuentran P por ciento de los valores de la serie. Dado que ese es el número de índice de un elemento en una lista, no puede ser un flotante. – mpounsett

5

Aquí se explica cómo hacerlo sin numpy, utilizando solo python para calcular el percentil.

import math 

def percentile(data, percentile): 
    size = len(data) 
    return sorted(data)[int(math.ceil((size * percentile)/100)) - 1] 

p5 = percentile(mylist, 5) 
p25 = percentile(mylist, 25) 
p50 = percentile(mylist, 50) 
p75 = percentile(mylist, 75) 
p95 = percentile(mylist, 95) 
+0

esto solo funcionará si se ordenan los datos – otmezger

+2

Sí, tiene que ordenar la lista antes: mylist = ordenados (...) – Ashkan

23
import numpy as np 
a = [154, 400, 1124, 82, 94, 108] 
print np.percentile(a,95) # gives the 95th percentile 
0

Para calcular el percentil de una serie, ejecute:

from scipy.stats import rankdata 
import numpy as np 

def calc_percentile(a, method='min'): 
    if isinstance(a, list): 
     a = np.asarray(a) 
    return rankdata(a, method=method)/float(len(a)) 

Por ejemplo:

a = range(20) 
print {val: round(percentile, 3) for val, percentile in zip(a, calc_percentile(a))} 
>>> {0: 0.05, 1: 0.1, 2: 0.15, 3: 0.2, 4: 0.25, 5: 0.3, 6: 0.35, 7: 0.4, 8: 0.45, 9: 0.5, 10: 0.55, 11: 0.6, 12: 0.65, 13: 0.7, 14: 0.75, 15: 0.8, 16: 0.85, 17: 0.9, 18: 0.95, 19: 1.0} 
Cuestiones relacionadas