L'échantillonnage stratifié est une technique permettant de maintenir une bonne répartition de la population et un bon échantillonnage. En python, il est implémenté dans StratifiedShuffleSplit et train_test_split de Scikit-learn. Il est souvent pris en compte lors de la validation croisée d'un modèle d'apprentissage automatique. Au lieu de simplement l'utiliser comme un outil, j'ai implémenté un exemple de code pour apprendre en python et l'ai comparé à un échantillonnage aléatoire pour approfondir ma compréhension. En conséquence, il a été confirmé que plus le nombre d'échantillons de la source d'échantillonnage était petit, meilleure était la précision de l'échantillonnage par rapport à l'échantillonnage aléatoire. (Bien que ce soit un résultat naturel, j'ai approfondi ma compréhension en le reproduisant de mes propres mains)
En termes simples, il s'agit d'une technique utile pour l'échantillonnage à partir d'une population avec une structure d'échantillonnage biaisée. Divisez la population en petits groupes appelés «couches». A ce moment, la dispersion pour chaque couche doit être aussi petite que possible, et la dispersion entre les couches doit être aussi grande que possible. En d'autres termes, les échantillons avec les mêmes attributs sont regroupés.
Par exemple, supposons que vous ayez 100 cartes avec n'importe quel nombre de 0 à 9. Mélangez ceci.
0 | 1 | 9 | ・ ・ ・ | 5 | 3 | 7 | 1 |
---|---|---|---|---|---|---|---|
Groupez-le par le même numéro. C'est un nombre, vous pouvez donc le trier.
0 | 0 | 0 | ・ ・ ・ | 5 | 5 | 5 | 5 | ・ ・ ・ | 9 | 9 | 9 | 9 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Après avoir regroupé par le même nombre comme celui-ci, échantillonnez dans chaque groupe au même ratio. Par exemple, si le taux d'échantillonnage est de 10%, il y a 10% de chances d'échantillonnage aléatoire de chaque groupe avec les nombres 0-9. S'il y a 10 nombres de 0 à 9, randomisez-les comme suit.
0 | 0 | 0 | ・ ・ ・ | 0 | → Sélectionnez-en un au hasard |
---|---|---|---|---|---|
1 | 1 | 1 | ・ ・ ・ | 1 | → Sélectionnez-en un au hasard |
2 | 2 | 2 | ・ ・ ・ | 2 | → Sélectionnez-en un au hasard |
・ ・ ・ | |||||
9 | 9 | 9 | ・ ・ ・ | 9 | → Sélectionnez-en un au hasard |
Cet échantillonnage stratifié est efficace pour les configurations d'échantillons biaisées.
À titre d'exemple facile à comprendre, disons que sur 20 cartes, 2 sont «0» et les 18 autres sont «1».
0 | 0 | 1 | 1 | ・ ・ ・ | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
Disons que vous sélectionnez au hasard 10 feuilles de l'ensemble. Le taux d'extraction est de 50%. Puisqu'il est aléatoire, il peut arriver que 10 sur 18 "1" soient sélectionnés et que "0" ne soit pas extrait. Dans ce cas, l'échantillon après extraction ne contient aucun "0", donc la distribution ne peut pas être maintenue.
0 | 0 | 1 | 1 | ・ ・ ・ | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
↓ ↓ ↓ ↓ Extrait 10 sur 20
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
→ ** Puisqu'il n'y a pas de "0", c'est clairement différent de la répartition de la population! ** **
Par conséquent, un échantillonnage stratifié est effectué.
Pour l'échantillonnage stratifié, extraire comme suit.
0 | 0 | 1 | 1 | ・ ・ ・ | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
↓ ↓ ↓ ↓ Extrait 10 sur 20
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
→ ** Le rapport de composition de "0" et "1" est le même que la population = la distribution est la même! ** **
Les échantillons ainsi extraits conservent une meilleure répartition de la population que s'ils étaient choisis au hasard dans l'ensemble.
Maintenant que nous avons une vue d'ensemble, nous allons mettre en œuvre un échantillonnage stratifié. La logique de traitement est la suivante.
Vous trouverez ci-dessous le code qui a été échantillonné en fonction de la logique ci-dessus.
import numpy as np
import random
def extract_stratified_sampling_result(ratio, base_samples):
u"""
L'échantillonnage stratifié est effectué à partir d'une population finie en spécifiant le taux d'extraction.
:param ratio:Taux d'extraction 0 à 1.0
:param base_sample:Groupe de sources d'extraction
:return:
"""
#Commencez par en retirer un de chaque groupe de nombres.
#Ensuite, il est sélectionné au hasard dans chaque groupe numérique pour rapprocher le ratio de composition de la population.
#Taux d'extraction X après en avoir extrait un de chaque groupe de nombres(i)Et. i est le numéro du groupe.
#N pour le numéro de chaque groupe de numéros(i)Et.
#Le nombre à extraire est le rapport x N(i)Est.
#J'en ai déjà sorti un, donc ça reste( N(i) - 1 )Taux d'extraction X des pièces(i)Sortez au hasard.
#Par conséquent, lorsqu'il est combiné avec celui déjà retiré, le rapport x N(i)Devenez un individu.
# X(i) x (N(i) - 1) + 1 = ratio x N(i)
# X(i) = (ratio x N(i) - 1 )/(N(i) - 1)Est.
block_count = np.bincount(base_samples)
x = (ratio * block_count - 1) / (block_count - 1)
#Calculez le seuil de nombres aléatoires lors de l'échantillonnage.
#Seuil= 1.0 -Taux d'extraction de chaque groupe
#Extraire lorsque le nombre aléatoire dépasse le seuil.
#Le taux d'extraction d'un groupe est de 0.Si 3, alors 1.0 - 0.3 = 0.7, le nombre aléatoire est 0.S'il est égal ou supérieur à 7, il sera extrait.
#Un tableau x contenant le taux d'extraction pour chaque groupe de nombres,
#Disposer autant que le nombre de chaque nombre.
threshold = np.repeat(1.0 - x, block_count)
#Liste d'index de chaque élément lors du tri de l'ensemble d'origine
#L'extraction d'échantillons dans cet ordre entraînera un tri.
sorted_pos = np.argsort(base_samples)
#Position de départ de chaque groupe de numéros
block_start = np.concatenate(([0], np.cumsum(block_count)[:-1]))
#Lorsque le nombre aléatoire généré dépasse le seuil de seuil, il est extrait.
threshold[block_start] = 0 #Le premier élément de chaque groupe de numéros est toujours extrait
extracted = []
for i in range(len(base_samples)):
each_rand = random.random()
if each_rand > threshold[i]:
pos = sorted_pos[i]
extracted.append(base_samples[pos])
extracted = np.array(extracted, dtype=np.int64)
return extracted
On suppose que l'argument base_samples contient une liste d'entiers. Jetons un coup d'œil à chaque code. Tout d'abord, comprenons la structure du groupe de base_samples dont il est extrait. C'est là qu'intervient np.bincount (). Il agrège le nombre de chaque nombre qui compose la liste.
block_count = np.bincount(base_samples)
Par exemple, si base_samples contient 9 0 et 91 1, block_count renverra le résultat suivant:
[ 9 91]
En d'autres termes block_coount [0] = nombre de nombres 0, block_count [1] = nombre de nombres 1, Voilà pourquoi. Ce block_count correspond au nombre N (i) de chaque couche dans la logique précédente. Ensuite, trouvez le taux d'extraction X (i) pour chaque couche. Le taux d'extraction r correspond à l'argument ratio, donc le code est le suivant.
x = (ratio * block_count - 1) / (block_count - 1)
Puisque block_count est un tableau numpy, le résultat du calcul sera également un tableau numpy. Autrement dit, le contenu de x ressemble à ceci:
x [0] = Taux d'extraction de la couche avec le numéro 0 x [1] = Taux d'extraction de la couche avec le numéro 1
Maintenant que x a été calculé, l'étape suivante consiste à trouver le seuil aléatoire. Si le nombre aléatoire est supérieur ou égal à cette valeur, l'échantillon est prélevé. Donc,
Seuil aléatoire pour chaque couche= 1.0 - X(i)
Ce sera. Par exemple, si le taux d'extraction pour le nombre 0 est de 0,10, le seuil est
1.0 - 0.10 = 0.90
Ce sera.
En d'autres termes, l'échantillon n'est prélevé que lorsque le nombre aléatoire généré (0 à 1,0) est égal ou supérieur à 0,90.
Les seuils aléatoires de chaque couche ainsi obtenus sont agencés de manière répétée autant que le nombre d'échantillons dans chaque couche.
#Un tableau x contenant le taux d'extraction pour chaque groupe de nombres,
#Disposer autant que le nombre de chaque nombre.
threshold = np.repeat(1.0 - x, block_count)
x[0] = 0.20 , block_count[0] = 2 En supposant que x [1] = 0,10, block_count [1] = 18, le seuil de liste des seuils de nombres aléatoires est:
threshold = [ 0.80, 0.80, 0.90, 0.90, 0.90, ... 0.90]
Ensuite, récupérez la liste d'index après avoir trié base_samples.
#Liste d'index de chaque élément lors du tri de l'ensemble d'origine
#L'extraction d'échantillons dans cet ordre entraînera un tri.
sorted_pos = np.argsort(base_samples)
Vous pouvez utiliser une combinaison de threshold, sorted_pos et base_samples pour l'échantillonnage stratifié. Par exemple
--threshold [0]: seuil aléatoire du premier numéro de la couche 0 --sort_pos [0]: Position (= index) où le premier numéro de la couche 0 est stocké sur base_samples
Par conséquent, si le premier nombre aléatoire généré est au seuil [0] ou supérieur, le premier élément de la couche 0 est extrait. En déplaçant la position de balayage du seuil et sorted_pos, un échantillonnage stratifié peut être effectué.
Après cela, nous allons traiter la logique selon laquelle un est toujours retiré de chaque couche.
#Position de départ de chaque groupe de numéros
block_start = np.concatenate(([0], np.cumsum(block_count)[:-1]))
#Lorsque le nombre aléatoire généré dépasse le seuil de seuil, il est extrait.
threshold[block_start] = 0 #Le premier élément de chaque groupe de numéros est toujours extrait
block_start contient la position du premier élément de chaque couche. Par exemple, s'il y a 10 0 et 90 1, alors:
block_start = [0,10]
La couche avec le numéro 0 commence à partir du block_start [0] th La couche avec le numéro 1 signifie qu'elle commence à partir de la couche block_start [1] ème.
Utilisez ce block_start pour définir le seuil de nombre aléatoire du premier élément de chaque couche sur 0. Un seuil de nombre aléatoire de 0 signifie qu'il sera toujours extrait.
Et puisque le seuil de nombre aléatoire après le début de chaque couche est (1-X (i)), il sera extrait de manière aléatoire en fonction du taux d'extraction calculé.
L'entrée est susceptible d'être longue, je vais donc conclure ici.
L'entrée suivante présente un exemple de code qui compare les performances de l'échantillonnage aléatoire simple à l'échantillonnage stratifié.
Recommended Posts