Java实现采样,等比例分和均分

Java实现采样,等比例分和均分

今天接到老大给的一个任务,让我做一个从一些流量中,按照模版进行采样。需要按照等比例和均分。

例如:

模版有A和B,总数量是10个,A有4个,B有6个。

假设现在需要采5个:

如果按照等比例分配:那么A要采2个,B要才3个。

假设现在需要采6个:

按照均分,A和B个才3个。

理想情况下,如果都是上面的这种当然好了,能够整除。但是很多情况下是不能整除的,但是也要保证达到采样的总数。

要求:

每个模版都要采到。

废话不多说,直接上代码。

/***
* 等比例采样
* @param map 存放数据,需要按照数量正序排
* @param total 总数量
* @param sampleTotal 需要采样的数量
*/
public static void allocateFlowByPercentage(Map map, Integer total, Integer sampleTotal) {
int newTotal = 0;
int addCount = 0;
int i = 0;
double basePercentage = sampleTotal / total.doubleValue();
Iterator> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry next = iterator.next();
String key = next.getKey();
if (sampleTotal == map.size()) {
// 每个模版分1个
map.put(key, 1);
System.out.println("模版" + key + ":原来有流量:" + next.getValue() + "个,采样:1个");
newTotal++;
continue;
}
double doubleCount = basePercentage * next.getValue();
int newCount = (int) Math.round(doubleCount);
if (newCount == 0) {
newCount = 1;
addCount++;
} else if (newCount > doubleCount && addCount > 0 && newCount > 1) {
addCount--;
newCount--;
}
if (i == map.size() - 1) {
// 最后一个不计算了,直接拿总数减去之前的总数。需要保证,map中存储的数量,是按照正序从小到大排序的
newCount = sampleTotal - newTotal;
}
System.out.println("模版" + key + ":原来有流量:" + next.getValue() + "个,采样:" + newCount + "个");
map.put(key, newCount);
newTotal += newCount;
i++;
}
System.out.println("实际采样的总数:" + newTotal);
}
/***

* 均分采样

* @param map 存放数据,需要按照数量正序排
* @param sampleTotal 需要采样的数量
*/
public static void allocateFlowByAverage(Map map, Integer sampleTotal) {
int newTotal = 0;
int i = 0;
double averageCount = sampleTotal.doubleValue() / map.size();
Iterator> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry next = iterator.next();
String key = next.getKey();
if (sampleTotal == map.size()) {
// 每个模版分1个
map.put(key, 1);
System.out.println("模版" + key + ":原来有流量:" + next.getValue() + "个,采样:1个");
newTotal++;
continue;
}
int newCount = next.getValue();
if (newCount > averageCount) {
newCount = (int) Math.round(averageCount);
}
if (i == map.size() - 1) {
// 最后一个不计算了,直接拿总数减去之前的总数。需要保证,map中存储的数量,是按照正序从小到大排序的
newCount = sampleTotal - newTotal;
}
System.out.println("模版" + key + ":原来有流量:" + next.getValue() + "个,采样:" + newCount + "个");
map.put(key, newCount);
newTotal += newCount;
i++;
}
System.out.println("实际采样的总数:" + newTotal);
}

注意:

这里当采样数量小于模版数量的时候,异常处理我这边省略了。

当采样数量大于总数的时候,不需要做任何处理,全部采。这里面我也省略了。

下面验证一下:

public static void main(String[] args) {
// 保证添加的顺序是从小到大
Map map = new LinkedHashMap<>();
map.put("D", 4);
map.put("E", 6);
Integer total = 10;
Integer sampleTotal = 5;
System.out.println("========= 等比例采样 ===========");
allocateFlowByPercentage(map, total, sampleTotal);
System.out.println();
System.out.println("========= 均分采样 ===========");
map.put("D", 4);
map.put("E", 6);
sampleTotal = 6;
allocateFlowByAverage(map, sampleTotal);
}

先来验证下能整除的情况下。

java 分布直方图 java均匀分布_spring

验证下不能整除的情况下。

这里面测试两个零界点。

一个是数量等于模版总数

一个是采样数量 = 总数 - 1

数量等于模版总数

public static void main(String[] args) {
// 保证添加的顺序是从小到大
Map map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 1);
map.put("C", 3);
map.put("D", 4);
map.put("E", 6);
Integer total = 15;
Integer sampleTotal = 5;
System.out.println("========= 等比例采样 ===========");
allocateFlowByPercentage(map, total, sampleTotal);
System.out.println();
System.out.println("========= 均分采样 ===========");
map.put("A", 1);
map.put("B", 1);
map.put("C", 3);
map.put("D", 4);
map.put("E", 6);
sampleTotal = 5;
allocateFlowByAverage(map, sampleTotal);
}

结果是:

java 分布直方图 java均匀分布_spring_02

采样数量 = 总数 - 1

把sampleTotal设置成14;

java 分布直方图 java均匀分布_模版_03

采样数量在 5 ~ 14之间

当我们测试了两个零界点之后,是没有问题的,那么中间的数量就没什么问题了。

把sampleTotal设置成9;

java 分布直方图 java均匀分布_java 分布直方图_04

Java实现采样,等比例分和均分相关教程

spring应用手册-IOC(XML配置实现)-(2)-spring的helloworld应

spring应用手册-IOC(XML配置实现)-(2)-spring的helloworld应用 看文字嫌累的可以查看后面的视频说明( __ ) 嘻嘻…… [1]准备 创建项目:spring-st 添加依赖: dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/arti

JavaScript事件讲解

JavaScript事件讲解 事件讲解 什么是JavaScript事件? 事件流 事件冒泡 事件捕获 事件冒泡和事件捕获关系图 DOM事件流 事件类型 1.事件(Event)是JavaScript应用跳动的心脏,也是把所有东西粘在一起的胶水,当我们与浏览器中Web页面进行某些类型的交互时,事件

Lua文件操作

Lua文件操作 在实现文件操作之前 如果大家也有乱码问题的话 就跟着我先把这个问题解决了 首先打开这个设置 之后给这里添加两句代码即可 code.page=65001output.code.page=65001 之后就可以开始我们的文件操作了 还是首先给出一个表格 接下来我做几个简单的演

LeetCode 771宝石与石头(Java)

LeetCode 771宝石与石头(Java) class Solution { public int numJewelsInStones(String J, String S) { if(J == null || S== null ) return 0; int num = 0; for(char s : S.toCharArray()) { for(char j : J.toCharArray()) { if(s == j) { num ++; break; }

JavaScript事件对象

JavaScript事件对象 事件对象 什么是event对象? event对象-事件添加方法 Event相关方法与属性 Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。事件通常与函数结合使用,函数不会在事件发生前被执行! 监

008 触发器实现三分频

008 触发器实现三分频 1、D触发器实现 不带NOR1时,就是一个4分频电路,或者说4计数器,11-10-01-00-11 {signal: [ {name: 'Clk', wave: 'P...........', period: 1}, {name: 'Q1\'', wave: 'P.....', period: 2}, {name: 'Q2\'', wave: 'P..', period: 4}]}

java容器

java容器 一、java容器 1.java容器类库中一共有两种主要类型:Collection和Map (1)Collection和Map的区别在于容器内每个槽所存储的元素的个数不同,Collection类型中,每个槽只有一个元素;Map类型中,持有key-value关联(key叫做键,value叫做值)像一个小型

输入/输出流

输入/输出流 1.在java的I/O结构中,RandomAccessFile是比较不寻常的类,直接继承自Object类,并不属于Streams结构的一部分。 2.读取具有很多字节流的文本文件的时候,通常使用BufferedReader。 3.java中的IO流图。 (1)java 的IO操作中有面向字节(Byte)和面向