news 2026/5/1 11:27:45

Numpy 的随机选择在 Go 语言中的实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Numpy 的随机选择在 Go 语言中的实现

原文:towardsdatascience.com/numpys-random-choice-in-go-d65bc2838191?source=collection_archive---------12-----------------------#2024-01-23

https://mlefarov.medium.com/?source=post_page---byline--d65bc2838191--------------------------------https://towardsdatascience.com/?source=post_page---byline--d65bc2838191-------------------------------- Max Lefarov

·发表于Towards Data Science ·阅读时间 5 分钟·2024 年 1 月 23 日

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a8b5ef60ccf65bdd8b82b5bb8edf3698.png

由 ChatGPT 生成

最近我帮助实现了一些 Java 逻辑,这些逻辑本可以通过简单调用 Numpy 的random.choice来实现。这最终成了一个任务,让我有机会去深入了解那些你每天都在使用,但从未真正有时间完全理解其工作原理的东西。同时,我也有一段时间想开始学习 Go,那么为什么不一举两得,再次用 Go 实现random.choice呢?

random.choice允许我们根据指定的概率从提供的集合中采样 N 个元素。重要的是(对于激励这项工作的使用案例),它允许我们进行无重复的采样。也就是说,如果集合中的一个元素已经被采样,它将不会再次被采样。例如,如果我们有一个集合 [A, B, C],其对应的概率为 [0.1, 0.7, 0.2],并且我们想无重复地采样 3 个元素,那么大多数时候我们会得到 [B, C, A] 作为输出。如果我们进行有重复的采样,预期的输出将是 [B, B, B]。

首先,让我们定义 Go 函数的签名。我们希望它尽可能与 Numpy 的对应函数保持一致。

func ChoiceTany([]T,error){}

关于函数签名,有几点需要注意:

现在我们需要弄清楚如何使用仅在[0, 1]之间均匀抽样的浮动随机数(由 rng 返回)从由probs参数定义的离散概率分布中抽取元素。幸运的是,有一种方法可以完美解决这个问题。

CDF 反演法

首先,CDF 代表累积分布函数。在离散情况下,它可以表示为一个数组,其中索引i处的元素等于所有输入概率在位置i及之前的累计和。让我们用一个简单的帮助函数来实现这个公式。

func CDF(probs[]float64)[]float64{cdf:=make([]float64,len(probs))cum:=0.0fori:=rangecdf{cum+=probs[i]cdf[i]=cum}returncdf}

通过离散概率分布的 CDF 和随机数生成器,我们可以通过以下方式从输入集合中抽取元素:

  1. 从统一分布中随机抽取一个介于[0, 1]之间的浮动数值。

  2. 找到第一个 CDF 值大于等于随机浮动数的索引。

  3. 返回原集合中该索引位置的元素。

为了理解它为何有效,我们可以进行一个简单的视觉实验。我们可以把 CDF 数组中的值看作是放置在区间[0, 1]上每个箱子的右边界。每个箱子的宽度与输入的概率成正比。当生成介于[0, 1]之间的均匀随机浮动数时,我们可以把它看作是将球随机投掷到这个区间,并选择我们撞到的箱子。撞到箱子的概率正好与输入概率成正比(这正是我们需要的)。下面是我们最后一个例子——集合[A, B, C]及其相关概率[0.1, 0.7, 0.2]的视觉示范。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9a22c4e1bb87c7c5af9188bff8d5a420.png

由作者在 Excalidraw 中创建

要获得箱子的索引,我们可以返回第一个右边界大于或等于抽样值的索引。同样,这里有一个简单的帮助函数来实现这个功能:

func FindIndexFromRight(val float64,cdf[]float64)int{fori,cumProb:=rangecdf{ifcumProb>=val{returni}}returnlen(cdf)-1}

将所有内容整合在一起

这样,我们就具备了实现带有重复的random.choice所需的一切。无重复抽样则需要多一个技巧。为了确保我们不会抽取已经被抽取过的元素,可以在抽样后将其概率置为 0。然而,这样会使我们的离散概率分布失效,因为其总和将不再等于 1。为了修正这一点,我们需要通过将概率除以新的总和来重新归一化概率。作为额外的优化,我们可以直接对 CDF 进行重新归一化,而不需要先重新归一化输入概率再计算 CDF。将所有内容整合在一起:

func ChoiceTany([]T,error){if!replace&&(size>len(arr)){returnnil,errors.New("cannot sample more than array size without replacements")}samples:=make([]T,size)probsCopy:=make([]float64,len(probs))copy(probsCopy,probs)fori:=0;i<size;i++{cdf:=CDF(probsCopy)if!replace{total:=cdf[len(cdf)-1]forcdfInd:=rangecdf{cdf[cdfInd]/=total}}randFloat:=rng.Float64()sampledIndex:=FindIndexFromRight(randFloat,cdf)samples[i]=arr[sampledIndex]if!replace{probsCopy[sampledIndex]=0.0}}returnsamples,nil}

再次提醒几个需要注意的事项:

驱动代码如下:

rngSource:=rand.NewSource(time.Now().UnixNano())rng:=rand.New(rngSource)arr:=[]string{"A","B","C","D"}probs:=[]float64{0.1,0.6,0.2,0.1}samples,err:=Choice(arr,3,false,probs,rng)iferr!=nil{log.Fatal(err)}fmt.Println("Samples: ",samples)

就是这样,随时可以在评论区提问。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 5:49:52

PyTorch 2.8 + OpenCV实战:DAMO-YOLO手机检测图像预处理详解

PyTorch 2.8 OpenCV实战&#xff1a;DAMO-YOLO手机检测图像预处理详解 1. 引言&#xff1a;为什么图像预处理如此重要&#xff1f; 想象一下&#xff0c;你正在用手机拍照。光线不好、手抖了一下&#xff0c;或者背景太杂乱&#xff0c;拍出来的照片可能就模糊不清。对于人眼…

作者头像 李华
网站建设 2026/5/1 5:51:15

RexUniNLU模型API性能优化:QPS提升500%的实战技巧

RexUniNLU模型API性能优化&#xff1a;QPS提升500%的实战技巧 1. 为什么你的RexUniNLU服务跑不快&#xff1f; 刚部署好RexUniNLU模型&#xff0c;满怀期待地准备上线服务&#xff0c;结果一压测就发现QPS卡在个位数&#xff1f;API响应时间动辄几秒&#xff1f;别急&#xf…

作者头像 李华
网站建设 2026/5/1 5:49:55

霜儿-汉服-造相Z-Turbo部署实录:阿里云ECS+GPU实例从0到图生成全过程

霜儿-汉服-造相Z-Turbo部署实录&#xff1a;阿里云ECSGPU实例从0到图生成全过程 想亲手打造一位身着精美汉服的“霜儿”吗&#xff1f;今天&#xff0c;我将带你从零开始&#xff0c;在阿里云ECS的GPU实例上&#xff0c;一步步部署“霜儿-汉服-造相Z-Turbo”这个专为生成古风汉…

作者头像 李华
网站建设 2026/5/1 5:49:28

手把手教你用GTE+SeqGPT构建知识库检索系统

手把手教你用GTESeqGPT构建知识库检索系统 你是不是也遇到过这样的问题&#xff1a;想给公司内部文档、产品手册或者个人知识库加一个智能搜索功能&#xff0c;但发现传统的关键词搜索太笨了&#xff1f;比如你问“手机充电快不快”&#xff0c;它根本找不到“支持65W超级快充…

作者头像 李华
网站建设 2026/5/1 5:49:25

STM32CubeMX项目结构深度解析:Core/Drivers/Middleware/Startup四大分区

4.2 CubeMX生成项目的文件组成&#xff1a;深度解析STM32工程结构与代码组织逻辑在嵌入式开发实践中&#xff0c;一个清晰、可维护、可扩展的项目结构是工程稳定性的基石。STM32CubeMX作为ST官方提供的图形化配置与代码生成工具&#xff0c;其核心价值不仅在于简化外设初始化流…

作者头像 李华