161 votes

Comment créer un graphique de densité dans matplotlib ?

Dans R, je peux créer la sortie désirée en faisant :

data = c(rep(1.5, 7), rep(2.5, 2), rep(3.5, 8),
         rep(4.5, 3), rep(5.5, 1), rep(6.5, 8))
plot(density(data, bw=0.5))

Density plot in R

En python (avec matplotlib), le plus proche que j'ai obtenu était un simple histogramme :

import matplotlib.pyplot as plt
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
plt.hist(data, bins=6)
plt.show()

Histogram in matplotlib

J'ai aussi essayé le paramètre normed=True mais je n'ai rien trouvé d'autre que d'essayer d'ajuster une gaussienne à l'histogramme.

Mes dernières tentatives étaient autour de scipy.stats y gaussian_kde J'ai suivi des exemples sur le web, mais je n'ai pas réussi jusqu'à présent.

0 votes

Jetez un coup d'œil à seaborn stackoverflow.com/a/32803224/1922302

200voto

Xin Points 3156

Cinq ans plus tard, lorsque je cherche sur Google "comment créer un graphique de densité de noyau en utilisant python", ce fil de discussion apparaît toujours en tête de liste !

Aujourd'hui, un moyen beaucoup plus simple de le faire est d'utiliser seaborn un paquet qui fournit de nombreuses fonctions de traçage pratiques et une bonne gestion des styles.

import numpy as np
import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.set_style('whitegrid')
sns.kdeplot(np.array(data), bw=0.5)

enter image description here

0 votes

Merci beaucoup. J'ai cherché quelque chose comme ça depuis des jours. Pouvez-vous expliquer pourquoi l'image de l'entreprise est si belle ? bw=0.5 est donné ?

5 votes

@SitzBlogz Le bw paramètre signifie largeur de bande. J'essayais de correspondre au paramètre de l'OP (voir son premier exemple de code original). Pour une explication détaillée de ce que bw les contrôles, voir fr.wikipedia.org/wiki/ . En fait, il contrôle la régularité du tracé de la densité. Plus le bw est grand, plus il sera lisse.

0 votes

J'ai une autre question à poser : mes données sont discrètes par nature et j'essaie de tracer le PDF pour cela, après avoir lu la documentation de Scipy, j'ai compris que PMF = PDF ; avez-vous des suggestions sur la façon de le tracer ?

144voto

Justin Peel Points 17348

Sven a montré comment utiliser la classe gaussian_kde de Scipy, mais vous remarquerez qu'il ne ressemble pas tout à fait à ce que vous avez généré avec R. C'est parce que gaussian_kde essaie de déduire la largeur de bande automatiquement. Vous pouvez jouer avec la largeur de bande d'une certaine manière en modifiant la fonction covariance_factor de la gaussian_kde classe. Tout d'abord, voici ce que vous obtenez sans modifier cette fonction :

alt text

Cependant, si j'utilise le code suivant :

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = gaussian_kde(data)
xs = np.linspace(0,8,200)
density.covariance_factor = lambda : .25
density._compute_covariance()
plt.plot(xs,density(xs))
plt.show()

Je reçois

alt text

ce qui est assez proche de ce que vous obtenez de R. Qu'est-ce que j'ai fait ? gaussian_kde utilise une fonction modifiable, covariance_factor pour calculer sa largeur de bande. Avant de modifier la fonction, la valeur renvoyée par covariance_factor pour ces données était d'environ 0,5. En la diminuant, on a réduit la largeur de bande. J'ai dû appeler _compute_covariance après avoir modifié cette fonction pour que tous les facteurs soient calculés correctement. Il ne s'agit pas d'une correspondance exacte avec le paramètre bw de R, mais j'espère que cela vous aidera à aller dans la bonne direction.

7 votes

@Justin Bonne réponse (+1) et je ne veux pas commencer une guerre de mots entre Python et R ou quoi que ce soit, mais j'aime la façon dont R travaille avec les données de façon beaucoup plus succincte que python et d'autres langages. Je suis sûr que python a beaucoup de points positifs par rapport à R (je ne suis pas un utilisateur de Python, donc je suis totalement incompétent pour faire un commentaire) et peut être utilisé pour beaucoup plus de travail que l'analyse de données, mais en tant qu'utilisateur de longue date de R, j'oublie à quel point c'est un langage succinct pour de telles tâches jusqu'à ce que des exemples comme celui-ci apparaissent.

0 votes

Voici une sous-classe de gaussian_kde qui permet de définir la largeur de bande en tant qu'argument.

4 votes

(je me bats toujours avec l'édition des commentaires) Voici une sous-classe de gaussian_kde qui permet de définir la largeur de bande comme argument et plus d'exemples : mail.scipy.org/pipermail/scipy-user/2010-janvier/023877.html et il existe un ticket d'amélioration à l'adresse suivante projets.scipy.org/scipy/ticket/1092 . Remarque : gaussian_kde est conçu pour des données à n dimensions.

71voto

iamaziz Points 49

Option 1 :

Utilice pandas tracé de dataframe (construit sur la base de matplotlib ) :

import pandas as pd
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
pd.DataFrame(data).plot(kind='density') # or pd.Series()

enter image description here

Option 2 :

Utilice distplot de seaborn :

import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.distplot(data, hist=False)

enter image description here

4 votes

Pour ajouter le paramètre de largeur de bande : df.plot.density(bw_method=0.5)

4 votes

@Aziz Pas besoin pandas.DataFrame peut utiliser pandas.Series(data).plot(kind='density') @Anake, il n'est pas nécessaire de définir df.plot.density en tant qu'étape séparée ; vous pouvez simplement passer dans votre fichier df.plot.density. bw_method kwarg en pd.Series(data).plot(kind='density', bw_method=0.5)

52voto

Sven Marnach Points 133943

Essayez peut-être quelque chose comme :

import matplotlib.pyplot as plt
import numpy
from scipy import stats
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = stats.kde.gaussian_kde(data)
x = numpy.arange(0., 8, .1)
plt.plot(x, density(x))
plt.show()

Vous pouvez facilement remplacer gaussian_kde() par une estimation différente de la densité du noyau.

0voto

tetrisforjeff Points 29

Le graphique de densité peut également être créé à l'aide de matplotlib : La fonction plt.hist(data) renvoie les valeurs y et x nécessaires au tracé de densité (voir la documentation https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.hist.html ). En conséquence, le code suivant crée un graphique de densité en utilisant la bibliothèque matplotlib :

import matplotlib.pyplot as plt
dat=[-1,2,1,4,-5,3,6,1,2,1,2,5,6,5,6,2,2,2]
a=plt.hist(dat,density=True)
plt.close()
plt.figure()
plt.plot(a[1][1:],a[0])      

Ce code renvoie le graphique de densité suivant

enter image description here

7 votes

Cette réponse mérite un downvote. Je ne le ferai pas cependant, les downvotes sont diaboliques, mais j'expliquerai plutôt ce qui ne va pas : Les estimations de densité à partir d'un échantillon (ensemble de points de données) impliquent généralement lissage . C'est ce que les R density() ou ce que fait la fonction SciPy gaussian_kde() fait. Le résultat est une approximation de la densité continue dont les points de données proviennent vraisemblablement, et c'est ce que le PO recherchait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X