Comment calculer la probabilité d'une valeur donnée d'une liste d'échantillons à partir d'une distribution en Python?
Je ne suis pas sûr que cela appartienne aux statistiques, mais J'essaie D'utiliser Python pour y arriver. J'ai essentiellement juste une liste d'entiers:
data = [300,244,543,1011,300,125,300 ... ]
Et je voudrais savoir la probabilité d'une valeur particulière en fonction de ces données. J'graphique en histogrammes des données à l'aide de matplotlib et obtenu ces:
Dans le premier graphique, les chiffres représentent le montant de caractères dans une séquence. Dans le deuxième graphique, c'est un temps mesuré en millisecondes. Le minimum est supérieur à zéro, mais il n'y a pas nécessairement de maximum. Les graphiques ont été créés en utilisant des millions d'exemples, mais je ne suis pas sûr que je peux faire d'autres hypothèses sur la distribution. Je veux savoir la probabilité d'une nouvelle valeur étant donné que j'ai quelques millions exemples de valeurs. Dans le premier graphique, j'ai quelques millions de séquences de longueurs différentes. Voudrais savoir la probabilité de 200 longueur, par exemple.
je sais que pour une distribution continue la probabilité de n'importe quel point exact est supposé être zéro, mais étant donné un flux de nouvelles valeurs, je dois être en mesure de dire combien probable chaque valeur est. J'ai regardé à travers certaines des fonctions de densité de probabilité de numpy/scipy, mais je ne suis pas sûr de savoir où choisir ou comment rechercher de nouvelles valeurs Une fois que j'exécute quelque chose comme scipy.statistique.norme.pdf(les données). Il semble que différentes fonctions de densité de probabilité vont s'adapter aux données différemment. Compte tenu de la forme des histogrammes, Je ne sais pas comment décider lequel utiliser.
3 réponses
puisque vous ne semblez pas avoir une distribution spécifique à l'esprit, mais vous pourriez avoir beaucoup d'échantillons de données, je suggère d'utiliser une méthode d'estimation de la densité non paramétrique. Un des types de données que vous décrivez (temps en ms) est clairement continu, et une méthode pour l'estimation non paramétrique d'une fonction de densité de probabilité (PDF) pour les variables aléatoires continues est l'histogramme que vous avez déjà mentionné. Cependant, comme vous le verrez ci-dessous, estimation de la densité du grain (KDE) peut être mieux. Le deuxième type de données que vous décrivez (nombre de caractères dans une séquence) est du genre discret. Ici, l'estimation de la densité du noyau peut également être utile et peut être considérée comme une technique de lissage pour les situations où vous n'avez pas une quantité suffisante d'échantillons pour toutes les valeurs de la variable discrète.
Estimation De La Densité
l'exemple ci-dessous montre comment générer d'abord des échantillons de données à partir d'un mélange de 2 distributions gaussiennes et ensuite appliquer la densité du noyau estimation de trouver la fonction de densité de probabilité:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from sklearn.neighbors import KernelDensity
# Generate random samples from a mixture of 2 Gaussians
# with modes at 5 and 10
data = np.concatenate((5 + np.random.randn(10, 1),
10 + np.random.randn(30, 1)))
# Plot the true distribution
x = np.linspace(0, 16, 1000)[:, np.newaxis]
norm_vals = mlab.normpdf(x, 5, 1) * 0.25 + mlab.normpdf(x, 10, 1) * 0.75
plt.plot(x, norm_vals)
# Plot the data using a normalized histogram
plt.hist(data, 50, normed=True)
# Do kernel density estimation
kd = KernelDensity(kernel='gaussian', bandwidth=0.75).fit(data)
# Plot the estimated densty
kd_vals = np.exp(kd.score_samples(x))
plt.plot(x, kd_vals)
# Show the plots
plt.show()
il en résultera le graphique suivant, où la distribution réelle est montrée en bleu, l'histogramme est montré en vert, et le PDF estimé à L'aide de KDE est montré en rouge:
comme vous pouvez le voir, dans cette situation, le PDF approximé par l'histogramme n'est pas très utile, alors que KDE fournit une bien meilleure estimation. Cependant, un plus grand nombre de données des échantillons et un choix approprié de la taille de la cellule, histogramme pourrait également produire une bonne estimation.
Les paramètres que vous pouvez régler en cas de KDE sont les kernel et bande passante. Vous pouvez penser au noyau comme le bloc de construction pour le PDF estimé, et plusieurs fonctions du noyau sont disponibles dans Scikit apprendre: gaussian, tophat, epanechnikov, exponentielle, linéaire, cosinus. Changer la bande passante vous permet d'ajuster le compromis de biais-variance. Plus la largeur de bande résultera en un biais accru, ce qui est bon si vous avez moins d'échantillons de données. Une plus petite largeur de bande augmentera la variance (moins d'échantillons sont inclus dans l'estimation), mais donnera une meilleure estimation lorsque plus d'échantillons sont disponibles.
Calcul De La Probabilité
pour un PDF, la probabilité est obtenue en calculant l'intégrale sur une gamme de valeurs. Comme vous l'avez remarqué, cela conduira à la probabilité 0 pour une valeur spécifique.
Scikit Apprendre ne semble pas avoir une fonction intégrée pour calculer la probabilité. Cependant, il est facile d'estimer l'intégrale du PDF sur une gamme. Nous pouvons le faire en évaluant le PDF plusieurs fois à l'intérieur de l'intervalle et en additionnant les valeurs obtenues multipliées par la taille de l'étape entre chaque point d'évaluation. Dans l'exemple ci-dessous, N
les échantillons sont obtenus à l'étape step
.
# Get probability for range of values
start = 5 # Start of the range
end = 6 # End of the range
N = 100 # Number of evaluation points
step = (end - start) / (N - 1) # Step size
x = np.linspace(start, end, N)[:, np.newaxis] # Generate values in the range
kd_vals = np.exp(kd.score_samples(x)) # Get PDF values for each x
probability = np.sum(kd_vals * step) # Approximate the integral of the PDF
print(probability)
Veuillez noter que kd.score_samples
génère la log-vraisemblance des échantillons de données. Par conséquent, np.exp
est nécessaire pour obtenir la probabilité.
le même calcul peut être effectué en utilisant les méthodes d'intégration SciPy, ce qui donnera un résultat un peu plus précis:
from scipy.integrate import quad
probability = quad(lambda x: np.exp(kd.score_samples(x)), start, end)[0]
Par exemple, pour une fois, la première méthode a calculé la probabilité que 0.0859024655305
, tandis que la seconde méthode produit 0.0850974209996139
.
OK je propose ceci comme point de départ, mais l'estimation des densités est un sujet très large. Pour votre cas impliquant la quantité de caractères dans une séquence, nous pouvons modéliser cela d'un point de vue frequentiste en utilisant probabilité empirique. Ici, la probabilité est essentiellement une généralisation de la notion de pourcentage. Dans notre modèle, l'exemple de l'espace est discret et est tous les entiers positifs. Eh bien, alors il suffit de compter les occurrences et diviser par le nombre total des événements pour obtenir votre devis pour les probabilités. Partout où nous avons zéro observation, notre estimation pour la probabilité est zéro.
>>> samples = [1,1,2,3,2,2,7,8,3,4,1,1,2,6,5,4,8,9,4,3]
>>> from collections import Counter
>>> counts = Counter(samples)
>>> counts
Counter({1: 4, 2: 4, 3: 3, 4: 3, 8: 2, 5: 1, 6: 1, 7: 1, 9: 1})
>>> total = sum(counts.values())
>>> total
20
>>> probability_mass = {k:v/total for k,v in counts.items()}
>>> probability_mass
{1: 0.2, 2: 0.2, 3: 0.15, 4: 0.15, 5: 0.05, 6: 0.05, 7: 0.05, 8: 0.1, 9: 0.05}
>>> probability_mass.get(2,0)
0.2
>>> probability_mass.get(12,0)
0
maintenant, pour vos données chronologiques, il est plus naturel de modéliser ceci comme une distribution continue. Au lieu d'utiliser une approche paramétrique où vous supposez que vos données ont une certaine distribution et puis ajuster cette distribution à vos données, vous devriez prendre une approche non paramétrique. Une façon simple est d'utiliser un densité du noyau estimation. Vous pouvez simplement penser à cela comme un moyen de lisser un histogramme pour vous donner une fonction de densité de probabilité continue. Plusieurs bibliothèques sont disponibles. Le plus simple pour les données univariées est peut-être celui de scipy:
>>> import scipy.stats
>>> kde = scipy.stats.gaussian_kde(samples)
>>> kde.pdf(2)
array([ 0.15086911])
pour obtenir la probabilité d'une observation dans un certain intervalle:
>>> kde.integrate_box_1d(1,2)
0.13855869478828692
Voici une solution possible. Vous comptez le nombre d'occurrences de chaque valeur dans la liste d'origine. La probabilité future pour une valeur donnée est son taux d'occurrence passé, qui est simplement le nombre d'occurrences passées divisé par la longueur de la liste originale. En Python c'est très simple:
x est la liste des valeurs
from collections import Counter
c = Counter(x)
def probability(a):
# returns the probability of a given number a
return float(c[a]) / len(x)