原文towardsdatascience.com/simulated-data-real-learnings-power-analysis-652045eeae22https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/58847e217e3d294c5929b791e2342b49.png图片由 Pexels.com 的 Robert So 提供引言模拟是数据科学工具箱中的强大工具。阅读完这篇文章后您将很好地理解如何使用模拟来估计设计实验的功率。这是关于模拟在数据科学和机器学习中有用性的多部分系列的第二部分。下面是我们将要涵盖的内容功效分析概述如何使用模拟计算功率——基于示例的方法在这篇文章中我将只简要定义数据模拟数据模拟是创建模仿现实世界特性的虚构数据。在本系列的第一个部分我更详细地讨论了数据模拟的定义——您可以在下面的链接中查看模拟数据真实学习第一部分功效分析概述实验是我们了解周围世界关系的黄金标准。在计划实验时有许多考虑因素。尽管实验是黄金标准但一个计划不当的实验可能会产生无用或误导性的结果。功效分析是良好实验计划的一个关键组成部分。在深入细节之前让我们回答这个以价值为导向的问题问题为什么在运行实验之前估计功率很重要答案因为没有理解实验的功率我们可能会浪费时间在无法检测到有意义结果的实验上。在统计术语中功效的定义是正确拒绝零假设的概率。虽然不够精确并且特定于实验设计但我喜欢将实验的功效定义为——在存在关系的情况下我们能够捕捉到关系的概率。在实验中功率是在存在关系的情况下我们能够捕捉到关系的概率功率的计算是通过估计两种相互竞争的力量——1信号和2噪声来完成的。这两个变量的相对大小决定了我们能够多好地捕捉到趋势。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/16a4cc145b3cb827b3ab10932e5b21f8.png在计算功效时我们创建两个分布——一个分布的平均值为零解释为我们的实验变量与响应变量没有关系和另一个分布具有非零平均值解释为我们的变量与响应变量有正相关关系。请注意第一个分布对应于零假设第二个分布对应于备择假设。粗略地说功效与这两个分布之间的重叠程度成反比——即重叠越多功效越低重叠越少功效越高。我从文章的下方拉取了下面的图片。我将快速讲解这张图片然后转到这篇文章真正要讨论的内容——模拟如果你在阅读这一部分后对功效分析还有很多疑问不用担心互联网上不止我一个人写过关于它https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f5335d94c314e01592cea9595f809507.png图片由作者提供绿色分布是我们的零分布表示如果我们的实验变量和响应变量之间没有关系我们可能看到的估计关系值的概率分布。蓝色是另一种分布表示如果实验变量和响应变量之间的关系是一个正数可能的关系估计。红色线是零分布绿色前 5%的截止线。在这里我将跳过很多细节只说蓝色分布中红色线右侧的区域是功效。如果这还不清楚请记住谷歌是你的朋友 我们必须继续讨论这篇文章中的模拟如何使用模拟计算功效现在我们已经快速讨论了什么是功效让我们最终进入文章的核心内容——模拟如何帮助我们计算功效从而帮助我们设计更好的实验我非常喜欢通过例子学习所以在这个部分我的主要教学媒介将通过一个模拟例子进行。这里是场景你为一家广告公司工作该公司要求你估计一个特定设计实验的功效。这个实验试图了解广告策略对销售的影响。设计将国家分成多个子组并随机选择一个组进行广告活动另一个组作为对照组。由于这不是一篇关于实验设计的文章我们将做出简化的假设即我们决定采用简单的差分-差分DID方法进行分析我不会过多地深入这个方法——再次提醒谷歌是你的朋友。差分-差分方法将我们的数据分为四个组1前/控制2后/控制3前/测试和4后/测试。只有后/测试数据集将受到活动的直接影响其他三个数据集将不会收到任何活动的广告并将用于控制混杂因素。注意虽然我们在这个例子中选择了 DID 方法但我们仍然可以修改我们的代码/方法来计算任何分析方法的功率。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/187c29155e0a6fbf8ff165294b92b4f4.png差分-差分方法的数据分离 – 图像由作者提供为了估计我们测试的功率我们将运行两个模拟。模拟 1程序没有影响模拟 2程序具有我们设定的特定影响水平。第一个模拟对应于零假设活动对销售没有影响第二个模拟代表备择假设活动对销售有积极影响。每个模拟将为我们提供一个数据点在我们的特定情况下它将是 DID 计算。例如如果我们运行模拟 1 一次我们将从那个模拟中计算出 DID 值。下一步是多次运行这两个模拟以获得我们 DID 指标的两个分布。这两个分布就是我们估计功率所需的所有。然后我们根据分布的重叠部分进行功率计算。重叠越小功率越高反之亦然。下面是两个模拟对应的四个数据集的示意图。请注意当我们创建模拟 2 数据时我们将测试/后数据集的模拟影响标记为“simulate impact 0”设置为特定水平例如销售增加 5%。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e68bbe227e32e6394c67fb9a0d58ad76.pngbreak down of 2 types of simulations needed for power analysis既然我们已经了解了我们如何运行我们的模拟让我们开始编写一些 Python 代码来实际创建模拟数据并计算功率下面是如何将代码与我们刚才讨论的设置相联系https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bf1540dbf038984f811045a3601bd935.pngimportnumpyasnpfrommatplotlibimportpyplotaspltimportseabornassnsdefcalculate_diff_in_diff(pre_test,pre_control,post_test,post_control): Calculates the diff in diff given the 4 averages from the 4 data sets used to calculate diff in diff. inputs: pre_test (float) : average for the pre/test data pre_control (float) : average for the pre/control data pre_test (float) : average for the pre/test data post_control (float) : average for the post/control data output diff_in_diff_ratio (float) : diff in diff calculation test_diffpost_test-pre_test control_diffpost_control-pre_control diff_in_diff_ratiotest_diff-control_diffreturndiff_in_diff_ratiodefsimulate_group_data(n_customers,rv_dist_func,rv_inputs,program_impact0): Simulates a single dataset for diff in diff simulation inputs: n_customers (int) : number of customers to be simulated in the dataset rv_dist_func (func) : function used to sample random variables rv_inputs (dict) : keyword inputs to the rv_dist_func program_impact (float) : additive impact that program has on probability of customer purchasing. Should only be non-zero for post/test data default 0 output: purch_rate (float) : average purchase rate (total purchs / total custs) for the simulated data set purch_probrv_dist_func(**rv_inputs,sizen_customers)# add impact of treatment if simulating post/test datapurch_probprogram_impact# convert to binaryconv_to_binary_probnp.random.uniform(0,1,n_customers)purch_binarynp.where(purch_probconv_to_binary_prob,1,0)purch_ratenp.sum(purch_binary)/len(purch_binary)returnpurch_ratedefsimulate_multiple_times(n_sims,pre_test_sim_inputs,post_test_sim_inputs,pre_control_sim_inputs,post_control_sim_inputs,cut_off_decimal0.05): Uses functions that run a single simulation to run multiple simulation - aggregates the results of the multiple simulations inputs: n_sims (int) : number of simulations to run pre_test_sim_inputs (dict) : keyword args for running a single pre/test simulation post_test_sim_inputs (dict) : keyword args for running a single post/test simulation pre_control_sim_inputs (dict) : keyword args for running a single pre/control simulation post_control_sim_inputs (dict) : keyword args for running a single post/control simulation cut_off_decimal (float) : decimal form of significance level for power analysis, e.g. 5% 0.05 default 0.05 outputs: Nothing, but prints power at a significance level set with the cut_off_decimal input and creates visualization of the null and alternative histograms diff_in_diff_impact[]# run with given impact for interventionforiinrange(n_sims):pre_test_simsimulate_group_data(**pre_test_sim_inputs)post_test_simsimulate_group_data(**post_test_sim_inputs)pre_control_simsimulate_group_data(**pre_control_sim_inputs)post_control_simsimulate_group_data(**post_control_sim_inputs)temp_diff_in_diffcalculate_diff_in_diff(pre_test_sim,pre_control_sim,post_test_sim,post_control_sim)diff_in_diff_impact.append(temp_diff_in_diff)# run w/o any impact for interventiondelpost_test_sim_inputs[program_impact]diff_in_diff_no_impact[]foriinrange(n_sims):pre_test_simsimulate_group_data(**pre_test_sim_inputs)post_test_simsimulate_group_data(**post_test_sim_inputs)pre_control_simsimulate_group_data(**pre_control_sim_inputs)post_control_simsimulate_group_data(**post_control_sim_inputs)temp_diff_in_diffcalculate_diff_in_diff(pre_test_sim,pre_control_sim,post_test_sim,post_control_sim)diff_in_diff_no_impact.append(temp_diff_in_diff)# print power calculation resultcutoff1-cut_off_decimal cutoff_indexint(len(diff_in_diff_no_impact)*cutoff)sorted_datasorted(diff_in_diff_no_impact)top_5_percent_cutoffsorted_data[cutoff_index]# calculate powerreject_region_indnp.where(diff_in_diff_impacttop_5_percent_cutoff,1,0)power1-np.sum(reject_region_ind)/len(reject_region_ind)print(fpower for scenario specifics is{power})# Kernel density estimation (KDE) to estimate the PDFssns.kdeplot(diff_in_diff_impact,colorblue,labelsimulated impact,fillTrue)sns.kdeplot(diff_in_diff_no_impact,colorgreen,labelno impact,fillTrue)plt.axvline(xtop_5_percent_cutoff,colorred,linestyle--)# Plot settingsplt.xlabel(Difference in Differences)plt.ylabel(Probability Density)plt.title(No Impact vs. Simulated Impact)plt.legend()plt.show()return# running simulations# set up sample sizestest_n_customers1500control_n_customers1500# set inputs for the four needed data setspre_test_sim_inputs{n_customers:test_n_customers,rv_dist_func:np.random.uniform,rv_inputs:{low:0,high:0.60}}post_test_sim_inputs{n_customers:test_n_customers,rv_dist_func:np.random.uniform,rv_inputs:{low:0,high:0.60},program_impact:0.10}pre_control_sim_inputs{n_customers:control_n_customers,rv_dist_func:np.random.uniform,rv_inputs:{low:0,high:0.80}}post_control_sim_inputs{n_customers:control_n_customers,rv_dist_func:np.random.uniform,rv_inputs:{low:0,high:0.80}}# run multiple simulationssimulate_multiple_times(1000,pre_test_sim_inputs,post_test_sim_inputs,pre_control_sim_inputs,post_control_sim_inputs)在上面的代码中我们运行了两个模拟 1000 次。如果我们模拟 5%的影响这意味着我们的程序使客户增加购买概率的可能性提高了 5%并且样本大小为 1500 名客户我们得到以下结果。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f5335d94c314e01592cea9595f809507.pngimage by author红线代表绿色“无影响”分布对应模拟 1 的分布的最高 5%的截止点。在 5%的显著性水平下样本量为 1500影响大小为 5%我们的功效约为 63%——这意味着在模拟条件下我们有 63%的几率会得出项目存在差异的结论。63%是蓝色分布中位于红线右侧的百分比。从这里模拟在功效分析中的魔力显现出来63%的功效相当低。幸亏我们在实施实验之前检查了使用我们的框架我们现在可以探索如何解决低功效问题。有两种非平凡的方法可以增加功效——1增加样本量以及2增加测试的影响。让我们来看看两者我们将样本量从 1500 增加到 3000。这在代码中做起来很简单# set up sample sizes for test and controltest_n_customers3000control_n_customers3000https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1a7a72f0444925380be341ee843ad760.png作者图片现在我们的功效约为 91%我们可以在设计的实验中通过延长实验时间或增加将要包括在测试中的地理区域来实施样本量的增加。根据我们的功效分析鉴于当前样本量的较低功效我们绝对应该做其中之一。第二种方法——增加影响大小——不那么直接。我们实际上只能在这个方向上产生一定的影响。如果我们知道如何精确地改变影响大小我们就不需要运行测试因为我们就会理解我们的实验变量和响应变量之间的关系如果我们想增加影响大小我们必须提高处理水平——在这个例子中这意味着更激进的广告活动。我们知道如果销售和活动之间存在关系增加活动的预算可能会增加项目的效果。但同样我们不知道在更加强烈的活动下影响会变得多大——我们只知道它会更大。我们可以通过模拟不同的影响水平来了解我们的功效是如何随着影响的增加而改变的。下表显示了与不同模拟影响水平相对应的功效水平。这可以帮助我们了解在不同水平上的信心。如果活动的影响小于 5%我们不太可能检测到它。如果这不是可以接受的我们要么增加样本量以减少噪声要么提高活动水平使其更有可能观察到更高的影响。我们可以将这样的表格拿给我们的利益相关者确保每个人都理解测试可能检测到的不同影响水平。如果每个人都接受检测不到5%影响的低概率那么我们可以继续前进。如果不可以我们可以修改实验设计。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/906f8f043aab432c871904c5ff6ab274.png模拟影响的力量 - 图片由作者提供遵循这个模拟过程我们假设的自我现在已经准备好做出一个明智的实验设计决策了我们有了理解需要包含多少客户才能捕捉到一定水平功率的工具。我们还了解给定一定数量的客户我们检测到各种规模趋势的可能性有多大。这一切都归功于模拟结论模拟可以是一个极其有用的工具用于计算实验的功率。它不依赖于特定方法无论是差异分析还是回归或传统假设检验它都能很好地工作。我们可以从使用模拟进行功率分析中获得非常有用的关键见解。我们可以了解我们需要多大的样本量想象一下如果我们创建了一个测试并且样本量太小或太大会有多大的浪费以及我们需要达到什么程度的影响才能检测到它。通过功率模拟计算我们可以极大地提高我们实验的质量以及我们从实验中获得的学习成果