Tout d'abord, quelques initialisations pour python.
%matplotlib inline
from pilouface import PileOuFace, color_sequence, get_longest_sequence, \
str2ndarray, print_square, plot_echantillon_hist, \
generate_animation
import numpy as np
from matplotlib import rcParams
import matplotlib.pyplot as plt
from matplotlib.animation import PillowWriter
import pandas as pd
rcParams['figure.figsize'] = (8., 6.) # Enlarge figure
On s'intéresse à la suite aléatoire de taille $n = 100$ à valeur pile $(P)$ ou face $(F)$. Un tirage donne par exemple la suite suivante :
sample = np.random.choice(a=['P', 'F'], size=100)
color_sequence(sample)
On veut étudier l'occurrence de séquences répétées de pile ou de face.
Dans la suite précédente, on met en gras les plus longues séquences consécutives de pile et de face.
color_sequence(sample, strong=True)
On remarque la plus longue séquence de pile :
long_pile, _ = get_longest_sequence(str2ndarray(sample), select='P')
color_sequence('P'*long_pile, strong=True)
et la plus longue séquence de face :
long_face, _ = get_longest_sequence(str2ndarray(sample), select='F')
color_sequence('F'*long_face, strong=True)
Pour observer la fréquence d'apparition de ces séquences :
On génère 100000 échantillons de taille 100
pof = PileOuFace(nsample=100000)
Pour chaque échantillon, on calcule la longueur de la plus grande séquence consécutive de pile
pof.compute_sequences()
Pour chaque longueur de séquence maximale, on calcule sa fréquence d'apparition
pof.get_histogram1D()
On trace ces fréquences sous la forme d'un histogramme
fig = pof.plot1D()
fig.savefig("hist_pile_face.png")
On s'intéresse maintenant aux couples des plus longues séquences. Pour chaque couple, on calcule sa fréquence d'apparition et on la représente sur une figure à deux dimensions.
fig = pof.plot2D()
fig.savefig("couples.png")
Pour simplifier les formulations, nous remplaçons les piles et les faces par des 0 et des 1.
On arrange les éléments d'un tirage aléatoire de taille $n = 100$, dans un carré de taille $10 \times 10$. Dans ce carré, on compte le nombre de sous-carrés de taille $3 \times 3$ dont la somme des éléments vaut :
Exemple avec :
print_square()
On initialise un tirage de 100000 échantillons.
pof = PileOuFace(100000)
On calcule l'histogramme de la somme des carrés.
pof.compute_3x3_squares()
On trace l'histogramme.
fig = pof.plot_3x3_squares()
fig.savefig("hist_3x3.png")
pof.histo_nsquares
Moyenne
pof.mean
Ecart-type
pof.std
Les données sont contenus dans le fichier cadres.csv
, que l'on lit avec la bibliothèques Pandas :
df = pd.read_csv("cadres.csv")
df = df[:-2].astype('int32') # On convertit en entiers courts
df = df.drop('N°', axis=1) # On enlève la première colonne
df
Pour chaque échantillon, on trace l'histogramme de la fréquence des carrés $3 \times 3$, en superposant l'histogramme calculé sur 100000 échantillons aléatoires.
Les figures générées sont sauvegardées dans les fichiers hist_*.png
.
echantillons = 'A', 'B', 'C', 'D'
for echantillon in echantillons:
s = df[f'ECH {echantillon}']
s.name = f"Echantillon {echantillon}"
fig = plot_echantillon_hist(s, pof, xmax=df.max().max())
fig.savefig(f'hist_{echantillon}.png')
Afin de vérifier que la taille de nos échantillons $(n = 10)$ est suffisante pour que le classement soit significatif, on compare les 100000 tirages aléatoires à un échantillon de 10 tirages aléatoires.
pof10 = PileOuFace(nsample=10)
s10 = pof10.compute_3x3_squares(ret_df=True, verbose=False)
fig = plot_echantillon_hist(s10, pof, xmax=df.max().max())
fig.savefig('hist_10_tirages.png')
Pour mieux se rendre compte, on fait défiler en boucle sur 10 séries de 10 tirages.
anim = generate_animation(nsample=10, nframe=10, large_pof=pof, xmax=df.max().max())
anim.save('animation.gif', PillowWriter(fps=2))
plt.close(anim._fig)
Toujours dans l'objectif de trier les échantillons, on calcule la moyenne et l'écart-type du nombre de carrés $3 \times 3$.
stat = pd.DataFrame(index=echantillons, columns=['mean', 'std'])
for echantillon in echantillons:
s = df[f'ECH {echantillon}']
stat['mean'][echantillon] = s.mean()
stat['std'][echantillon] = s.std()
# On ajoute l'échantillon de taille 100 000
stat = stat.append(pd.Series({'mean': pof.mean, 'std': pof.std}, name=pof.name))
# On ajoute les échantillons de taille 10
for echantillon in range(10):
pof10 = PileOuFace(nsample=10)
pof10.compute_3x3_squares(verbose=False)
s10 = pd.Series({'mean': pof10.mean, 'std': pof10.std}, name=f"10-tirs ({echantillon + 1})")
stat = stat.append(s10)
stat
On représente ces valeurs sous forme d'un nuage de points
fig = plt.figure()
ax = fig.add_subplot(111)
for index, row in stat.iterrows():
if index in echantillons:
marker = {'markersize': 10, 'c': 'r'}
text = {'fontsize': 14, 'color': 'r'}
elif index == '100000 tirages aléatoires':
marker = {'markersize': 10, 'c': 'b'}
text = {'fontsize': 10, 'color': 'b'}
else:
marker = {'markersize': 6}
text = {'fontsize': 10}
ax.plot(row['mean'], row['std'], 'o', **marker)
ax.annotate(index, (row['mean'] + 0.1, row['std']), **text)
ax.set_xlabel('Moyenne')
ax.set_ylabel('Ecart-type')
ax.set_title('Nuage de points des échantillons', fontsize=14);
fig.savefig('scatterplot.png')