分层抽样法

分层抽样的具体程序是:把总体各单位分成两个或两个以上的相互独立的完全的组(如男性和女性),从两个或两个以上的组中进行简单随机抽样样本相互独立。总体各单位按主要标志加以分组,分组的标志与关心的总体特征相关。例如,正在进行有关啤酒品牌知名度方面的调查,初步判别,在啤酒方面男性的知识与和女性的不同,那么性别应是划分层次的适当标准。如果不以这种方式进行分层抽样,分层抽样就得不到什么效果,花再多时间、精力和物资也是白费。

分层抽样与简单随机抽样相比,往往选择分层抽样,因为它有显著的潜在统计效果。也就是说,如果从相同的总体中抽取两个样本,一个是分层样本,另一个是简单随机抽样样本,那么相对来说,分层样本的误差更小些。另一方面,如果目标是获得一个确定的抽样误差水平,那么更小的分层样本将达到这一目标。

 

各层样本数的确定方法有3种:

①分层定比。即各层样本数与该层总体数的比值相等。例如,样本大小n=50,总体N=500,则n/N=0.1 即为样本比例,每层均按这个比例确定该层样本数。

②奈曼法。即各层应抽样本数与该层总体数及其标准差的积成正比。

③非比例分配法。当某个层次包含的个案数在总体中所占比例太小时,为使该层的特征在样本中得到足够的反映,可人为地适当增加该层样本数在总体样本中的比例。但这样做会增加推论的复杂性。

在调查实践中,为提高分层样本精确度实际上要付出一些代价。通常,现实正确的分层抽样一般有三个步骤:

首先,辩明突出的(重要的)人口统计特征和分类特征,这些特征与所研究的行为相关。例如,研究某种产品的消费率时,按常理认为男性和女性有不同的平均消费比率。为了把性别作为有意义的分层标志,调查者肯定能够拿出资料证明男性与女性的消费水平明显不同。用这种方式可识别出各种不同的显著特征。调查表明,一般来说,识别出 6 个重要的显著特征后,再增加显著特征的辨别对于提高样本代表性就没有多大帮助了。

第二,确定在每个层次上总体的比例(如性别已被确定为一个显著的特征,那么总体中男性占多少比例,女性占多少比例呢?)。利用这个比例,可计算出样本中每组(层)应调查的人数。

最后,调查者必须从每层中抽取独立简单随机样本。

 

<think>根据用户需求,需要提供C#实现分层抽样的示例代码。分层抽样(Stratified Sampling)是将总体分成若干层(子总体),然后从每层中抽取样本的方。其关键步骤包括: 1. 将总体分为互斥的层(如按年龄、地区等特征) 2. 确定每层的抽样比例(可按比例分配或最优分配) 3. 在各层内独立进行简单随机抽样或其他抽样 我们将实现一个按比例分配的分层抽样。假设我们有一个数据集,其中每个数据项属于某个层(用字符串标识)。我们将按照每层在总体中的比例,抽取相应数量的样本。 步骤: 1. 计算每个层在总体中的比例。 2. 根据总样本量,按比例分配各层应抽取的样本数(四舍五入或取整,注意处理取整后总数可能不等于总样本量的问题)。 3. 对每个层,随机抽取所需数量的样本。 注意:由于取整问题,实际抽取的样本总数可能与目标总数有差异,我们将采用以下策略: - 先按比例向下取整分配各层样本数 - 然后按各层比例的小数部分从大到小依次增加1个样本,直到达到总样本量 我们将编写一个通用的分层抽样,可以处理任何类型的数据,只要提供层标识。 代码结构: 1. 定义一个类`StratifiedSampler`,包含一个静态方`Sample`。 2. 输入参数: - `IEnumerable<T> population`: 总体数据 - `Func<T, string> stratumSelector`: 从数据项获取层标识的委托 - `int totalSampleSize`: 总样本量 3. 输出:抽样结果列表`List<T>` 实现细节: - 首先将总体按层分组 - 计算每层的比例和应分配的样本数(按上述取整策略) - 对每层进行简单随机抽样(使用随机数生成器) 注意:随机性使用`Random`类,考虑线程安全,这里我们使用局部随机实例(在方内部创建)。 由于取整调整,我们使用以下步骤分配样本数: 1. 计算每层的数据量(count)和比例(proportion = count / totalCount) 2. 计算每层基础样本数 = floor(proportion * totalSampleSize) 3. 计算剩余样本数 = totalSampleSize - 所有层基础样本数之和 4. 将剩余样本数按各层比例的小数部分从大到小分配(即小数部分大的层优先增加一个样本) 我们将使用LINQ来简化操作。 代码示例:</think>### C# 分层抽样实现 分层抽样是将总体划分为若干同质子群(层),再从各层中独立抽取样本的统计方。以下是完整的 C# 实现模板: ```csharp using System; using System.Collections.Generic; using System.Linq; public static class StratifiedSampler { /// <summary> /// 执行分层随机抽样 /// </summary> /// <typeparam name="T">数据类型</typeparam> /// <param name="population">总体数据</param> /// <param name="stratumSelector">分层选择函数</param> /// <param name="sampleSize">总样本量</param> /// <param name="randomSeed">随机种子(可选)</param> /// <returns>分层抽样结果</returns> public static List<T> Sample<T>( IEnumerable<T> population, Func<T, string> stratumSelector, int sampleSize, int? randomSeed = null) { // 参数校验 if (population == null || !population.Any()) throw new ArgumentException("总体数据不能为空"); if (stratumSelector == null) throw new ArgumentNullException(nameof(stratumSelector)); if (sampleSize <= 0) throw new ArgumentException("样本量必须大于0"); // 1. 将总体按层分组 var strata = population .GroupBy(stratumSelector) .Select(g => new Stratum<T> { Key = g.Key, Items = g.ToList(), Size = g.Count() }) .ToList(); // 2. 计算各层样本分配量(比例分配) var totalPopulation = strata.Sum(s => s.Size); var allocations = CalculateAllocations(strata, sampleSize, totalPopulation); // 3. 创建随机数生成器 Random random = randomSeed.HasValue ? new Random(randomSeed.Value) : new Random(); // 4. 从各层抽取样本 var samples = new List<T>(); for (int i = 0; i < strata.Count; i++) { var stratum = strata[i]; var allocation = allocations[i]; if (stratum.Size < allocation) throw new InvalidOperationException( $"层 '{stratum.Key}' 的样本量({allocation})超过层大小({stratum.Size})"); samples.AddRange(GetRandomSamples(stratum.Items, allocation, random)); } return samples; } // 计算各层样本分配量 private static List<int> CalculateAllocations<T>( List<Stratum<T>> strata, int totalSampleSize, int totalPopulation) { var allocations = new List<int>(); int allocatedTotal = 0; var fractions = new List<(int index, double fraction)>(); // 第一步: 按比例计算基础分配量 for (int i = 0; i < strata.Count; i++) { var proportion = (double)strata[i].Size / totalPopulation; var allocation = (int)Math.Floor(proportion * totalSampleSize); allocations.Add(allocation); allocatedTotal += allocation; // 保存小数部分用于后续分配 fractions.Add((i, proportion * totalSampleSize - allocation)); } // 第二步: 分配剩余样本(按小数部分从大到小) int remaining = totalSampleSize - allocatedTotal; if (remaining > 0) { foreach (var item in fractions.OrderByDescending(f => f.fraction).Take(remaining)) { allocations[item.index]++; } } return allocations; } // 从层内随机抽取样本 private static List<T> GetRandomSamples<T>(List<T> items, int count, Random random) { // 简单随机抽样 return items.OrderBy(x => random.Next()).Take(count).ToList(); } // 层数据存储结构 private class Stratum<T> { public string Key { get; set; } public List<T> Items { get; set; } public int Size { get; set; } } } ``` ### 使用示例 ```csharp // 定义测试数据模型 public class Person { public int Id { get; set; } public string AgeGroup { get; set; } // 分层依据:年龄层 public string City { get; set; } } class Program { static void Main() { // 1. 创建测试数据(1000条记录) var population = new List<Person>(); var random = new Random(); var cities = new[] { "北京", "上海", "广州", "深圳" }; var ageGroups = new[] { "18-25", "26-35", "36-45", "46+" }; for (int i = 1; i <= 1000; i++) { population.Add(new Person { Id = i, City = cities[random.Next(cities.Length)], AgeGroup = ageGroups[random.Next(ageGroups.Length)] }); } // 2. 执行分层抽样(总样本量100) var samples = StratifiedSampler.Sample( population: population, stratumSelector: p => p.AgeGroup, // 按年龄层分组 sampleSize: 100, randomSeed: 1234); // 固定种子保证可重现 // 3. 验证结果(打印各层样本量) Console.WriteLine("分层抽样结果:"); Console.WriteLine($"{"年龄层",-10} | 样本量"); Console.WriteLine(new string('-', 20)); foreach (var group in samples.GroupBy(s => s.AgeGroup).OrderBy(g => g.Key)) { Console.WriteLine($"{group.Key,-10} | {group.Count()}"); } } } ``` ### 关键实现说明: 1. **分层逻辑**: - 使用 `GroupBy` 按指定特征(如年龄层)分层 - 自动计算各层在总体中的比例 $$p_i = \frac{N_i}{N}$$ - 按比例分配样本量 $$n_i = n \times p_i$$ 2. **样本分配算**: - 基础分配:取整运算 $\lfloor n \times p_i \rfloor$ - 剩余分配:按小数部分大小分配剩余样本 - 确保总样本量精确:$\sum n_i = n$ 3. **随机抽样**: - 使用 Fisher-Yates 洗牌算(通过 `OrderBy(x => random.Next())` 实现) - 支持随机种子保证结果可重现 4. **异常处理**: - 空数据校验 - 层大小不足校验 - 无效参数检测 ### 适用场景: 1. 人口统计调查 2. 产品质量抽检 3. 临床试验分组 4. 市场调研 5. 社会调查数据收集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值