Je voudrais créer un ** histogramme ** avec Python + pandas + matplotlib et superposer la ** courbe de distribution normale ** obtenue en supposant que la population suit une distribution normale.
En outre, ** contrôle de normalité ** par test de Shapiro-Wilk **, estimation d'intervalle pour la moyenne de la population ** en supposant une distribution normale ** (intervalle de confiance à 95%) Je ferai aussi).
Ici, à titre d'exemple, je voudrais créer un histogramme pour le score du test (pour 100 personnes) sur 100 points.
■ Moyenne: 76,1 points, écart-type: 10,3 points --p = 0,77 (p> = 0,05) et on peut dire que la population a une normalité Intervalle de confiance> --95% IC de l'IC moyen de la population = [74,09, 78,19]
Nous avons confirmé l'exécution et le fonctionnement avec Google Colab (Python 3.6.9). C'est presque le même que Jupyter Notebook.
!pip list
matplotlib 3.1.2
numpy 1.17.4
pandas 0.25.3
scipy 1.3.3
Rendre le japonais disponible dans le diagramme de sortie de matplotlib.
!pip install japanize-matplotlib
import japanize_matplotlib
Avec ce qui précède, japanize-matplotlib-1.0.5
sera installé et importé, et même si vous utilisez le japonais pour les étiquettes, etc., les caractères ne seront pas déformés (tofu).
python
%reset -f
import numpy as np
import pandas as pd
import scipy.stats as st
import math
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.transforms as ts
#Générer des données fictives des résultats de test (nombres aléatoires normaux (entier) compris entre 0 et 100)
def getTestData(mu,sig,n) : #Moyenne mu, écart type sig, nombre de nombres aléatoires normaux n
f = lambda x: min(100,max(0,round( np.random.normal(mu,sig),0)))
return (np.frompyfunc(f, 1, 1)(np.zeros(n))).astype(np.float)
df = pd.DataFrame( {'p1':getTestData(75,8,40)} )
#Paramètres de dessin graphique
target = 'p1' #Colonnes à tracer dans le bloc de données
x_min, x_max = 40, 100 #Plage de score à tracer (limites inférieure et supérieure)
j = 5 #Taille de pas de l'axe Y (fréquence)
k = 5 #Largeur de section
bins = 12 #Nombre de sections(x_max-x_min)/k (100-40)/5->12
#Processus de dessin de graphique à partir d'ici
plt.figure(dpi=96)
plt.xlim(x_min,x_max)
d = 0.001
# (1)Traitement statistique
n = len(df[target]) #Taille de l'échantillon
mu = df[target].mean() #moyenne
sig = df[target].std(ddof=0) #Écart type: ddof(Degré de liberté)=0
print(f'■ Moyenne:{mu:.1f}Point, écart type:{sig:.1f}point')
ci1, ci2 = (None, None)
#Test de normalité (niveau de signification 5)%) Et la population moyenne de 95%Intervalle de confiance
_, p = st.shapiro(df[target])
if p >= 0.05 :
print(f' - p={p:.2f} ( p>=0.05 )Et on peut dire que la population a la normalité')
U2 = df[target].var(ddof=1) #Estimation de la variance de la population (variance sans biais)
DF = n-1 #Degré de liberté
SE = math.sqrt(U2/n) #Erreur standard
ci1,ci2 = st.t.interval( alpha=0.95, loc=mu, scale=SE, df=DF )
print(f' -Population moyenne 95%IC de l'intervalle de confiance= [{ci1:.2f} , {ci2:.2f}]')
else:
print(f' ※ p={p:.2f} ( p<0.05 )Et on ne peut pas dire que la population est normale')
# (2)Dessiner un histogramme
hist_data = plt.hist(df[target], bins=bins, color='tab:cyan', range=(x_min, x_max), rwidth=0.9)
plt.gca().set_xticks(np.arange(x_min,x_max-k+d, k))
# (3)Courbe approximative en supposant une distribution normale
sig = df[target].std(ddof=1) #Écart-type impartial: ddof(Degré de liberté)=1
nx = np.linspace(x_min, x_max+d, 150) #150 divisions
ny = st.norm.pdf(nx,mu,sig) * k * len(df[target])
plt.plot( nx , ny, color='tab:blue', linewidth=1.5, linestyle='--')
# (4)Réglage de l'échelle / étiquette de l'axe X
plt.xlabel('Classement des scores de test',fontsize=12)
plt.gca().set_xticks(np.arange(x_min,x_max+d, k))
# (5)Réglage de l'échelle / étiquette de l'axe Y
y_max = max(hist_data[0].max(), st.norm.pdf(mu,mu,sig) * k * len(df[target]))
y_max = int(((y_max//j)+1)*j) #Le plus petit multiple de j supérieur à la fréquence maximale
plt.ylim(0,y_max)
plt.gca().set_yticks( range(0,y_max+1,j) )
plt.ylabel('Nombre de personnes',fontsize=12)
# (6)Sortie texte du score moyen et de l'écart type
tx = 0.03 #Pour le réglage de la position de sortie des caractères
ty = 0.91 #Pour le réglage de la position de sortie des caractères
tt = 0.08 #Pour le réglage de la position de sortie des caractères
tp = dict( horizontalalignment='left',verticalalignment='bottom',
transform=plt.gca().transAxes, fontsize=11 )
plt.text( tx, ty, f'Score moyen{mu:.2f}', **tp)
plt.text( tx, ty-tt, f'écart-type{sig:.2f}', **tp)
plt.vlines( mu, 0, y_max, color='black', linewidth=1 )
Dans le cas d'un histogramme, il peut être difficile de dire si la valeur qui est la limite de la division est comptée dans la fréquence gauche ou droite. Vous en trouverez ci-dessous une version plus simple.
python
%reset -f
import numpy as np
import pandas as pd
import scipy.stats as st
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.transforms as ts
import math
#Générer des données factices de test (0-100)
def getTestData(mu,sig,n) : #Moyenne mu, écart type sig, nombre de nombres aléatoires normaux n
f = lambda x: min(100,max(0,round( np.random.normal(mu,sig),0)))
return (np.frompyfunc(f, 1, 1)(np.zeros(n))).astype(np.float)
df = pd.DataFrame( {'p1':dm} )
#Paramètres de dessin graphique
target = 'p1' #Colonnes à tracer dans le bloc de données
x_min, x_max = 40, 100 #Plage de score à tracer (limites inférieure et supérieure)
j = 5 #Taille de pas de l'axe Y (fréquence)
k = 5 #Largeur de section
bins = 12 #Nombre de sections(x_max-x_min)/k (100-40)/5->12
#Processus de dessin de graphique à partir d'ici
plt.figure(dpi=96)
plt.xlim(x_min-k/2,x_max-k/2)
d = 0.001
# (1)Traitement statistique
n = len(df[target]) #Taille de l'échantillon
mu = df[target].mean() #moyenne
sig = df[target].std(ddof=0) #Écart type: ddof(Degré de liberté)=0
print(f'■ Moyenne:{mu:.1f}Point, écart type:{sig:.1f}point')
ci1, ci2 = (None, None)
#Test de normalité (niveau de signification 5)%) Et la population moyenne de 95%Intervalle de confiance
_, p = st.shapiro(df[target])
if p >= 0.05 :
print(f' - p={p:.2f} ( p>=0.05 )Et on peut dire que la population a la normalité')
U2 = df[target].var(ddof=1) #Estimation de la variance de la population (variance sans biais)
DF = n-1 #Degré de liberté
SE = math.sqrt(U2/n) #Erreur standard
ci1,ci2 = st.t.interval( alpha=0.95, loc=mu, scale=SE, df=DF )
print(f' -Population moyenne 95%IC de l'intervalle de confiance= [{ci1:.2f} , {ci2:.2f}]')
else:
print(f' ※ p={p:.2f} ( p<0.05 )Et on ne peut pas dire que la population est normale')
# (2)Dessiner un histogramme
hist_data = plt.hist(df[target], bins=bins, color='tab:cyan', range=(x_min, x_max), rwidth=0.9, align='left')
plt.gca().set_xticks(np.arange(x_min,x_max-k+d, k))
# (3)Courbe approximative en supposant une distribution normale
sig = df[target].std(ddof=1) #Écart-type impartial: ddof(Degré de liberté)=1
nx = np.linspace(x_min, x_max+d, 150) #150 divisions
ny = st.norm.pdf(nx,mu,sig) * k * len(df[target])
plt.plot( nx - k/2 , ny, color='tab:blue', linewidth=1.5, linestyle='--')
# (4)Réglage de l'échelle / étiquette de l'axe X
plt.xticks(rotation=90)
plt.xlabel('Classement des scores de test',fontsize=12)
tmp = list([ f'${i} \\leq x < {i+k}$' for i in range(x_min,x_max-k+1, k) ])
tmp[-1] = f'${x_max-k} \\leq x \\leq {x_max}$'
plt.gca().set_xticklabels( tmp )
# (5)Réglage de l'échelle / étiquette de l'axe Y
y_max = max(hist_data[0].max(), st.norm.pdf(mu,mu,sig) * k * len(df[target]))
y_max = int(((y_max//j)+1)*j) #Le plus petit multiple de j supérieur à la fréquence maximale
plt.ylim(0,y_max)
plt.gca().set_yticks( range(0,y_max+1,j) )
plt.ylabel('Nombre de personnes',fontsize=12)
Recommended Posts