C# 蓄水池抽样
蓄水池采样算法解决的是在给定但长度未知的大数据集中,随机等概率抽取一个数据。如果知道数据的长度,可以用随机数rand()%n得到一个确切的随机位置,或者分块取值来构造随机,那么该位置的对象就是所求的对象,选中的概率是1/n。那长度未知特别是如果这个大数据集不能一次性放入内存中,蓄水池抽样算法就非常有用,在我的项目中采用的蓄水池随机抽样还加入了权重的计算。
其中方法中核心代码,也就是蓄水池抽样就是如下代码。
if (i < spotQuantity)
{
titleIndexList.Add(i);
eigenValueList.Add(tempEigenValue);
}
else
{
double minEigenValue = eigenValueList.Min();
int minIndex = eigenValueList.IndexOf(minEigenValue);
if (tempEigenValue > minEigenValue)
{
eigenValueList[minIndex] = tempEigenValue;
titleIndexList[minIndex] = i;
}
}
首先从计算出的要抽取多少数量,根据数据循环,先让抽取数量的数据放入池子中titleIndexList,并且将对应数据的权重放入到抽取数据的权重列表。
在后面的循环中,判断抽取的权重如果大于已经抽取的最小权重则替换最小权重的数据为当前循环的数据。
如果你不是按照权重,则可以产生一个随机数,如果随机数落在已经抽取队列的数组下标内,则替换掉原来的下标数据也能实现随机性。
public static void WeightedSampling(List<article> articleList, int grade)
{
//根据传入的grade 计算一个抽样数量。
double sampleFactor = (double)Math.Pow((double)1 / (1 + grade), Math.E);
var spotQuantity = (int)Math.Ceiling(articleList.Count() * sampleFactor);
//如果规则抽的数量已经超过随机抽取数则不再抽取
var spotedCount = articleList.Where(t => t.isspot == 1).Count();
if (spotedCount >= spotQuantity)
return;
//如果数量不足则补齐
spotQuantity -= spotedCount;
var spotTitleList = articleList.Where(t => t.isspot != 1).ToList();
//实例化池子和数据权重List
List<int> titleIndexList = new List<int>();
List<double> eigenValueList = new List<double>();
if (spotArticle.Count() <= spotQuantity)
{
for (int i = 0; i < spotArticle.Count(); i++)
{
spotArticle[i].isspot = 1;
}
}
else
{
var random = new Random();
for (int i = 0; i < spotTitleList.Count; i++)
{
double tempWeight = spotTitleList[i].eigenvalue;
double tempEigenValue = Math.Pow(random.NextDouble(), 1 / tempWeight);
if (i < spotQuantity)
{
titleIndexList.Add(i);
eigenValueList.Add(tempEigenValue);
}
else
{
double minEigenValue = eigenValueList.Min();
int minIndex = eigenValueList.IndexOf(minEigenValue);
if (tempEigenValue > minEigenValue)
{
eigenValueList[minIndex] = tempEigenValue;
titleIndexList[minIndex] = i;
}
}
}
//将抽取出来的对象isspot 抽取标志设置为1
foreach (var index in titleIndexList)
{
spotTitleList[index].isspot = 1;
}
}
}
该方法对于我们平时项目中抽取不知道数据长度的随机数是非常好用的算法,同时该算法不复杂其时间复杂度为O(n)。
C# 蓄水池抽样的更多相关文章
- Reservoir Sampling - 蓄水池抽样
问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...
- 蓄水池抽样(原理&实现)
前言: 蓄水池抽样:从N个元素中随机的等概率的抽取k个元素,其中N无法确定. 适用场景: 模式识别等概率抽样,抽样查看渐增的log日志(无法先保存整个数据流然后再从中选取,而是期望有一种将数据流遍历一 ...
- Reservoir Sampling - 蓄水池抽样问题
问题起源于编程珠玑Column 12中的题目10,其描述如下: How could you select one of n objects at random, where you see the o ...
- 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)
蓄水池抽样算法简介 蓄水池抽样算法随机算法的一种,用来从 N 个样本中随机选择 K 个样本,其中 N 非常大(以至于 N 个样本不能同时放入内存)或者 N 是一个未知数.其时间复杂度为 O(N),包含 ...
- Reservoir Sampling - 蓄水池抽样算法&&及相关等概率问题
蓄水池抽样——<编程珠玑>读书笔记 382. Linked List Random Node 398. Random Pick Index 从n个数中随机选取m个 等概率随机函数面试题总结 ...
- leetcode398 and leetcode 382 蓄水池抽样算法
382. 链表随机节点 给定一个单链表,随机选择链表的一个节点,并返回相应的节点值.保证每个节点被选的概率一样. 进阶:如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现? 示 ...
- C#LeetCode刷题-蓄水池抽样
蓄水池抽样篇 # 题名 刷题 通过率 难度 382 链表随机节点 47.0% 中等 398 随机数索引 41.6% 中等
- 【数据结构与算法】蓄水池抽样算法(Reservoir Sampling)
问题描述 给定一个数据流,数据流长度 N 很大,且 N 直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出 m 个不重复的数据. 比较直接的想法是利用随机数算 ...
- Reservoir Sampling 蓄水池抽样算法,经典抽样
随机读取数据,如何保证真随机是不可能的,因为计算机的随机函数是伪随机的. 但是在不考虑计算机随机函数的情况下,如何保证数据的随机采样呢? 1.系统提供的shuffle函数 C++/Java都提供有sh ...
随机推荐
- hive从入门到放弃(四)——分区与分桶
今天讲讲分区表和分桶表,前面的文章还没看的可以点击链接: hive从入门到放弃(一)--初识hive hive从入门到放弃(二)--DDL数据定义 hive从入门到放弃(三)--DML数据操作 分区 ...
- 将项目导入eclipse中出现的jsp页面报错
图片摘自百度经验,实在是每次都会忘了步骤,每次都得重新百度,所以索性自己总结到博客中,下次如果还记不住就直接从博客中看.原谅我实在学渣,呜呜~~~~(>_<)~~~~
- Java学习day30
线程分为用户线程和守护线程,虚拟机必须确保用户线程执行完毕,虚拟机不用等待守护线程执完毕 并发:同一个对象被多个线程同时操作,例如上万了同时抢100张票,手机银行和柜台同时取同一张卡里的钱 处理多线程 ...
- Java语言学习day39--8月14日
今日内容介绍1.Map接口2.模拟斗地主洗牌发牌 ###01Map集合概述 A:Map集合概述: 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形 ...
- 2021.12.21 eleveni的刷题记录
2021.12.21 eleveni的刷题记录 0. 有意思的题 P6701 [POI1997] Genotype https://www.luogu.com.cn/problem/P6701 状压优 ...
- javascript中的Ajax基础(一)
一.手写一个ajax 1 const xhr = new xmlHttpRequest() 2 3 xhr.open(请求方式:post get, 请求地址, 同步或者异步) 4 5 xhr.onre ...
- [ Perl ] 多线程并发编程
https://www.cnblogs.com/yeungchie/ 记录一些常用的 模块 / 方法 . 多线程 使用模块 threads use 5.010; use threads; sub fu ...
- Go语言 文件操作
@ 目录 引言 1. 打开和关闭文件 2. 读取文件 2.1 defer 语句 2.2 手动宕机处理 2.3 打开文件并获取内容 2.4 bufio 读取文件 2.5 ioutil 读取文件 2.6 ...
- jmeter脚本编写
jmeter脚本编写 一.http协议接口编写注意事项 1.请求体为json格式:一定要写请求头Content-Type:application/json 2.json格式文本 2.1 key-val ...
- 【Electron】在 WSL2 中 打包 electron Linux 版本
[Electron]在 WSL2 中 打包 electron Linux 版本. 安装 WSL 我使用的是 Ubuntu 20.04.4 LTS 的版本. 安装 WSL 文档地址:https://do ...