web-dev-qa-db-fra.com

tracés de distribution cumulative python

Je fais un projet en utilisant python où j'ai deux tableaux de données. Appelons-les pc et pnc. Je dois tracer une distribution cumulative des deux sur le même graphique. Pour pc, il est supposé être un graphique inférieur à, c'est-à-dire à (x, y), y points dans pc doit avoir une valeur inférieure à x. Pour pnc il doit s'agir d'un tracé supérieur à, c'est-à-dire qu'en (x, y), y points dans pnc doivent avoir une valeur supérieure à x.

J'ai essayé d'utiliser la fonction d'histogramme - pyplot.hist. Existe-t-il un moyen meilleur et plus simple de faire ce que je veux? De plus, il doit être tracé sur une échelle logarithmique sur l'axe des x.

20
akhiljain

Tu étais proche. Vous ne devez pas utiliser plt.hist comme numpy.histogram, qui vous donne à la fois les valeurs et les bacs, que vous pouvez tracer facilement le cumulatif:

import numpy as np
import matplotlib.pyplot as plt

# some fake data
data = np.random.randn(1000)
# evaluate the histogram
values, base = np.histogram(data, bins=40)
#evaluate the cumulative
cumulative = np.cumsum(values)
# plot the cumulative function
plt.plot(base[:-1], cumulative, c='blue')
#plot the survival function
plt.plot(base[:-1], len(data)-cumulative, c='green')

plt.show()

enter image description here

33
EnricoGiampieri

L'utilisation d'histogrammes est vraiment inutilement lourde et imprécise (le binning rend les données floues): vous pouvez simplement trier toutes les valeurs x: l'index de chaque valeur est le nombre de valeurs plus petites. Cette solution plus courte et plus simple ressemble à ceci:

import numpy as np
import matplotlib.pyplot as plt

# Some fake data:
data = np.random.randn(1000)

sorted_data = np.sort(data)  # Or data.sort(), if data can be modified

# Cumulative counts:
plt.step(sorted_data, np.arange(sorted_data.size))  # From 0 to the number of data points-1
plt.step(sorted_data[::-1], np.arange(sorted_data.size))  # From the number of data points-1 to 0

plt.show()

De plus, un style de tracé plus approprié est en effet plt.step() au lieu de plt.plot(), car les données sont à des emplacements discrets.

Le résultat est:

enter image description here

Vous pouvez voir que c'est plus irrégulier que la sortie de la réponse d'EnricoGiampieri, mais celui-ci est le véritable histogramme (au lieu d'en être une version approximative et plus floue).

PS : Comme l'a noté SebastianRaschka, le tout dernier point devrait idéalement afficher le nombre total (au lieu du nombre total-1). Cela peut être réalisé avec:

plt.step(np.concatenate([sorted_data, sorted_data[[-1]]]),
         np.arange(sorted_data.size+1))
plt.step(np.concatenate([sorted_data[::-1], sorted_data[[0]]]),
         np.arange(sorted_data.size+1))

Il y a tellement de points dans data que l'effet n'est pas visible sans zoom, mais le tout dernier point du nombre total importe quand les données ne contiennent que quelques points.

22
Eric O Lebigot

Après une discussion concluante avec @EOL, je voulais publier ma solution (en haut à gauche) en utilisant un échantillon gaussien aléatoire comme résumé:

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from math import ceil, floor, sqrt

def pdf(x, mu=0, sigma=1):
    """
    Calculates the normal distribution's probability density 
    function (PDF).  

    """
    term1 = 1.0 / ( sqrt(2*np.pi) * sigma )
    term2 = np.exp( -0.5 * ( (x-mu)/sigma )**2 )
    return term1 * term2


# Drawing sample date poi
##################################################

# Random Gaussian data (mean=0, stdev=5)
data1 = np.random.normal(loc=0, scale=5.0, size=30)
data2 = np.random.normal(loc=2, scale=7.0, size=30)
data1.sort(), data2.sort()

min_val = floor(min(data1+data2))
max_val = ceil(max(data1+data2))

##################################################




fig = plt.gcf()
fig.set_size_inches(12,11)

# Cumulative distributions, stepwise:
plt.subplot(2,2,1)
plt.step(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$')
plt.step(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$') 

plt.title('30 samples from a random Gaussian distribution (cumulative)')
plt.ylabel('Count')
plt.xlabel('X-value')
plt.legend(loc='upper left')
plt.xlim([min_val, max_val])
plt.ylim([0, data1.size+1])
plt.grid()

# Cumulative distributions, smooth:
plt.subplot(2,2,2)

plt.plot(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$')
plt.plot(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$') 

plt.title('30 samples from a random Gaussian (cumulative)')
plt.ylabel('Count')
plt.xlabel('X-value')
plt.legend(loc='upper left')
plt.xlim([min_val, max_val])
plt.ylim([0, data1.size+1])
plt.grid()


# Probability densities of the sample points function
plt.subplot(2,2,3)

pdf1 = pdf(data1, mu=0, sigma=5)
pdf2 = pdf(data2, mu=2, sigma=7)
plt.plot(data1, pdf1, label='$\mu=0, \sigma=5$')
plt.plot(data2, pdf2, label='$\mu=2, \sigma=7$')

plt.title('30 samples from a random Gaussian')
plt.legend(loc='upper left')
plt.xlabel('X-value')
plt.ylabel('probability density')
plt.xlim([min_val, max_val])
plt.grid()


# Probability density function
plt.subplot(2,2,4)

x = np.arange(min_val, max_val, 0.05)

pdf1 = pdf(x, mu=0, sigma=5)
pdf2 = pdf(x, mu=2, sigma=7)
plt.plot(x, pdf1, label='$\mu=0, \sigma=5$')
plt.plot(x, pdf2, label='$\mu=2, \sigma=7$')

plt.title('PDFs of Gaussian distributions')
plt.legend(loc='upper left')
plt.xlabel('X-value')
plt.ylabel('probability density')
plt.xlim([min_val, max_val])
plt.grid()

plt.show()
13
user2489252