随机分组并获得平均值你好,
我有一个按 3 个类别(性别/年龄/种族)分层的约 2000 个人的数据集。 我想通过从每个性别/年龄/种族中抽取约 8 个人并找到平均值来获得这些个人的“汇总”值。 需要注意的是,某些类别的垃圾箱中的个体比其他垃圾箱中的个体多。 附件是我得到的所有个人及其分组的细分。 例如,类别 1-1-1 有 120 个个体,因此我可以从中创建 8*15 个随机个体组。 如果我的数字不是 8 的倍数怎么办?
我怎样才能一步完成这一切? 最后,我们将拥有大约 200 个池。

脚本回复:随机分组并获得平均值我不完全确定我是否创建了一个可以满足您需求的脚本,但它可能会给您一个良好的开端。这是它的作用
- 它找到人口最少的性别/年龄/种族组。该组将限制可以创建多少个池,因为没有行可以出现在一个以上的池中。
- 然后它会尝试找到最小化该子组的未包含行数的池大小。它通过将组大小从 8 增加到 21 来做到这一点,并找到最小的余数(浪费)。
- 然后它从原始表创建一个工作表。
- 它在工作台上循环,
- 创建分层随机样本
- 将新样本添加到最终池数据表中
- 从工作数据表中删除为最新的子集化随机数据表选择的行。
- 尽可能多地重复以将尽可能多的最小子组记录放入最终的合并数据表中。
这是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 );
我在我创建的示例数据表上对此进行了测试,因此您的实际表可能存在一些问题。我已经对代码进行了注释,因此希望您能够了解我所做的事情,并能够进行调整以使其完全按照您的需要工作。
回复:随机分组并获得平均值
嗨,吉姆,
此脚本会生成一个空白表。 我希望从中得到的是原始数据表中的一个新列,称为“池编号”。 需要注意的一点是,年龄不是一个连续的数值变量。 它是数字 1 - 4 之间的分类变量。
有一次,我将原始数据集中的所有样本归类到它们的池中,我可以通过取池中约 8 个样本的平均值来计算池的平均值。
我已附上该文件作为参考。
工作表在脚本中是有意义的;您正在创建一列,每一行都有一个唯一的值。 最终数据集的创建导致一个空白数据表,我看不出这个错误是从哪里引起的。
回复:随机分组并获得平均值如果潜在池大小减少到 6,我的 JSL 将成功完成。我的代码要求必须能够从每个子组中提取至少 1 个样本,并且由于子组,1 2 4 只有 6 个观察值(行),我为找到最佳样本量而编写的代码必须修改为池大小为 6。
但不管怎样,我显然不明白你是如何确定你的池的。对于每个数据子组,我将您的池等同于具有给定样本大小的随机样本。事实证明,这对我来说是一个错误的假设。
您是否为每个子组独立创建池?也就是说,对于子组 1 1 1,有 120 行数据。如果池大小为 8,是否创建 15 个池?然后对于有 50 行的组 1 1 2,您将创建 6 个池,其中 4 行未被选择用于池?
这就是你创建游泳池的方式吗?
这是所有性别/种族/年龄亚组的细分。

我当前的 JSL 没有做你想做的事,请给我一个关于如何创建池的更准确的解释,我会看看需要做些什么来组合一个可行的脚本。
回复:随机分组并获得平均值嗨,吉姆,
通过在每个池中拥有约 8 个人来创建子组。 您对 1-1-1 是正确的。 这个组有 120 个人,所以如果我们要随机汇集这些个人,他们应该正好适合 15 个池。 对于有 50 行的组 1-1-2,您将创建 6 个由 8 个人组成的池,其余 4 个将放入他们自己的池中。
那有意义吗? 我们希望数据表中的所有行都与特定的池编号相关联。
回复:随机分组并获得平均值下面是一个适用于您的示例数据表的脚本,用于创建您想要的所有池。请花时间研究脚本,以便您可以进行任何可能需要的修改以将其调整为最终形式
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 );