(保守群组测试 非保守群组测试 二次重复测试 自适应二次重复测试)四种群体测试的C++代码

目录

  • 原理
    • 保守组检测
    • 非保守组检测
    • 二次重复测试
    • 自适应二次重复测试
  • 四种测试方法的核心代码
    • 保守群组测试
    • 非保守群组测试
    • 二次重复测试与自适应二次重复测试
    • 测试代码
  • 参考文献

原理

假设该病在人群中的患病率(先验概率)为p,我们想用群体检验法检验N个独立样本组大小n,即样本数量。
单个试验的诊断方法的FNR用fN表示,FPR可忽略不计。
用G表示一组样本,G=0表示G中的所有样本均未感染。相反,G=1意味着G是一个阳性组;即,它至少有一个感染标本。通过观察不同方法的分组试验结果,我们将一个组分为感染组和未感染组,分别用Gˆ=1和Gˆ=0表示。

保守组检测

在这里插入图片描述
在这里插入图片描述

非保守组检测

在这里插入图片描述

步骤如下:
在这里插入图片描述
每个Group由三个sample人的血液组成。
这样能保证每个Group能被测试两次(也代表着每个sample人的血液能够被测试两次),fN表示单个试验的FNR(false negative rate),这样就能保证Sg(群体水平敏感度)= 1 - fN^2;
总的来说,Gi、Gi+1为阳性,则Mi,i+1也为阳性。
这样,图1中的M2,3和M3,4都是正的,很可能是因为G3=1。尽管在G2=1和G4=1的情况下也会出现这些阳性结果,但缺少M1,2=1和M4,1=1使得G2和G4都不太可能等于1。在这种方法中,例如,如果G2为真阳性,M1,2=0为假阴性结果,我们将忽略G2=1,从而导致灵敏度降低。

在非保守组检测中有以下规则:
在这里插入图片描述

二次重复测试

简单来说就是对分组之后检测的所有组都检测两遍,只要有一次为阳则说明这个组中有阳性。
在这里插入图片描述

自适应二次重复测试

第二次测试将第一次测试中为阴性的进行测试。
在这里插入图片描述

四种测试方法的核心代码

【0】保守群组测试 【1】非保守群组测试 【2】二次重复测试 【3】二次自适应重复测试

保守群组测试

//非保守测试
//输入:splited_group 、 分组混合血液 、 假阴率 fnr
//输出:检测出来的阳性样本数、总检测次数
int No_Conservative_Group_Detection(vector<vector<int>>& splited_group,vector<int>& result, float fnr, vector<int>& Positive_Group, vector<int>& PositiveSamples)
{//将Gi、Gi+1混合到一起为Mi//如果相邻两个M(Mj,Mj+1)检测结果是阳性,则认定是Gj+1是阳性。//如果只有单独的Mj检测结果是阳性,则将Gj与Gj+1都检测一遍。int All_Test_Times = 0;//【step1】将G血液结果两两混合到M中vector<int> Mixed_Group_Result;for (int i = 0; i < result.size() - 1; i++){if (result[i] == 1 || result[i + 1] == 1)Mixed_Group_Result.emplace_back(1);else Mixed_Group_Result.emplace_back(0);}//第一个样本与最后一个样本混合if(result[0] == 1 || result[result.size()-1] == 1) Mixed_Group_Result.emplace_back(1);else Mixed_Group_Result.emplace_back(0);//【step2】对M结果进行检测,需要考虑到假阴性影响,得到阳性G序号vector<int> Blured_Mixed_Group_Result;Test_Synthetic_Blood(Mixed_Group_Result, Blured_Mixed_Group_Result, fnr);All_Test_Times += Mixed_Group_Result.size();//寻找检测结果为阳性的Mfor (int j = 0; j < Blured_Mixed_Group_Result.size() - 1; j++){//如果是两个连在一起的为阳性,取交集的Gif (Blured_Mixed_Group_Result[j] == 1 && Blured_Mixed_Group_Result[j + 1] == 1){Positive_Group.emplace_back(j+1);}else if(Blured_Mixed_Group_Result[j] == 1 && Blured_Mixed_Group_Result[j + 1] == 0){//如果Gj已经被送入结果,那么只需要再送入Gj+1if (!Positive_Group.empty() && Positive_Group.back() == j){Positive_Group.emplace_back(j + 1);}//否则,将两个都送入else{Positive_Group.emplace_back(j);Positive_Group.emplace_back(j + 1);}}}cout << "非保守测试可能为阳性的Group个数" << Positive_Group.size() << endl;//对每个可能阳性的Group进行核酸检测for (int i = 0; i < Positive_Group.size(); i++){int pos_index = Positive_Group[i];//对可能阳性Group中每个样本都进行检测,要考虑到假阴性的影响,得到阳性的样本的序号。vector<int> Blured_Splited_GroupResult;Test_Synthetic_Blood(splited_group[pos_index], Blured_Splited_GroupResult, fnr);//对检测结果进行记录,记录下在原序列中的坐标for (int j = 0; j < Blured_Splited_GroupResult.size(); j++){if (Blured_Splited_GroupResult[j] == 1){PositiveSamples.emplace_back(pos_index* splited_group[0].size() + j);}	}}All_Test_Times += Positive_Group.size() * splited_group[0].size();return All_Test_Times;}

非保守群组测试

//保守测试
//输入:splited_group 、 分组混合血液 、 假阴率 fnr
//输出:检测出来的阳性样本数、总检测次数
int Conservative_Group_Detection(vector<vector<int>>& splited_group, vector<int>& result, float fnr, vector<int>& Positive_Group, vector<int>& PositiveSamples)
{//将Gi、Gi+1混合到一起为Mi//如果M检测结果是阳性,则认定是Gj,Gj+1是阳性。int All_Test_Times = 0;//【step1】将G血液结果两两混合到M中vector<int> Mixed_Group_Result;for (int i = 0; i < result.size() - 1; i++){if (result[i] == 1 || result[i + 1] == 1)Mixed_Group_Result.emplace_back(1);elseMixed_Group_Result.emplace_back(0);}//第一个样本与最后一个样本混合if (result[0] == 1 || result[result.size() - 1] == 1) Mixed_Group_Result.emplace_back(1);else Mixed_Group_Result.emplace_back(0);//【step2】对M结果进行检测,需要考虑到假阴性影响,得到阳性G序号vector<int> Blured_Mixed_Group_Result;Test_Synthetic_Blood(Mixed_Group_Result, Blured_Mixed_Group_Result, fnr);All_Test_Times += Mixed_Group_Result.size();//寻找检测结果为阳性的Mfor (int j = 0; j < Blured_Mixed_Group_Result.size() - 1; j++){if (Blured_Mixed_Group_Result[j] == 1){if (!Positive_Group.empty() && Positive_Group.back() == j){Positive_Group.emplace_back(j + 1);}else{Positive_Group.emplace_back(j);Positive_Group.emplace_back(j + 1);}}}//对每个可能阳性的Group进行核酸检测cout << "保守测试可能为阳性的Group个数"<< Positive_Group.size() <<endl;for (int i = 0; i < Positive_Group.size(); i++){int pos_index = Positive_Group[i];//对可能阳性Group中每个样本都进行检测,要考虑到假阴性的影响,得到阳性的样本的序号。vector<int> Blured_Splited_GroupResult;Test_Synthetic_Blood(splited_group[pos_index], Blured_Splited_GroupResult, fnr);//对检测结果进行记录,记录下在原序列中的坐标for (int j = 0; j < Blured_Splited_GroupResult.size(); j++){if (Blured_Splited_GroupResult[j] == 1){PositiveSamples.emplace_back(pos_index * splited_group[0].size() + j);}}}All_Test_Times += Positive_Group.size() * splited_group[0].size();return All_Test_Times;}

二次重复测试与自适应二次重复测试

/*
* 重复二次测量
* 输入:result实际感染情况,blured_result第一次检测情况,rep_blured_result第二次检测情况
* 输出:
*/
void Replicate_Test(vector<int>& result, vector<int>& blured_result, vector<int>& rep_blured_result, float fnr)
{rep_blured_result.clear();srand((unsigned)time(NULL));int fnr_100 = fnr * 100;for (int i = 0; i < result.size(); i++) //第二次全覆盖测试{//对每个阳性样本进行混淆处理if (result[i] == 1){int num = rand() % 100;// r % 概率检测为阴性if (num <= fnr_100){rep_blured_result.emplace_back(0);}//1-fnr%概率检测为阳性else{rep_blured_result.emplace_back(1);}}//由于covid-19不存在假阳性,这里对阴性样本不做处理else{rep_blured_result.emplace_back(0);}}for (int i = 0; i < result.size(); i++) { //将第一第二次的检测结果合并if (blured_result[i] == 1) {rep_blured_result[i] = 1;}}return;
}
/*
* 自适应重复二次测量,对象为第一次测量中为阴性的组
* 输入:result实际感染情况,blured_result第一次检测情况,rep_blured_result第二次检测情况
* 输出:二次测量的测量数
*/
int Adt_Replicate_Test(vector<int>& result, vector<int>& blured_result, vector<int>& rep_blured_result, float fnr) {rep_blured_result.clear();srand((unsigned)time(NULL));int fnr_100 = fnr * 100;int Test_Times = 0;for (int i = 0; i < blured_result.size(); i++){//对第一次检测结果再进行挑选检测if (blured_result[i] == 1) //第一次检测为阳性,跳过检测{rep_blured_result.emplace_back(1);}else  //第一次检测为阴性,再次检测{Test_Times++;if (result[i] == 1) {int num = rand() % 100;// r % 概率检测为阴性if (num <= fnr_100){rep_blured_result.emplace_back(0);}//1-fnr%概率检测为阳性else{rep_blured_result.emplace_back(1);}}else rep_blured_result.emplace_back(0);}}return Test_Times;
}/*
* 重复二次测量
* 输入:splited_group分组,result实际感染情况,fnr假阴率,Positive_Group二次测量后的阳性组,PositiveSamples二次测量后的阳性样本,Mode方法模式,0为重复二次测量,1为自适应重复二次测量
* 输出:
*/
int Replicate_TestDetection(vector<vector<int>>& splited_group, vector<int>& result, float fnr, vector<int>& Positive_Group, vector<int>& PositiveSamples,int Mode)
{//将Gi、Gi+1混合到一起为Mi//如果M检测结果是阳性,则认定是Gj,Gj+1是阳性。int All_Test_Times = 0;//【step1】将G血液结果两两混合到M中vector<int> Mixed_Group_Result;for (int i = 0; i < result.size() - 1; i++){if (result[i] == 1 || result[i + 1] == 1)Mixed_Group_Result.emplace_back(1);elseMixed_Group_Result.emplace_back(0);}//第一个样本与最后一个样本混合if (result[0] == 1 || result[result.size() - 1] == 1) Mixed_Group_Result.emplace_back(1);else Mixed_Group_Result.emplace_back(0);vector<int> Blured_Mixed_Group_Result;//第一次检测Test_Synthetic_Blood(Mixed_Group_Result, Blured_Mixed_Group_Result, fnr);All_Test_Times += Mixed_Group_Result.size();vector<int> Sec_Blured_Mixed_Group_Result;if (Mode == 0){//第二次检测,采用重复二次测量Replicate_Test(result, Blured_Mixed_Group_Result, Sec_Blured_Mixed_Group_Result, fnr);All_Test_Times += Blured_Mixed_Group_Result.size();}else{//第二次检测,采用自适应重复二次测量,对象为第一次测量中为阴性的组int Sec_Test_Times = Adt_Replicate_Test(result, Blured_Mixed_Group_Result, Sec_Blured_Mixed_Group_Result, fnr);All_Test_Times += Sec_Test_Times;}//记录二次结果后的阳性组for (int i = 0; i < Sec_Blured_Mixed_Group_Result.size(); i++){if (Sec_Blured_Mixed_Group_Result[i] == 1) Positive_Group.emplace_back(i);}//对每个可能阳性的Group进行核酸检测cout << "二次重复测试可能为阳性的Group个数" << Positive_Group.size() << endl;for (int i = 0; i < Positive_Group.size(); i++){int pos_index = Positive_Group[i];//对可能阳性Group中每个样本都进行检测,要考虑到假阴性的影响,得到阳性的样本的序号。vector<int> Blured_Splited_GroupResult;Test_Synthetic_Blood(splited_group[pos_index], Blured_Splited_GroupResult, fnr);//对检测结果进行记录,记录下在原序列中的坐标for (int j = 0; j < Blured_Splited_GroupResult.size(); j++){if (Blured_Splited_GroupResult[j] == 1){PositiveSamples.emplace_back(pos_index * splited_group[0].size() + j);}}}All_Test_Times += Positive_Group.size() * splited_group[0].size();return All_Test_Times;
}

测试代码

	//检测总人数int sample_nums = 175000;//流行率设定double p = 0.04;//分组设定int sec_group_sample_nums =2;//假阴率设定float FNR = 0.2;int positive_sample_nums = p * sample_nums;if (sample_nums <= 0){cout <<"error1" <<endl;return 0;}sec_group_sample_nums = pow(2, i + 1);vector<int> Group(sample_nums, 0);//混合血液后的真实结果vector<int> Result;//受到假阴性影响后的混合血液测试结果vector<int> Blured_Result;vector<vector<int>> Splited_Group;//【1】初始化样本序列Initial_Group(Group, positive_sample_nums);//Pirnt_Group(Group);cout << endl;//【2】Pooling操作Split_Group(Group, Splited_Group, sec_group_sample_nums);//Pirnt_Split_Group(Splited_Group);cout << endl;//【3】混合血液Synthetic_Blood(Splited_Group, Result);vector<int> Positive_Group;vector<int> PositiveSamples;int All_Test_Times = 0;int Methods = 3;//【4】使用不同的测试方法switch (Methods){//【0】保守群组测试case 0:{All_Test_Times = Conservative_Group_Detection(Splited_Group, Result, FNR, Positive_Group, PositiveSamples);cout << "重复性测试总检测次数" << All_Test_Times << endl;if (positive_sample_nums != 0)cout << "检测出的阳性样本个数为" << PositiveSamples.size() << "准确率" << PositiveSamples.size() * 1.0f / positive_sample_nums << endl;elsecout << "error2" << endl;}break;//【1】非保守群组测试case 1:{All_Test_Times = No_Conservative_Group_Detection(Splited_Group, Result, FNR, Positive_Group, PositiveSamples);cout << "非重复性测试总检测次数" << All_Test_Times << endl;if (positive_sample_nums != 0)cout << "检测出的阳性样本个数为" << PositiveSamples.size() << "准确率" << PositiveSamples.size() * 1.0f / positive_sample_nums << endl;elsecout << "error2" << endl;}break;//【2】二次重复测试case 2:{All_Test_Times = Replicate_TestDetection(Splited_Group, Result, FNR, Positive_Group, PositiveSamples, 0);cout << "重复性测试总检测次数" << All_Test_Times << endl;cout << "阳性样本组数" << Positive_Group.size() << endl;if (positive_sample_nums != 0)cout << "检测出的阳性样本个数为" << PositiveSamples.size() << "准确率" << PositiveSamples.size() * 1.0f / positive_sample_nums << endl;elsecout << "error2" << endl;}break;//【3】二次自适应重复测试case 3:{All_Test_Times = Replicate_TestDetection(Splited_Group, Result, FNR, Positive_Group, PositiveSamples, 1);cout << "重复性测试总检测次数" << All_Test_Times << endl;if (positive_sample_nums != 0)cout << "检测出的阳性样本个数为" << PositiveSamples.size() << "准确率" << PositiveSamples.size() * 1.0f / positive_sample_nums << endl;elsecout << "error2" << endl;}break;default:break;}//根据仿真得出一个测试实际社会成本(即找出最后为阴性的组数/总组数*每组多少人*每个人的闲置成本)int Neg_Groups = Splited_Group.size() - Positive_Group.size();double Neg_rate = Neg_Groups * 1.0f / Splited_Group.size();cout << "Neg_rate " << Neg_rate << endl;cout << "总样本个数 " << Splited_Group.size() << endl;

参考文献

https://www.medrxiv.org/content/10.1101/2020.07.31.20154070v1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377434.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AngularJS中的表达式

AngularJS表达式 (AngularJS Expressions) In AngularJS, expressions are solved to give a result. It outputs the result of the expression in the html element that called it. Expressions in AngularJS contain literals, constants, operators and variables with re…

学习总结:机器学习(一)

有监督学习&#xff08;Supervised Learning&#xff09;所谓有监督学习&#xff0c;是区别于无监督学习而言的。其过程如下&#xff1a;给定一系列样本&#xff0c;样本是由一系列特征值和输出值组成。比如&#xff0c;某个地方的商品房&#xff0c;包括房子大小、房间数、距离…

Silverlight读取与设置Cookies

Silverlight读取与设置Cookies 设置Cookie DateTime expire DateTime.UtcNow TimeSpan.FromDays(30);string cookie string.Formate("{0}{1},expires{2}",key,value,expire)HtmlPage.SetProperty("cookie",cookie);读取Cookie 由于读取到的Cookie是一个…

WPS双栏格式下插入单栏图片

以一个我认识的西工大博士大佬的一篇SCI为例&#xff0c;期刊是双栏&#xff0c;图片过大&#xff0c;需要单栏进行展示&#xff0c;效果图如下&#xff1a; 一、双栏内容 二、插入单栏图像 随便敲几个字&#xff0c;选中&#xff0c; 页面布局----分栏---一栏 这行字就会…

JavaScript中的数组

Here we are discussing one of the most useful data structure, Array. 在这里&#xff0c;我们讨论最有用的数据结构之一Array 。 By conventional definition of arrays, "Arrays are the homogeneous collection of data types. But in JS, Arrays simply are the c…

【C++基础】异常处理机制概要

目录C的异常处理方法知识要点踹扔抓的代码块示例两种处理被0除的方法异常处理机制的优点其他语言中的异常处理C函数异常声明C的异常处理方法知识要点 理解“踹扔抓”三部曲的结构&#xff0c;尤其是catch是怎么匹配异常的。 知道C标准库中的异常类都是从exception继承下来的&am…

[转载]Struts2 获得Session和Request

转自http://www.blogjava.net/lyyb2001/archive/2008/03/07/184593.html 在struts1中&#xff0c;获得到系统的request或者session对象非常方便&#xff0c;都是按照形参传递的&#xff0c;但是在struts2中&#xff0c;request和session都被隐藏了struts提供两种方式访问sessio…

WPS根据章节编号依次排序

第Ⅲ章节有四小部分&#xff0c;分别为A、B、C、D 第Ⅳ章节要重新开始编号&#xff0c;从A开始 操作步骤&#xff1a; ①再D后面回车&#xff08;红线位置回车&#xff09;&#xff0c;生成E ②把Ⅳ中待写内容写到E中 ③将E复制到Ⅳ下&#xff0c;这里需要注意D的换行也要复制…

【C++基础】异常匹配与内建异常类

目录异常匹配catch: 按异常类型匹配为何要使用异常类内建异常类标准库中的异常基类标准库中的异常类例1&#xff1a;vector下标访问越界out_of_range异常例2&#xff1a;内存分配失败bad_alloc异常例3&#xff1a;侧向转换失败bad_cast异常类几种情况&#xff0c;使用对应异常异…

scala 访问修饰符_Scala中的访问修饰符

scala 访问修饰符Access modifiers are used in order to restrict the usage of a member function to a class or a package. Using access modifiers data hiding takes place which is a very important concept of OOPs. 访问修饰符用于将成员函数的使用限制为类或包。 使…

小试---EF5.0入门实例1

现在做个小练习吧~~~ 第一步&#xff1a;首先新建一个数据库名字为Test;数据库里面只有一个表UserTable 脚本为&#xff1a; USE [master] GO /****** 对象: Database [Test] 脚本日期: 12/15/2013 18:51:54 ******/ CREATE DATABASE [Test] ON PRIMARY ( NAME NTest, F…

iScroll4 禁止select等页面元素默认事件的解决方法 转

iScroll4 禁止select等页面元素默认事件的解决方法起因在于onBeforeScrollStart : function(e){ e.preventDefault(); },这一行&#xff0c;iSroll禁止了事件的默认行为&#xff0c;导致select&#xff0c;option&#xff0c;textarea等元素无法点击。解决方法也很简单&#xf…

C++中比较两个浮点数是否相等

来源&#xff1a; https://stackoverflow.com/a/37686/3242645 代码&#xff1a; #include <cmath> #include <limits> bool AreSame(double a, double b) {return std::fabs(a - b) < std::numeric_limits<double>::epsilon(); }

MPEG的完整形式是什么?

MPEG&#xff1a;运动图像专家组 (MPEG: Moving Picture Experts Group) MPEG is an abbreviation of Moving Picture Experts Group. It is a working group of authorities that is founded to establish standards for audio and video compression and transmission. The a…

正则 去除html标记

//string regexstr "<[^>]*>"; //去除所有的标签 //"<script[^>]*?>.*?</script>" //去除所有脚本&#xff0c;中间部分也删除 // string regexstr "<img[^>]*>"; //去除图片的正则 // string regexstr &…

自画PopMenu弹出

BorderColor:TColor; //边框颜色FillColor:TColor; //未选中填充颜色TextColor:TColor; //未选中字体颜色SelectTextColor:TColor; //选中字体颜色SelectFillColor:TColor; //选中填充颜色SideBuffer:Integer; //边框宽度procedure TForm1.FormCreate(Sender: TObject); b…

安利一款倒计时插件---雨滴桌面

内容来自B站(搜索Rainmeter即可)&#xff0c;里面教程很多&#xff0c;因为视频看的有点麻烦&#xff0c;故进行了整理 一、下载安装包、解压、安装 免费下载连接&#xff0c;不需要积分 skin文件夹存放皮肤的一些配置文件&#xff0c;因为原本皮肤太low了 第二个是可执行文…

【C++基础】自定义异常类与多重捕获

目录自定义异常类构建过程例&#xff1a;Vec3D类的数组下标越界的异常类捕获多种无关异常不同的异常的捕获捕获派生异常异常处理的次序例子&#xff1a;多重捕获异常类catch块的参数类型可以不用引用类型吗?自定义异常类 自定义异常类通常由exception或其后代类派生。这样我们…

gprs 睡眠模式_GPRS的完整形式是什么?

gprs 睡眠模式GPRS&#xff1a;通用分组无线业务 (GPRS: General Packet Radio Service) GPRS is an abbreviation of General Packet Radio Service. It is a non-voice, high-level speed packet switching technology planned for GSM networks. On 2G and 3G cellular tran…

int main(int argc,char* argv[])讲解

分类&#xff1a; 学习笔记2011-11-07 21:502354人阅读评论(0)收藏举报dos编译器pathunixcommandc在最近学习中老是遇到 int main(int argc,char* argv[])&#xff0c;以为就是简单的参数应用了&#xff0c;但是看代码是没能理解参数的具体传递过程&#xff0c;上网…