[Implémentation pour l'apprentissage] Implémentation de l'échantillonnage stratifié en Python (1)

Résumé de l'entrée

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)

Échantillonnage stratifié

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.

Extraction d'une composition d'échantillon biaisée

À 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

(1) Lors de l'échantillonnage aléatoire de l'ensemble

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é.

(2) Dans le cas de l'échantillonnage stratifié

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.

Mettre en œuvre un échantillonnage stratifié

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

[Implémentation pour l'apprentissage] Implémentation de l'échantillonnage stratifié en Python (1)
Mettre en œuvre l'apprentissage de l'empilement en Python [Kaggle]
Implémentation RNN en python
Implémentation ValueObject en Python
Mettre en œuvre des recommandations en Python
Implémenter XENO avec python
Implémenter sum en Python
Implémenter Traceroute dans Python 3
Implémentation SVM en python
Premier apprentissage profond en C # -Imitation de l'implémentation en Python-
Créez un environnement interactif pour l'apprentissage automatique avec Python
Flux d'apprentissage pour les débutants en Python
Plan d'apprentissage Python pour l'apprentissage de l'IA
Implémenter Naive Bayes dans Python 3.3
Implémenter d'anciens chiffrements en python
Techniques de tri en Python
Implémenter Redis Mutex en Python
Implémenter l'extension en Python
Mettre en œuvre un RPC rapide en Python
La recommandation de Checkio pour apprendre Python
Implémenter l'algorithme de Dijkstra en python
Implémenter le bot de discussion Slack en Python
Implémentation du tri rapide en Python
À propos de "for _ in range ():" de python
Comment implémenter Python EXE pour Windows avec le conteneur Docker
Implémenter la fonction power.prop.test de R en python
Rechercher des commandes externes avec python
Algorithme de tri et implémentation en Python
Implémentation de l'estimation des paramètres HMM en python
Implémentation de distribution normale mixte en python
Matériel pédagogique Web pour apprendre Python
Implémenter le modèle Singleton en Python
Implémentation du jeu de vie en Python
<Pour les débutants> bibliothèque python <Pour l'apprentissage automatique>
Python: prétraitement dans l'apprentissage automatique: présentation
Implémentation des règles d'apprentissage Perceptron en Python
Implémentez rapidement l'API REST en Python
Implémentation du tri original en Python
Exécutez unittest en Python (pour les débutants)
Historique d'apprentissage pour participer au développement d'applications d'équipe avec Python ~ Tutoriel Django 5 ~
Historique d'apprentissage pour participer au développement d'applications d'équipe en Python ~ Page d'index ~
Historique d'apprentissage pour participer au développement d'applications d'équipe avec Python ~ Tutoriel Django 4 ~
Que diriez-vous d'Anaconda pour créer un environnement d'apprentissage automatique avec Python?
Historique d'apprentissage pour participer au développement d'applications d'équipe avec Python ~ Tutoriel Django 6 ~
J'ai essayé d'implémenter PLSA en Python
Implémenter __eq__ etc. de manière générique dans la classe Python
J'ai essayé d'implémenter la permutation en Python
Amplifiez les images pour l'apprentissage automatique avec Python
Note de nfc.ContactlessFrontend () de nfcpy de python
Inject est recommandé pour DDD en Python
Module d'implémentation de file d'attente et Python "deque"
Implémenter le filtre FIR en langage Python et C
Conseils pour gérer les binaires en Python
[python] Techniques souvent utilisées dans l'apprentissage automatique
Mettre en œuvre collectivement des tests d'hypothèses statistiques en Python
Pourquoi Python est choisi pour l'apprentissage automatique
J'ai essayé d'implémenter PLSA dans Python 2
Résumé de diverses instructions for en Python