Sous-sélectionnez au hasard dans des groupes et devenez méchantSalut,
J'ai un ensemble de données d'environ 2000 individus stratifiés en 3 catégories (sexe/âge/ethnie). Je veux obtenir des valeurs "regroupées" pour ces individus en prenant ~ 8 individus de chaque sexe/âge/ethnie et en trouvant la moyenne. Une mise en garde est qu'il y a plus d'individus dans certaines catégories que dans les autres. Vous trouverez ci-joint une ventilation de toutes les personnes que j'ai reçues et de leur regroupement. Par exemple, la catégorie 1-1-1 compte 120 individus, je pourrais donc créer 8*15 groupes d'individus aléatoires à partir de ceux-ci. Et si j'ai un nombre qui n'est pas un multiple de 8 ?
Comment puis-je faire tout cela en une seule étape ? Au final, nous aurions environ 200 piscines.

ScriptRe : Sous-sélectionner au hasard dans des groupes et devenir méchantJe ne suis pas totalement sûr d'avoir créé un script qui fait ce que vous voulez, mais cela peut vous donner un bon début.Voici ce que ça fait
- Il trouve le groupe de sexe/âge/ethnie qui a la plus petite population.Ce groupe sera le limiteur du nombre de pools pouvant être créés car aucune ligne ne peut apparaître dans plus d'un pool.
- Il essaie ensuite de trouver la taille du pool qui a réduit le nombre de lignes non incluses pour ce sous-groupe.Pour ce faire, il augmente la taille du groupe de 8 à 21 et trouve le plus petit reste (gaspillage).
- Il crée ensuite une table de travail à partir de la table d'origine.
- Il boucle à travers la table de travail,
- Crée un échantillon aléatoire stratifié
- Ajoute le nouvel échantillon à la table de données finale du pool
- Supprime de la table de données de travail les lignes qui ont été sélectionnées pour la dernière table de données aléatoires de sous-ensemble.
- Se répète autant de fois que possible pour obtenir autant d'enregistrements de sous-groupes les plus petits que possible dans la table de données regroupées finale.
Voici le JSL
Names Default To Here( 1 );
dt = Current Data Table();
// Find smallest subgroup
Summarize( dt, subGroup = by( :age, :gender, :ethnicity ), size = Count( :age ) );
smallest = Min( size );
// Find best group size
minLost = 999999999;
minLostSize = .;
For( i = 8, i <= 21, i++,
If( Mod( smallest, i ) < minLost,
minLost = Mod( smallest, i );
minLostSize = i;
)
);
// Create a working data table
dt2 = dt << subset( selected rows( 0 ), selected columns( 0 ), output table( "Working" ) );
dt2 << New Column( "__row__", set each value( Row() ) );
// Create start of final data table
dt2 << select rows( 1 );
dtPool = dt2 << subset( selected rows( 1 ), selected columns( 0 ), output table( "Final" ) );
dtPool << select rows( 1 );
dtPool << delete rows;
dtPool << New Column( "Pool Number" );
thePoolNumber = 0;
// Create data pools
For( i = 1, i <= Floor( smallest / minLostSize ), i++,
dtTemp = dt2 << Subset(
Sample Size( minLostSize ),
Selected columns only( 0 ),
Stratify( :ethnicity, :Age, :Gender )
);
thePoolNumber = thePoolNumber + 1;
dtTemp << New Column( "Pool Number", set each value( thePoolNumber ) );
dtPool = dtPool << concatenate( dtTemp, append to first table( 1 ) );
// Remove selected rows from working table
dtRemove = dtTemp << subset( selected rows( 0 ), columns( __row__ ) );
dtRemove << New Column( "Delete", character, set each value( "Yes" ) );
dt2 = dt2 << Update( With( dtRemove ), Match Columns( :__row__ = :__row__ ) );
dt2 << select where( :Delete == "Yes" );
dt2 << delete rows;
dt2 << delete columns( :delete );
// Cleanup temporary tables
Close( dtTemp, nosave );
Close( dtRemove, nosave );
);
// Delete the Working data table
Close( dt2, nosave );
J'ai testé cela sur un exemple de table de données que j'ai créé, il peut donc y avoir des problèmes avec votre table réelle.J'ai annoté le code, donc j'espère que vous pourrez apprendre ce que j'ai fait et être en mesure de faire des ajustements pour qu'il fonctionne exactement comme vous en avez besoin.
Re : Sous-sélectionner au hasard dans des groupes et devenir méchant
Salut Jim,
Ce script génère une table vide. Ce que j'espère en tirer, c'est une nouvelle colonne dans la table de données d'origine appelée "Pool Number". Une chose à noter est que l'âge n'est pas une variable numérique continue. C'est une variable catégorielle entre les nombres 1 à 4.
Une fois que tous les échantillons de l'ensemble de données d'origine sont classés dans leur pool, je peux calculer la valeur moyenne du pool en prenant la moyenne des ~ 8 échantillons du pool.
J'ai joint le fichier comme référence.
La table de travail prend tout son sens dans le script ; vous créez une colonne avec chaque ligne ayant une valeur unique. La création de l'ensemble de données final conduit à une feuille de données vierge et je ne vois pas d'où vient cette erreur.
Re : Sous-sélectionner au hasard dans des groupes et devenir méchantMon JSL se termine avec succès si la taille du pool potentiel est réduite à 6. Mon code exige qu'au moins 1 échantillon puisse être extrait de chaque sous-groupe, et depuis le sous-groupe, 1 2 4 n'a que 6 observations (lignes), le code que j'ai écrit pour trouver la meilleure taille d'échantillon a dû être modifié pour avoir une taille de pool de 6.
Mais quoi qu'il en soit, je ne comprends apparemment pas comment vous déterminez vos pools.J'assimilais votre pool à un échantillon aléatoire, avec une taille d'échantillon donnée, pour chaque sous-groupe de données.Cela s'avère être une fausse hypothèse de ma part.
Créez-vous des pools indépendamment pour chaque sous-groupe ?Autrement dit, pour le sous-groupe 1 1 1, il y a 120 lignes de données.Si la taille du pool est de 8, créez-vous 15 pools ?Et puis pour le groupe 1 1 2 qui a 50 rangées, vous créeriez 6 pools, 4 rangées n'étant pas sélectionnées pour un pool ?
C'est comme ça que vous créez vos piscines ?
Voici la répartition de tous les sous-groupes de sexe/ethnie/âge.

Mon JSL actuel ne fait pas ce que vous voulez, veuillez me donner une explication plus précise sur la façon de créer des pools, et je verrai ce qui doit être fait pour mettre en place un script exploitable.
Re : Sous-sélectionner au hasard dans des groupes et devenir méchantSalut Jim,
Les sous-groupes sont créés en ayant ~ 8 personnes dans chaque pool. Vous avez raison concernant 1-1-1. Ce groupe compte 120 individus, donc si nous devions regrouper ces individus au hasard, ils devraient correspondre à exactement 15 pools. Pour le groupe 1-1-2, qui compte 50 rangées, vous créeriez 6 pools de 8 individus et les 4 restants seraient placés dans leur propre pool.
Cela a-t-il du sens? Nous voulons que toutes les lignes de la table de données soient associées à un numéro de pool spécifique.
Re : Sous-sélectionner au hasard dans des groupes et devenir méchantVous trouverez ci-dessous un script qui fonctionne sur votre exemple de table de données, créant tous les pools que vous souhaitez.Veuillez prendre le temps d'étudier le script afin de pouvoir apporter les modifications nécessaires pour l'ajuster à sa forme finale
Names Default To Here( 1 );
dt = Current Data Table();
// Set the size of the pools
poolSize = 8;
thePoolNumber = 0;
// Add row number to data table
dt << New Column( "__Row__", Set Each Value( Row() ) );
// Create a working data table
dt2 = dt << subset(
selected rows( 0 ),
columns( {"Gender", "Ethnicity", "Age", "__Row__"} ),
output table( "Working" )
);
// Create start of final data table
dt2 << select rows( 1 );
dtPool = dt2 << subset( selected rows( 1 ), selected columns( 0 ), output table( "Final" ) );
dtPool << select rows( 1 );
dtPool << delete rows;
dtPool << New Column( "Pool Number" );
thePoolNumber = 0;
// Create data pools
While( N Rows( dt2 ) >= poolSize,
// Draw a new sample
dtTemp = dt2 << Subset(
Sample Size( poolSize ),
Selected columns only( 0 ),
Stratify( :Gender, :Ethnicity, :Age )
);
// Calculate the new pool numbers
dtPoolCount = dtTemp << Summary(
Group( :Gender, :Ethnicity, :Age ),
Freq( "None" ),
Weight( "None" ),
Link to original data table( 0 )
);
// Get the current pool number
maxPool = Col Max( dtPool:Pool Number );
If( Is Missing( maxPool ),
maxPool = 0
);
// Add Pool Number to Pool Count table
dtPoolCount << New Column( "Pool Number", set each value( maxPool + Row() ) );
dtPoolCount << delete columns( N Rows );
// Set the current pool number in the current sample table
dtTemp = dtTemp << Update(
With( dtPoolCount ),
Match Columns( :Gender = :Gender, :Ethnicity = :Ethnicity, :Age = :Age )
);
// Add the sample to the dtPool table
dtPool = dtPool << concatenate( dtTemp, append to first table( 1 ) );
// Delete the selected rows from the working table
dt2 = dt2 << Update( With( dtTemp ), Match Columns( :__row__ = :__row__ ) );
//
dt2 << select where( Is Missing( :Pool Number ) == 0 );
dt2 << delete rows;
dt2 << delete columns( :Pool Number );
// Cleanup temporary tables
Close( dtTemp, nosave );
Close( dtPoolCount, nosave );
);
If( N Rows( dt2 ) > 0,
// Calculate the new pool numbers
dtPoolCount = dt2 << Summary(
Group( :Gender, :Ethnicity, :Age ),
Freq( "None" ),
Weight( "None" ),
Link to original data table( 0 )
);
// Get the current pool number
maxPool = Col Max( dtPool:Pool Number );
If( Is Missing( maxPool ),
maxPool = 0
);
// Add Pool Number to Pool Count table
dtPoolCount << New Column( "Pool Number", set each value( maxPool + Row() ) );
dtPoolCount << delete columns( N Rows );
// Set the current pool number in the current sample table
dt2 = dt2 << Update(
With( dtPoolCount ),
Match Columns( :Gender = :Gender, :Ethnicity = :Ethnicity, :Age = :Age )
);
// Add the sample to the dtPool table
dtPool = dtPool << concatenate( dt2, append to first table( 1 ) );
// Clean up
Close( dtPoolCount, nosave );
);
// Add the Pool Number to the original data table
dt << Update( With( dtPool ), Match Columns( :__Row__ = :__Row__ ) );
// Delete the Working data table and the Pool Count data table
Close( dt2, nosave );
Close( dtPool, nosave );