原文:
towardsdatascience.com/mastering-sample-size-calculations-75afcddd2ff3?source=collection_archive---------6-----------------------#2024-10-09
A/B 测试、拒绝推断以及如何为实验获取正确的样本大小
https://medium.com/@lucasbraga461?source=post_page---byline--75afcddd2ff3--------------------------------https://towardsdatascience.com/?source=post_page---byline--75afcddd2ff3-------------------------------- Lucas Braga
·发表于 Towards Data Science ·阅读时间 17 分钟·2024 年 10 月 9 日
–
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1a94f5016a3129b52d57233ef1ea9dbd.png
图片由作者制作
针对不同的场景,有不同的统计公式。首先要问的问题是:你是在比较两组数据,比如在A/B 测试中,还是在从一个足够大的群体中选择样本,以使其能够代表该群体?
后者通常用于像交易中的保留组这样的场景。这些保留组对于评估欺诈预防规则的性能或拒绝推断非常关键,在这种情况下,欺诈检测的机器学习模型会重新训练。保留组的优势在于,它包含了没有被任何规则或模型阻止的交易,从而提供了一个不偏不倚的性能视角。然而,为了确保保留组具有代表性,你需要选择一个能准确反映群体的样本大小,这一点将在本文中与 A/B 测试的样本大小一起探讨。
在确定是否比较两组(如 A/B 测试)或选择一个代表性样本(如拒绝推断)之后,下一步是定义你的成功指标。**它是一个比例还是一个绝对数值?**例如,比较两个比例可能涉及转化率或违约率,其中违约交易的数量除以交易总数。另一方面,比较两个均值适用于处理绝对值的情况,比如总收入或 GMV(商品交易总值)。在这种情况下,你会比较每个客户的平均收入,假设你的实验中存在客户级别的随机化。
1. 比较两组(例如 A/B 测试)——样本大小
第 1.1 节是关于比较两个均值的,但这里提出的大多数原理在第 1.2 节中也适用。
1.1. 比较两个均值(度量绝对数值的平均值)
在这种情况下,我们比较两个组:一个控制组和一个处理组。控制组由通过借贷计划获得 100 欧元信用额度的客户组成,而处理组由通过同一计划获得 200 欧元信用额度的客户组成。
实验的目标是确定是否增加信用额度会导致客户支出增加。
我们的成功度量定义为每位客户每周的平均支出金额,以欧元为单位。
在确立目标和成功度量后,在典型的 A/B 测试中,我们还会定义假设、随机化单元(在本例中为客户)以及目标人群(获得信用的新客户)。然而,由于本文的重点是样本量,我们将在这里不讨论这些细节。
我们将比较控制组和处理组之间的每位客户每周的平均支出。接下来,我们将使用以下脚本来计算这个度量:
脚本 1:计算成功度量,分支:德国,周期:2024 年 5 月 1 日至 2024 年 7 月 31 日。
WITH customer_spending AS(SELECT branch_id,FORMAT_DATE('%G-%V',DATE(transaction_timestamp))AS week_of_year,customer_id,SUM(transaction_value)AS total_amount_spent_eur FROM `project.dataset.credit_transactions` WHERE1=1AND transaction_date BETWEEN'2024-05-01'AND'2024-07-31'AND branch_id LIKE'Germany'GROUP BY branch_id,week_of_year,customer_id),agg_per_week AS(SELECT branch_id,week_of_year,ROUND(AVG(total_amount_spent_eur),1)AS avg_amount_spent_eur_per_customer,FROM customer_spending GROUP BY branch_id,week_of_year)SELECT*FROM agg_per_week ORDER BY1,2;在结果中,我们观察到每周的度量avg_amount_spent_eur_per_customer。在过去的四周里,数值保持相对稳定,介于 35 欧元和 54 欧元之间。然而,考虑到过去两个月的所有周,方差较大。(请参见图像 1 作为参考。)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/279deef453754e038e447a2186f57ef8.png
图像 1:脚本 1 的结果。
接下来,我们计算成功度量的方差。为此,我们将使用脚本 2来计算所有周的方差和平均值。
脚本 2:查询计算成功度量的方差,并计算所有周的平均值。
WITH customer_spending AS(SELECT branch_id,FORMAT_DATE('%G-%V',DATE(transaction_timestamp))AS week_of_year,customer_id,SUM(transaction_value)AS total_amount_spent_eur FROM `project.dataset.credit_transactions` WHERE1=1AND transaction_date BETWEEN'2024-05-01'AND'2024-07-31'AND branch_id LIKE'Germany'GROUP BY branch_id,week_of_year,customer_id),agg_per_week AS(SELECT branch_id,week_of_year,ROUND(AVG(total_amount_spent_eur),1)AS avg_amount_spent_eur_per_customer,FROM customer_spending GROUP BY branch_id,week_of_year)SELECT ROUND(AVG(avg_amount_spent_eur_per_customer),1)AS avg_amount_spent_eur_per_customer_per_week,ROUND(VAR_POP(avg_amount_spent_eur_per_customer),1)AS variance_avg_amount_spent_eur_per_customer FROM agg_per_week ORDER BY1,2;脚本 2的结果显示方差约为 145.8(请参见图像 2)。此外,考虑到过去两个月的所有周,每位用户的平均消费金额为49.5 欧元。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/64278faf0614a71b9041fb7f28ac45ad.png
图像 2:脚本 2 的结果。
现在我们已经计算出度量并发现每位客户的平均每周支出约为49.5 欧元,我们可以定义最小可检测效应(MDE)。鉴于信用从 100 欧元增加到 200 欧元,我们旨在检测10%的支出增加,这相当于每位客户每周的新的平均值为54.5 欧元。
计算方差(145.8)并确定 MDE 后,我们可以将这些值代入公式中,计算所需的样本量。我们将使用默认值alpha(5%)和beta(20%):
显著性水平(Alpha 的默认值为α = 5%):Alpha 是一个预定的阈值,用作拒绝零假设的标准。Alpha 是 I 类错误(假阳性),p 值需要低于 Alpha,才能拒绝零假设。
统计功效(Beta 的默认值为β = 20%):这是测试在替代假设为真时正确拒绝零假设的概率,即在效应存在时检测到效应。统计功效 = 1 — β,β是 II 类错误(假阴性)。
这是计算在典型的 A/B 测试场景中每组(对照组和治疗组)所需样本量的公式:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3319033fd8fc46b6a2bfc7d696caa84f.png
图像 3:计算比较两个均值时样本量的公式。
n是每组的样本量。
σ²是正在测试的度量的方差(在本例中为145.8)。因子 2σ²被使用,因为我们计算的是合并方差,这样在比较两个样本时不会产生偏差。
δ(德尔塔)表示最小可检测的均值差异(效应大小),即我们希望检测的变化。其计算公式为:δ² = (μ₁ — μ₂)²,其中μ₁是对照组的均值,μ₂是治疗组的均值。
Zα/2是与相应置信水平对应的z 值(例如,1.96对应于95%置信水平)。
Zβ是与所需测试功效相关的z 值(例如,0.84对应于80%功效)。
n=(2*145.8*(1.96+0.84)²)/(54.5-49.5)²->n=291.6*7.84/25->n=2286.1/25->n=~92在我的网页应用程序计算器中尝试,样本量计算器,如应用截图 1所示:
置信水平:95%
统计功效:80%
方差:145.8
需要检测的差异(德尔塔):5(因为预期的变化是从€49.50 到€54.50)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/713d7337eda7cae42862e030b17ae896.png
应用截图 1:计算比较两个均值的样本量。
根据之前的计算,我们需要92 个用户在对照组中,92 个用户在治疗组中,总共需要184 个样本。
现在,让我们探讨一下改变最小可检测效应(MDE)如何影响样本量。较小的 MDE 需要更大的样本量。例如,如果我们希望检测每个用户平均€1 的增加,而不是之前使用的€5 的增加(10%),所需的样本量将显著增加。
MDE 越小,测试需要越敏感,这意味着我们需要更大的样本量才能可靠地检测到如此微小的效应。
n=(2*145.8*(1.96+0.84)²)/(50.5-49.5)²->n=291.6*7.84/1->n=2286.1/1->n=~2287我们将以下参数输入到样本量计算器的网页应用程序计算器中,如应用截图 2所示:
置信水平:95%
统计功效:80%
方差:145.8
需要检测的差异(德尔塔):1(因为预期的变化是从€49.50 到€50.50)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/dadc8ff02400ac38d2c7af78ab2fb1f8.png
应用截图 2:计算 Delta = 1 时比较两个均值的样本量。
为了检测更小的效应,例如每个用户增加 1 欧元,我们需要2,287 个用户在对照组,2,287 个用户在处理组,总共需要4,574 个样本。
接下来,我们将调整统计功效和显著性水平,重新计算所需的样本量。但首先,让我们看一下z 值表,以了解如何推导出z 值。
我们已经设置了β = 0.2,这意味着当前的统计功效为80%。参考 z 值表(见图像 4),这对应于z 值为 0.84,这是我们之前公式中使用的值。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0e6df69db82894b33b17d0e9ac808d5f.png
图像 4:在 z 值表中查找统计功效为 80% 时的 z 值。
如果我们现在将β值调整为 10%,即统计功效为 90%,我们将得到z 值为 1.28。该值可以在 z 值表中找到(见图像 5)。
n=(2*145.8*(1.96+1.28)²)/(50.5-49.5)²->n=291.6*10.49/1->n=3061.1/1->n=~3062通过调整β值为 10%(统计功效为 90%)并使用z 值为 1.28,我们现在需要3,062 个用户在对照组和处理组中,每组总共6,124 个样本。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a6d036fdb714dd539fce84c0d01c07e0.png
图像 5:在 z 值表中查找统计功效为 90% 时的 z 值。
现在,让我们来确定6,124 个样本所代表的流量。我们可以通过计算每周不同客户的平均交易量来得出这个数据。脚本 3将帮助我们获取2024 年 5 月 1 日到 2024 年 7 月 31 日期间的信息。
脚本 3:计算不同客户每周平均交易量的查询。
WITH customer_volume AS(SELECT branch_id,FORMAT_DATE('%G-%V',DATE(transaction_timestamp))AS week_of_year,COUNT(DISTINCT customer_id)AS cntd_customers FROM `project.dataset.credit_transactions` WHERE1=1AND transaction_date BETWEEN'2024-05-01'AND'2024-07-31'AND branch_id LIKE'Germany'GROUP BY branch_id,week_of_year)SELECT ROUND(AVG(cntd_customers),1)AS avg_cntd_customers FROM customer_volume;脚本 3的结果显示,平均每周有185,443 个不同客户(见图像 5)。因此,6,124 个样本大约占总每周客户基数的3.35%。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c2bdc30698591acd5f31b814526e949e.png
图像 5:脚本 3 的结果。
1.2. 比较两个比例(例如转化率、违约率)
虽然前一节讨论的大多数原则保持不变,但比较两种比例的公式有所不同。这是因为,我们不再预先计算指标的方差,而是将重点放在每个组的预期成功比例上(见图像 6)。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d8c43c36156bef1324aebd54ec2e8021.png
图像 6:计算比较两种比例的样本量的公式。
让我们回到相同的场景:我们正在比较两个组。对照组由可以获得100 欧元信贷的客户组成,信贷借款计划中的处理组由可以获得200 欧元信贷的客户组成。
这次,我们关注的成功指标是违约率。这可能是1.1 节中讨论的同一个实验的一部分,其中违约率作为护栏指标,也可能是完全独立的实验。无论是哪种情况,假设是给予客户更多信用可能会导致更高的违约率。
本次实验的目标是确定信用额度的增加是否会导致更高的违约率。
我们将成功指标定义为实验周内所有客户的平均违约率。理想情况下,实验应持续更长时间以收集更多数据,但如果无法实现这一点,选择一个没有偏差的星期就显得尤为重要。你可以通过分析过去12 到 16 周的违约率来验证这一点,从中找出与某些月份的特定星期相关的模式。
让我们来查看数据。脚本 4将显示每周违约率,结果可以在图像 7中看到。
脚本 4:查询以获取每周违约率。
SELECT branch_id,date_trunc(transaction_date,week)AS week_of_order,SUM(transaction_value)AS sum_disbursed_gmv,SUM(CASE WHEN is_completed THEN transaction_value ELSE0END)AS sum_collected_gmv,1-(SUM(CASE WHEN is_completed THEN transaction_value ELSE0END)/SUM(transaction_value))AS default_rate,FROM `project.dataset.credit_transactions` WHERE transaction_date BETWEEN'2024-02-01'AND'2024-04-30'AND branch_id='Germany'GROUP BY1,2ORDER BY1,2;从违约率指标来看,我们注意到一些波动,尤其是在较早的几周,但过去 5 周的违约率相对稳定。过去 5 周的平均违约率为0.070。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/acfeee9cf1209936b699b73877b1e6a1.png
图像 7:每周违约率的结果。
现在,假设这个违约率代表了对照组。那么下一个问题是:在处理组中,什么样的违约率会被认为是不可接受的?我们可以设定一个阈值:如果处理组的违约率增加到0.075,就会被认为过高。然而,任何低于0.0749的违约率仍然是可以接受的。
违约率为0.075意味着相较于对照组的0.070,增加了大约7.2%。这个差异——7.2%——是我们的最小可检测效应 (MDE)。
有了这些数据点,我们现在可以计算所需的样本大小。
n=(((1.96+0.84)²)*((0.070*(1-0.070)+0.075*(1-0.075)))/((0.070-0.075)²)->n=7.84*0.134475/0.000025->n=1.054284/0.000025->n=~42,171我们将以下参数输入到样本大小计算器的网页应用程序中,如应用截图 3所示:
置信水平:95%
统计功效:80%
第一次比例 (p1):0.070
第二次比例 (p2):0.075
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b4b40f485edaa98373743b979f70ec20.png
应用截图 3:计算比较两种比例的样本大小。
为了检测违约率的7.2%增长(从0.070到0.075),我们需要在对照组和处理组中各有42,171 个用户,因此总样本数为84,343 个。
样本大小为84,343相当大!我们可能甚至没有足够的客户来进行这个分析。但让我们探讨一下为什么会这样。我们没有改变alpha和beta的默认参数,这意味着我们将显著性水平保持在默认的5%,并将统计功效保持在默认的80%。正如我们之前讨论过的,我们本可以通过选择较低的显著性水平来减少假阳性的机会,或者我们可以提高统计功效来最小化假阴性的风险。
那么,是什么导致了如此大的样本量?是7.2%的 MDE吗?简短的回答是:不完全是。
考虑这种替代情境:我们保持相同的显著性水平(5%)、统计功效(80%)和MDE(7.2%),但假设默认比例(p₁)是0.23(23%)而不是0.070(7.0%)。在7.2%的 MDE下,治疗组的新的默认比例(p₂)将是0.2466(24.66%)。注意,这仍然是7.2%的 MDE,但比例明显高于0.070(7.0%)和0.075(7.5%)。
现在,当我们使用这些新的值p₁ = 0.23和p₂ = 0.2466进行样本量计算时,结果会有所不同。接下来,我们来计算一下。
n=(((1.96+0.84)²)*((0.23*(1-0.23)+0.2466*(1-0.2466)))/((0.2466-0.23)²)->n=7.84*0.3628/0.00027556->n=2.8450/0.00027556->n=~10,325使用新的默认比例(p₁ = 0.23和p₂ = 0.2466),我们在对照组和治疗组中各需要10,325 个用户,总共需要20,649 个样本。与之前的 84,343 样本相比,这样的样本量更加可管理。然而,值得注意的是,这种情况下的默认比例处于完全不同的范围。
关键的结论是,较低的成功率(如接近7%的默认比例)需要更大的样本量。当比例较小的时候,检测到即使是适度的差异(比如 7.2%的增长)也变得更加困难,因此需要更多的数据才能实现相同的统计功效和显著性水平。
2. 抽样一个群体
这个案例与 A/B 测试场景有所不同,因为我们现在专注于从单一群体中确定样本量。目标是选取一个能够准确代表群体的样本,从而进行分析并推断结果,进而估算整个群体可能发生的情况。
即使我们不在比较两个群体,从群体中抽样(一个群体)仍然需要决定你是在估算均值还是比例。这两种情况的公式与 A/B 测试中使用的公式非常相似。
看一下图像 8和图像 9。当你将图像 8与图像 3(比较两个均值的样本量公式)进行对比,或者将图像 9与图像 6(比较两个比例的样本量公式)进行对比时,你是否注意到了相似之处?它们确实非常相似。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5eda2848fc5b628130f111cc12b69c25.png
图像 8:用于估算总体均值的样本量公式。
在估算均值的情况下:
从图像 8 中,抽样自单一组的公式则使用了E,表示误差。
从图像 3 中,比较两组的公式使用了delta (δ)来比较两者均值之间的差异。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/60be487bef3d722c56c371ad2c62b607.png
图像 9:用于估算总体比例的样本量公式。
在估算比例的情况下:
从图像 9 可以看出,单组抽样的比例公式也使用了E,代表误差。
从图像 6 中,比较两组的公式使用了MDE(最小可检测效应),类似于差值,用于比较两种比例之间的差异。
那么,我们什么时候使用这些公式呢?让我们探讨两个实际例子——一个用于估算均值,另一个用于估算比例。
2.1. 抽样总体 — 估算均值
假设你希望更好地评估欺诈风险,为此,你打算估算每个国家每周的欺诈交易平均订单值。这可能相当具有挑战性,因为理想情况下,大多数欺诈交易已经被阻止。为了获得更清晰的图像,你将采用一个保留组,它不受任何规则和模型的影响,作为计算欺诈交易的真实平均订单值的参考。
假设你选择了一个特定的国家,并在回顾历史数据后发现:
该指标的方差为€905。
欺诈交易的平均订单值为€100。
(你可以参考脚本 1 和 2来计算成功指标和方差。)
由于方差为€905,标准差(方差的平方根)约为€30。现在,使用5%的显著性水平,对应的z-score 为 1.96,并假设你能接受10%的误差范围(代表€10的误差,或是€100 的 10%),那么在 95%的置信区间下,意味着在正确的样本量下,你可以95%的置信度断言平均值落在€90 到€110之间。
现在,将这些输入值代入样本量公式:
n=((1.96*30)/10)²->n=(58.8/10)²->n=35我们将以下参数输入到网页应用计算器中,在样本量计算器中,如应用截图 4所示:
置信水平:95%
方差:905
误差:10
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/372ea787d2fa0e5d445df9000f6a8d38.png
应用截图 4:在抽样一个总体时,计算估算均值的样本量。
结果是,你需要35 个样本来估算每个国家每周的欺诈交易平均订单值。然而,这还不是最终的样本量。
由于欺诈交易相对较少,你需要调整欺诈交易的比例。如果欺诈交易的比例为1%,那么你需要收集的实际样本数量为:
n=35/0.01->n=3500因此,你需要 3,500 个样本,以确保欺诈交易得到适当的代表。
2.2. 抽样总体——估计一个比例
在这种情况下,我们的欺诈规则和模型已经阻止了大量交易。为了评估我们的规则和模型的效果,我们需要让一部分流量绕过规则和模型,以便评估实际的假阳性率。这部分未经过滤的交易被称为留存组。这是欺诈数据科学团队中的常见做法,因为它既能评估规则和模型的表现,又能将留存组用于拒绝推断。
尽管我们在这里不会详细讨论拒绝推断,但值得简要总结一下。拒绝推断涉及使用未被阻止的交易的留存组数据,学习有助于改进交易阻止决策的模式。对此有多种方法,其中模糊增强是一种流行的方法。其基本思路是使用留存组的数据重新标记之前被拒绝的交易,并用这些数据训练新的模型。在欺诈建模中,这尤其重要,因为欺诈率通常较低(通常低于 1%,有时甚至低于 0.1%)。增加标记数据可以显著提升模型表现。
现在我们明白了估计比例的需求,接下来我们将深入探讨一个实际应用案例,看看需要多少样本。
对于某一分支,你分析历史数据发现该分支每月处理50,000,000 个订单,其中50,000 个订单是欺诈的,导致0.1%的欺诈率。使用5%的显著性水平(alpha)和25%的误差范围,我们旨在估计真实的欺诈比例,置信区间为95%。这意味着,如果真实的欺诈率为0.001(0.1%),我们估计的范围应在0.00075和0.00125之间,错误为0.00025。
请注意,误差范围(margin of error)和错误(Error)是两个不同的概念,误差范围是一个百分比值,而错误是一个绝对值。在欺诈率为 0.1%的情况下,如果我们的误差范围是 25%,那么它代表的错误为 0.00025。
让我们应用公式:
Zα/2= 1.96(95%置信水平的 z 值)
E= 0.00025(错误)
p= 0.001(欺诈率)
Zalpha/2=1.96->(Zalpha/2)²=3.8416E=0.00025->E²=0.0000000625p=0.001n=(3.8416*0.001*(1-0.001))/0.0000000625->n=0.0038377584/0.0000000625->n=61,404我们在样本大小计算器的网页应用程序中输入以下参数,如应用截图 5所示:
Confidence Level: 95%
Proportion: 0.001
Error: 0.00025
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1b45a66985a09866e1bc154afe9004be.png
应用截图 5:计算估算比例的样本大小,当从一个总体中抽样时。
因此,共需 61,404 个样本。假设一个月内有50,000,000 笔交易,如果保留组代表100%的流量,收集这些样本将花费不到 1 小时。然而,这对于一个可靠的实验来说并不现实。
相反,你应该将流量分布到几天,以避免季节性问题。理想情况下,你应收集至少一周的数据,确保覆盖所有工作日,并避免假期或高峰季节。如果你需要在一周内收集61,404 个样本,那么你需要每天收集8,772 个样本。由于每日流量约为1,666,666 个订单,保留组每天需要代表0.53%的总交易量,并持续一周。
最后的备注
如果你想在 Python 中执行这些计算,以下是相关的函数:
importmathdefsample_size_comparing_two_means(variance,z_alpha,z_beta,delta):returnmath.ceil((2*variance*(z_alpha+z_beta)**2)/(delta**2))defsample_size_comparing_two_proportions(p1,p2,z_alpha,z_beta):numerator=(z_alpha+z_beta)**2*((p1*(1-p1))+(p2*(1-p2)))denominator=(p1-p2)**2returnmath.ceil(numerator/denominator)defsample_size_estimating_mean(variance,z_alpha,margin_of_error):sigma=variance**0.5returnmath.ceil((z_alpha*sigma/margin_of_error)**2)defsample_size_estimating_proportion(p,z_alpha,margin_of_error):returnmath.ceil((z_alpha**2*p*(1-p))/(margin_of_error**2))下面是如何计算与第 1.1 节中应用截图 1 类似的两组均值比较的样本量:
variance=145.8z_alpha=1.96z_beta=0.84delta=5sample_size_comparing_two_means(variance=variance,z_alpha=z_alpha,z_beta=z_beta,delta=delta)# OUTPUT: 92这些功能也可以在 GitHub 仓库中找到:GitHub 样本大小计算器,你还可以在那里找到交互式样本大小计算器的链接。
免责声明:与 Google BigQuery 作业结果相似的图像由作者创建。所示数字并非基于任何商业数据,而是为了说明目的手动生成的。SQL 脚本也是如此——它们并非来自任何企业,也都是手动生成的。然而,它们旨在与使用Google BigQuery作为框架的公司可能遇到的情况高度相似。
- 该计算器使用 Python 编写,并在 Google Cloud Run(无服务器环境)中通过 Docker 容器和 Streamlit 部署,参考请见GitHub 上的代码。