AB测试实战

AB测试实战

1、AB测试介绍🐾

  • 很多网站/APP的首页都会挂一张头图(Banner),用来展示重要信息,头图是否吸引人会对公司的营收带来重大影响,一家寿险公司Humana设计了如下三张头图,现在需要决定使用哪一张放到首页,怎么办?开会讨论?举手表决还是领导拍板?

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • AB测试:以“对照”知“优劣”

    • AB测试主要应用于互联网行业,它通过对相同特征的互联网用户(流量)在同一时间内实施两种不同的策略。来观察每组流量在关键目标指标上的表现。从而找出表现更优的策略。并凭借实验结果对策略和人群展开交叉分析,得到洞察

    • 无论是添加功能,头图替换,还是添加新的按钮,使用了新的推荐算法,所有可能会对业务造成影响的主动调整最好都要经过AB测试

    • 在上面的Humana公司的例子中,头图的迭代就是使用了AB测试

      • 第一张图是最初的版本,第二张设计图在第一张的基础上,减少了文字描述,换了更大的按钮,
      • 在第二张图片的基础上又做了新的迭代,设计了第三张图片,主要的变化调整了按钮的;颜色和文字内容,添加了Shop这样带有明显销售倾向的词语
      • 两次迭代的决定都是基于AB测试的结果,经过AB测试验证后上线都得到了很好的效果
1.1 AB测试的关键点:目标KPI和策略
  • 目标KPI:指评判AB测试效果优劣的最终指标

    • 在Humana公司首页头图调整的例子中,目标KPI是该头图的点击率
  • 策略:AB组分别采取的策略的差异点

    • 如:注册按钮采用的颜色,位置,注册页面采用的海报,标语等
    • 有多少个差异点,就可以设计多少次AB测试,直到穷尽策略差异点后找出最有效的那一组策略。
    • 只要分流量的时候做到随机,那么AB组人群的特征就是类似的,因此最终结果的差异只能是策略不同造成的。
1.2 AB测试的作用
  • 实现目标KPI的最大化:通过在小样本用户中进行实验(避免错误决策影响用户体验),找到对KPI最优的策略

    • Humana公司的头图调整例子中,第二张图片对比第一张带来了433%的点击率提升
    • 第三张图片对比第二张有带来了192%的点击率提升
  • 后续分析,沉淀诀窍:

    • 每组流量都是随机分配的,因此每组人群中都包含了各种不同特征的子人群
    • 通过研究不同子人群对于不同策略的响应程度,可以获得每组人群在策略上的偏好,帮助未来更好的个性化创新和设计
    • 从上面的例子中,我们可以得出一些有意的结论,
      • 如头图文字不易过多,要主题突出, 文字简洁
      • 头图使用的按钮颜色, 红色更容易吸引人点击等
1.3 AB测试实施的一般步骤

在这里插入图片描述

严谨的产品迭代过程(策略,算法, 界面调整, 功能调整), 一定要先经过AB测试, 在少部分流量上进行测试, 没问题了再逐渐放量

  • 明确KPI 提升转化率, 提升点击率, 提升分享率
  • 圈人, 通过假设检验确定足够的实验人数
    • 通过目标KPI提升多少, 确定实验人数
  • AA 测试 : 确定圈人没圈跑偏(量组流量的组成类似)
    • 实验组和对照组在AA测试后, 观察目标KPI 没有太大的区别
  • AB测试: 对照组看老产品, 给测试组看新的产品
  • 回收结果,分析
    • 如果B组确实比A组好, 并且达到了圈人时设定的目标KPI 说明新设计有效的
    • 如果B组确实比A组好, 但是提升幅度有限, 没有达到圈人时设定的目标KPI 的提升度, 说明这个提升没有说服力, 不能证明新的设计有效
    • A组比B组好, 新的设计不行

2、AB测试常见问题和应对方案🐾

2.1 如何分配流量🐣

一般采用A组B组人数相等的方法进行流量分配

常用的分流方法

  • 利用随机数排序,例如My SQL中的 rand()函数
select a.*,case when rand()<0.1 then 'ctrl'
when rand() between 0.1 and 0.55 then 'test1' else 'test2' end as ab_group_tag
from (select distinct customerID from user_table) a
order by ab_group_tag;
  • 利用某些随机ID的尾数,例如case when ID like ‘%1’then ‘Ctrl’else ‘Test’end as AB_group
select a.*,case when customerID like '1%' then 'ctrl'
when customerID like '2%' or customerID like '3%' or customerID like '4%' or customerID like '5%' then 'test1'
else 'test2' end as ab_group_tag
from(select distinct customerID from user_table) a 
order by ab_group_tag;
  • 不管用哪种方法都要在人群身上留好标签以便事后分析
2.2 确定试验有效的最小参与人数🐣
  • AB测试的效果会一定程度上受到随机波动的影响

    • 完全随机的两组人不发优惠券,观察同一段时间的人均交易数,人均交易额这些KPI,都不会完全一样
    • 为了使测试结果显著有效,我们首先要确保测试组里人数最少的一组达到验证效果有效性的最小样本数量
  • 帮助计算样本量的网站:https://www.evanmiller.org/ab-testing/sample-size.html

    • 首先介绍比例类的KPI,例如领券率,点击率,核销率的样本量计算方式:我们以基准率10%,需要探知最低效果2%为例:

    在这里插入图片描述

    • Baseline conversion rate: 这里填写基准比率 10%
    • Minimum Detectable Effect:这里填写最低的可探知效果2%
    • Significance level α:显著性水平 一般选择5%
    • Statistical power 1−β:统计功效(statistical power )一般选择80%
  • 经过计算得知,我们想通过AB测试确定新的策略能够将KPI提升两个点参数实验的每组人数最少为3623人

2.3 AB测试中的假设检验🐾

为什么要计算参与AB测试的最少参与人数🐣

  • 我们做AB测试的目的是在尽量不影响用户体验的前提下,让少部分用户来验证新旧方案的优劣。这里就需要对用户进行抽样, 也就是抽取部分用户来代表全体用户来参与实验,并得出结论
    • 如果抽取的用户数量过少,不能代表所有用户的观点,结果没有意义
    • 如果抽取的用户过多,一旦我们的新方案与预期效果偏差较大则会对用户体验带来较大影响
  • 我们可以使用假设检验的理论帮助我们计算参与实验的最少人数

什么是假设检验?

假设检验(hypothesis testing),又称统计假设检验,是用来判断样本与样本、样本与总体的差异是由抽样误差引起还是本质差别造成的统计推断方法。显著性检验是假设检验中最常用的一种方法,也是一种最基本的统计推断形式,其基本原理是先对总体的特征做出某种假设,然后通过抽样研究的统计推理,对此假设应该被拒绝还是接受做出推断。

假设检验的基本思想

  • 假设检验的基本思想是“小概率事件”原理,其统计推断方法是带有某种概率性质的反证法

  • 小概率思想是指小概率事件在一次试验中基本上不会发生。反证法思想是先提出检验假设,再用适当的统计方法,利用小概率原理,确定假设是否成立

    • 即为了检验一个假设 H 0 H_0 H0是否正确,首先假定该假设 H 0 H_0 H0正确,然后根据样本对假设 H 0 H_0 H0做出接受或拒绝的决策
    • 如果样本观察值导致了“小概率事件”发生,就应拒绝假设 H 0 H_0 H0,否则应接受假设 H 0 H_0 H0
  • 假设检验中所谓“小概率事件”,并非逻辑中的绝对矛盾,而是基于人们在实践中广泛采用的原则,即小概率事件在一次试验中是几乎不发生的

  • 概率小到什么程度才能算“小概率事件”,显然,“小概率事件”的概率越小,否定原假设 H 0 H_0 H0就越有说服力,常记这个概率值为α(0<α<1),称为检验的显著性水平

  • 对于不同的问题,检验的显著性水平α不一定相同,一般认为,事件发生的概率小于0.1、0.05或0.01等,即“小概率事件” 。

假设检验举例——鉴别可口可乐和百事可乐

可口可乐和百事可乐作为市场上最常见的两种可乐饮料大家一定都喝过,我们知道这两种可乐的味道差不多很难分辨, 如果现在有一名同学说自己能通过味道区分出两种可乐,那么如何设计实验来验证他是否具备这项能力呢?

我们可以假设这名同学不具备这个能力,如果通过实验能证明我们的假设是错误的,那么就说明这名同学具备品尝出两种可乐的能力来

  • 原假设 H 0 H_0 H0 不能区分两种不同的可乐
  • 备择假设 H 1 H_1 H1 可以区分两种不同的可乐

接下来我们给该同学用相同的杯子倒若干杯不同的可乐,让他品尝说出杯子里的可乐究竟是可口可乐还是百事可乐,如果答对了可能有两种情况:

  • 瞎蒙的
  • 真的能尝出来

我们都知道只喝一杯他如果答对了说明不了什么问题,那么究竟喝几杯能下结论说这个同学不是瞎蒙的呢?我们可以计算一下概率

  • 如果是瞎猜,猜对的概率是0.5, 那么猜对一杯的概率是0.5, 连着猜对两杯的概率是0.5*0.5 = 0.25 连着猜对三杯的概率是0.5 * 0.5 * 0.5=0.125
  • 如果该同学连喝5杯都做出了正确的判断, 那么我们可以计算得知 0.5^5 = 0.03125 也就是说有 3.125%的可能他是猜对的, 那么此时我们就可以推翻原假设: 该同学是蒙的,因为连着猜对5杯的概率实在太低了
  • 那么尝对了5杯之后我们是否有100%的把握说该同学一定具备通过味道区分可乐的能力呢? 答案也是否定的, 因为仍然有3.125%的可能他是瞎蒙的, 这个3.125%就是显著性水平(Significance level) 一般用α表示, 一般我们把显著性水平α的阈值设置为5%, 也就是α≤5%的时候我们认为这个结果是具有统计学意义的
  • 当然我们还可以接着做更多次实验, 比如让该同学再多喝几杯, 如果都能做出正确判断, 那么对应的显著性水平α 就越小, 我们得出该同学能够通过味道区分出两种可能的把握就越大

AB测试中的假设检验

通过上面的例子我们对假设检验有了基本的了解, 接下来我们看一下如何在AB测试中应用假设检验

  • 原假设 H 0 H_0 H0 老的方案老的设计
  • 备择假设 H 1 H_1 H1 新的方案新的设计

在上面的例子中,实验的次数越多我们得到的结论就越准确,那么在AB测试中,实验的次数实际上就是参与实验的人数,我们可以通过设置显著性水平(Significance level) α来倒推参与实验的最少人数,具体计算可以通过上面给出的工具网站实现

显著性水平α : 依据实验结果做出推翻原假设(否定原方案) 选择备择假设(采用新方案) 的决定,犯错的概率, 一般设置为5%

统计功效(1−β): 依据实验结果做出保留原假设(保留原方案) 不选择备择假设(不采用新方案) 的决定,犯错的概率, 一般β设置为20% 那么1−β 为80%

2.4 AB测试与辛普森悖论

辛普森悖论为英国统计学家E.H.辛普森于1951年提出,即在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论。

方案A(现有方案)转化率方案B(新方案)转化率
Android 用户70/800 = 8.75%20/200 = 10%
iphone 用户10/200 = 5%50/800 = 6.25%
总用户80/1000 = 8%70/1000 = 7%

AB测试中产生辛普森悖论的原因:流量分割不均匀导致的实验组与对照组的用户特征不一致

AB测试中如何避免辛普森悖论

  • 要得到科学可信的 AB 测试试验结果,就必须合理的进行正确的流量分割,保证试验组和对照组里的用户特征是一致的,并且都具有代表性,可以代表总体用户特征。
方案A(现有方案)转化率方案B(新方案)转化率
Android 用户70/800 = 8.75%80/800 = 10%
iphone 用户10/200 = 5%12/200 = 6%
总用户80/1000 = 8%92/1000 = 9.2%
  • 在实验设计上,如果我们觉得某两个变量对试验结果都有影响,那我们就应该把这两个变量放在同一层进行互斥试验,不要让一个变量的试验动态影响另一个变量的检验。如果我们觉得一个试验可能会对新老客户产生完全不同的影响,那么就应该对新客户和老客户分别展开定向试验,观察结论

  • 在试验实施上,对试验结果我们要积极的进行多维度的细分分析,除了总体对比,也看一看对细分受众群体的试验结果,不要以偏盖全,也不要以全盖偏。一个试验版本提升了总体活跃度,但是可能降低了年轻用户的活跃度,那么这个试验版本是不是更好呢?一个试验版本提升总营收0.1%,似乎不起眼,但是可能上海地区的年轻女性 iPhone 用户的购买率提升了20%,这个试验经验就很有价值了。

3、AB测试代码实战

3.1 项目背景
  • 假设您在一家中型电商公司工作。 UI设计师设计了最新的产品页面想通过页面更新提高转化率

    • 目前的转化率全年平均在13%左右
    • 目标转化率达到 15%。

    在这里插入图片描述

  • 在新的页面上线之前,我们要通过一小部分用户上测试页面的效果, 所以需要进行A/B测试

3.2 设计实验
  • 提出假设

    • 首先,我们要确保在项目开始时就制定了一个假设

    • 鉴于我们不知道新设计的性能是否会比我们当前的设计更好或更差(或相同?),我们将选择双尾测试:

      H 0 H_0 H0 原假设 老的设计比较好, 新版设计没有用

      H 1 H_1 H1 备选假设 新的设计比较好

  • 选择变量

    • 对照组: 看到旧的设计
    • 实验组: 看到新的设计

    虽然我们已经知道了旧的设计的转化率(13%左右), 但是我们依然要需要设计两组, 原因是为了避免其他因素带来的误差, 比如季节因素, 促销因素。这两组人在其它条件都相同的只是页面设计不同的情况下进行实验, 这样能保证两组间的差异是由于设计导致的

    • 我们的设计的目标KPI是转化率, 所以,我们会添加一个字段来记录用户的购买情况
      • 购买了产品的用户 值为1
      • 未购买产品的用户值为0
  • 确定实验人数

    • AB测试只会选择一小部分用户来参与实验, 用小部分的实验结果来估计整体的结果,每组的人数越多,我们得到的结果就越精准,但同时我们付出的成本就越大,通过功效分析我们可以计算出满足实验条件的最小人群
    • 检验功效 (1 — β) :一般设置为0.8
    • α :在设计实验的时候我们设置为0.05
    • 效果大小:旧的页面转化率为13%,新页面我们希望转化率能提升2%,所以我们可以用13%和15%来计算预期效果大小
    • 确定实验人数的计算过程可以通过Python代码实现
    import numpy as np
    import pandas as pd
    import scipy.stats as stats
    import statsmodels.stats.api as sms
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import seaborn as sns
    from math import ceil%matplotlib inline# 计算effect_size  0.13为当前的转换率  0.15为目标转化率 也就是说我们希望通过新的设计带来2%的提升
    effect_size = sms.proportion_effectsize(0.13, 0.15)   required_n = sms.NormalIndPower().solve_power(effect_size, # 传入上面计算的 effect_sizepower=0.8, # 设置 1-β = 80%alpha=0.05, # 设置 α 为5%ratio=1  # 对照组和测试组人一样, 这里的ratio 比例就是1)                                                  
    #对结果向上取整
    required_n = ceil(required_n)                         print(required_n)
    

    4720

    • 计算结果说明每组至少需要4720人
    • 在实践中将功率参数设置为 0.8 意味着如果我们的设计之间存在转化率的实际差异,假设差异是我们估计的差异(13% 对 15%),我们有大约 80% 的机会检测到它 与我们计算的样本量在我们的测试中具有统计显着性。
3.3 收集准备数据
  • 在企业场景下,我们需要与工程团队配合,收集满足要求的数据, 这里我们使用准备好的数据集, 对数据进行处理

    • 加载数据到DataFrame
    • 检查和清理数据
    • 从DataFrame中采样数据每组4720行
    df = pd.read_csv('data/ab_data.csv')
    df.head()
    
    user_idtimestampgrouplanding_pageconverted
    08511042017-01-21 22:11:48.556739controlold_page0
    18042282017-01-12 08:01:45.159739controlold_page0
    26615902017-01-11 16:55:06.154213treatmentnew_page0
    38535412017-01-08 18:28:03.143765treatmentnew_page0
    48649752017-01-21 01:52:26.210827controlold_page1
    • 查看数据基本情况
    df.info()
    
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 294478 entries, 0 to 294477
    Data columns (total 5 columns):#   Column        Non-Null Count   Dtype 
    ---  ------        --------------   ----- 0   user_id       294478 non-null  int64 1   timestamp     294478 non-null  object2   group         294478 non-null  object3   landing_page  294478 non-null  object4   converted     294478 non-null  int64 
    dtypes: int64(2), object(3)
    memory usage: 11.2+ MB
    
    • 数据一共294478行,每一条数据代表一次用户访问,共五列:

      • user_id - 访问的用户ID
      • timestamp - 访问的时间
      • group - 该用户被放到那一组 {control对照, treatment实验}
      • landing_page -该用户看到的是哪一种落地页 {old_page老页面, new_page新页面}
      • converted - 改次访问是否有转化 (binary, 0=无转化, 1=转化)
    • 在后续的分析中,我们实际上主要用到的是 groupconverted 这两个字段

    • 创建透视表, 查询是否对照组看到的都是老页面

    df.pivot_table(index = 'group',columns='landing_page',values = 'user_id',aggfunc='count')
    
    landing_pagenew_pageold_page
    group
    control1928145274
    treatment1453111965
    • 在我们进行后续处理之前, 还要查看是否有用户进行了多次操作
    session_counts = df['user_id'].value_counts(ascending=False)
    multi_users = session_counts[session_counts>1].count()
    multi_users
    

    3894

    • 说明一共有3894个用户访问了不止一次, 整体数据有20多万条, 所以我们直接把这部分数据删除
    users = session_counts[session_counts < 2].index
    df = df[df['user_id'].isin(users)]
    
  • 数据采样

    • 接下来我们从处理后的数据中,每组采样4720条数据, 我们这里使用DataFrame的sample()方法进行简单随机采样
    control_sample = df[df['group'] == 'control'].sample(n=required_n, random_state=22)
    treatment_sample = df[df['group'] == 'treatment'].sample(n=required_n, random_state=22)
    # 这里random_state 为随机数种子, 如果也传入22, 那么后续结果会与讲义中一样
    ab_test = pd.concat([control_sample, treatment_sample], axis=0)
    ab_test.reset_index(drop=True, inplace=True)
    ab_test
    
    user_idtimestampgrouplanding_pageconverted
    07638542017-01-21 03:43:17.188315controlold_page0
    16905552017-01-18 06:38:13.079449controlold_page0
    28615202017-01-06 21:13:40.044766controlold_page0
    36307782017-01-05 16:42:36.995204controlold_page0
    46566342017-01-04 15:31:21.676130controlold_page0
    94359085122017-01-14 22:02:29.922674treatmentnew_page0
    94368732112017-01-05 00:57:16.167151treatmentnew_page0
    94376312762017-01-20 18:56:58.167809treatmentnew_page0
    94386623012017-01-03 08:10:57.768806treatmentnew_page0
    94399446232017-01-19 10:56:01.648653treatmentnew_page1
    • 查看两组数据情况
    ab_test.groupby('group')['landing_page'].value_counts()
    # landing_page 落地页类型  old_page老页面 new_page 新页面
    # control 控制组  treatment 对照组
    

    group landing_page
    control old_page 4720
    treatment new_page 4720
    Name: landing_page, dtype: int64

3.4 分析实验结果
  • 首先我们来计算一下两组的转化率和标准差

    conversion_rates = ab_test.groupby('group')['converted'].mean().to_frame()
    conversion_rates conversion_rates.style.format('{:.3f}')
    
    groupconversion_rate
    control0.123
    treatment0.126
  • 从上面的统计数据来看,旧的和新的落地页表现非常相似,新设计表现略好, 12.3% 与 12.6%

    • 从对照组的数据看, 转换率为12.3% 比之前我们的整体表现要差一些, 可能与采样人群的差异有关
    • 测试组的数据比对照组要好一些, 但是这个结果是否具有统计意义?
3.5 假设检验
  • 最后一步是假设检验, 我们的样本量比较大,可以应用Z检验来计算P值, 如果P值<0.05, 说明
  • 我们可以使用statsmodels.stats.proportion 模块来计算P值和置信区间
from statsmodels.stats.proportion import proportions_ztest, proportion_confint
control_results = ab_test[ab_test['group'] == 'control']['converted']     #获取对照组是否转化的数据
treatment_results = ab_test[ab_test['group'] == 'treatment']['converted'] #获取实验组是否转化的数据
n_con = control_results.count() # 获取对照组人数
n_treat = treatment_results.count()  # 获取实验组人数
successes = [control_results.sum(), treatment_results.sum()] # 获取实验组和对照组成功转化的人数
nobs = [n_con, n_treat]z_stat, pval = proportions_ztest(successes, nobs=nobs)  #计算P值
(lower_con, lower_treat), (upper_con, upper_treat) = proportion_confint(successes, nobs=nobs, alpha=0.05) #计算置信区间print(f'z statistic: {z_stat:.2f}')
print(f'p-value: {pval:.3f}')
print(f'ci 95% for control group: [{lower_con:.3f}, {upper_con:.3f}]')
print(f'ci 95% for treatment group: [{lower_treat:.3f}, {upper_treat:.3f}]')

z statistic: -0.34
p-value: 0.732
ci 95% for control group: [0.114, 0.133]
ci 95% for treatment group: [0.116, 0.135]

3.6 最终结论
  • 最终计算出的p-value = 0.732 远大于我们实验设置的α = 0.05, 我们不能拒绝原假设 旧的主页表现更好, 这就意味着,我们的新页面并不比旧的页面表现好
  • 查看实验组的置信区间([0.116, 0.135] 或 11.6-13.5%),注意到:
    • 13% 的基准转化率在置信区间内
    • 15% 的目标值(我们的目标是 2% 的提升)并不在置信区间内
    • 这意味着新设计的真实转化率可能与之前的转化率接近, 证明我们的新改进并没有效果

🥂小结

AB测试的应用场景

  • 互联网行业应用广泛:页面结构调整, 换新图标,添加新功能等等
  • 实体行业应用相对复杂一些:不同优惠券效果测试

AB测试还是ABC测试

  • AB测试:一次测试一个方案
  • ABC…… 测试: 一次测试多个方案,但需要流量足够大,否则难以满足实验要求的最少人数

AB测试需要注意如下几点

  • 流量分配

  • 确定有效的最小参与人数

    • 确定基准指标和提升目标
    • 设置显著性水平α (一般是5%)和 统计功效 1-β (一般是80%)
    • 出结果之后计算P值 如果P<5% 则可以拒绝原假设
  • 我们可以通过AB测试工具网站帮助确定人数,也可以使用statsmodels 模块来通过代码实现

    • import statsmodels.stats.api 计算需要人数
    • statsmodels.stats.proportion 计算P值和置信区间

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

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

相关文章

FastDFS分布式文件系统

一、概述 FastDFS是一款由国人余庆开发的轻量级开源分布式文件系统&#xff0c;它对文件进行管理&#xff0c;功能包括&#xff1a;文件存储、文件同步、文件访问&#xff08;文件上传、文件下载&#xff09;等&#xff0c;主要解决大容量文件存储和高并发访问问题&#xff0c…

jenkins应用2-freestyle-job

1.jenkins应用 1.jenkins构建的流程 1.使用git参数化构建&#xff0c;用标签区分版本 2.git 拉取gitlab远程仓库代码 3.maven打包项目 4.sonarqube经行代码质量检测 5.自定义制作镜像发送到远程仓库harbor 6.在远程服务器上拉取代码启动容器 这个是构建的整个过程和步骤…

保姆级教程:Redis 主从复制原理及集群搭建

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

线程池的工作原理

文章目录 一、应用场景二、工作原理三、主要函数 一、应用场景 传统并发变成的缺陷&#xff1a; 1.创建和销毁线程上花费的时间和消耗的系统资源&#xff0c;甚至可能要比花在处理实际的用户请求的时间和资源要多得多 2. 活动的线程需要消耗系统资源&#xff0c;如果启动太多&…

26、matlab多项式曲线拟合:polyfit ()函数

1、polyfit 多项式曲线拟合 语法 语法&#xff1a;p polyfit(x,y,n) 返回次数为 n 的多项式 p(x) 的系数&#xff0c;该阶数是 y 中数据的最佳拟合&#xff08;基于最小二乘指标&#xff09;。 语法&#xff1a;[p,S] polyfit(x,y,n) 还返回一个结构体 S 语法&#xff1a;[…

优化 mac 储存空间的方法 只需一招为你的苹果电脑提速

在职场中&#xff0c;许多人都对苹果电脑情有独钟。苹果电脑以其简洁美观的设计、流畅稳定的性能以及出色的用户体验&#xff0c;成为了众多职场人士的得力助手。无论是处理文档、制作演示文稿&#xff0c;还是进行创意设计等工作&#xff0c;苹果电脑都能展现出其独特的优势&a…

微信小程序公众号二合一分销商城源码系统 基于PHP+MySQL组合开发的 可多商户商家入驻 带完整的安装代码包以及搭建教程

系统概述 微信小程序公众号二合一分销商城源码系统&#xff0c;是基于PHPMySQL组合开发的一款高效、稳定的电子商务平台解决方案。该系统创新性地将微信公众号与小程序的功能进行了深度整合&#xff0c;为商家提供了一个功能齐全、易于管理的分销商城系统。通过此系统&#xf…

Vue3+vant 带你实现常见的历史记录的业务功能

前言 大部分小伙伴不管是开发PC端还是H5移动端&#xff0c;都会遇到历史搜索的功能。对用户的历史记录进行增删查可以是接口&#xff0c;也可以是前端用缓存实现&#xff0c;一般用浏览器缓存实现的比较多&#xff0c;这篇文章就来教你如何用LocalStorage对历史记录数据的存储、…

视创云展元宇宙虚拟展厅,带来沉浸式的逛展体验!

近年来&#xff0c;随着科技的飞速发展和市场需求的不断演变&#xff0c;众多企业纷纷将目光转向线上虚拟展厅的建设。视创云展元宇宙虚拟展厅凭借其创新性和实用性&#xff0c;为众多企业带来了前所未有的宣传体验&#xff0c;成为了商企展示自我、推广产品的全新舞台。 与传统…

Java 生成SSL证书

第一步&#xff1a; cmd打开指令窗口 第二步&#xff1a; 运行指令&#xff1a; keytool -keystore hk.jks -storepass 123456 -deststoretype jks -genkeypair -keyalg RSA -validity 365 -alias contrastserver -dname "CN111.230.63.59, OUHK, OHK, LZH, STGD, CCN&…

XSKY对象存储深度结合Alluxio分布式缓存系统,GPU利用率提高至90%以上

近日&#xff0c;Alluxio分布式缓存系统完成了与XSKY星辰天合的 XEOS V6.4 对象存储的兼容性测试&#xff0c;旨在解决数据管理和加速方面的挑战。双方进行了深度的产品对接和联合开发&#xff0c;将 Alluxio 分布式缓存系统与 XEOS 对象存储的众多应用特性进行结合&#xff0c…

38. 【Java教程】日期和时间处理

本小节我们将学习 Java 中的日期和时间&#xff0c;日期和时间在我们的实际开发中非常常用&#xff0c;例如用户的注册、数据的增删改、对敏感信息的操作等等都需要记录下日期和时间。通过本小节的学习&#xff0c;你将了解到什么是日期、什么是时间、什么是时区&#xff0c;Ja…

3072. 将元素分配到两个数组中 II

题目 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount &#xff0c;使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作&#xff0c;将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操…

WebGL画粗线

目录 前言 基本思路 求左右端点 实现 组织数据 顶点着色器计算端点坐标 效果 前言 WebGL绘制模式有点、线、面三种&#xff1b;通过点的绘制可以实现粒子系统等&#xff0c;通过线可以绘制一些连线关系&#xff1b;面就强大了&#xff0c;通过面&#xff0c;我们可以…

视频监控汇聚平台LntonCVS国标GB28181协议实现语音对讲功能

在当今这个智能技术飞速发展的时代&#xff0c;人工智能已经成为了电子产品领域的一股不可忽视的热门趋势。随着科技的不断进步&#xff0c;越来越多的电子产品开始融入人工智能技术&#xff0c;从而为其开拓了全新的发展路径。在这个大背景下&#xff0c;安防摄像头无插件直播…

基于springboot实现智慧校园之家长子系统项目【项目源码】计算机毕业设计

基于springboot实现智慧校园之家长子系统演示 SpringBoot框架介绍 本课题程序开发使用到的框架技术&#xff0c;英文名称缩写是SpringBoot&#xff0c;在JavaWeb开发中使用的流行框架有SSH、SpringBoot、SpringMVC等&#xff0c;作为一个课题程序采用SSH框架也可以&#xff0c…

【学习】测试用例设计与执行的黄金法则

在软件测试领域&#xff0c;测试用例的设计与执行是确保产品质量的关键环节。一个优秀的测试用例能够揭示软件中的缺陷&#xff0c;而高效的执行则能保障测试覆盖的全面性。如同璀璨的星辰指引航船前行&#xff0c;以下黄金法则将引领测试用例设计与执行的过程&#xff0c;确保…

Go 群发邮件Redis 实现邮件群发

一、安装 go get github.com/go-redis/redis/v8 go get gopkg.in/gomail.v2 二、使用"gopkg.in/gomail.v2"群发 package mainimport (gomail "gopkg.in/gomail.v2" )func main() {// 邮件内容m : gomail.NewMessage()m.SetHeader("From", &qu…

【杂谈】AIGC之Stable Diffusion:AI绘画的魔法

Stable Diffusion&#xff1a;AI绘画的魔法 引言 在AI的世界里&#xff0c;Stable Diffusion就像一位魔法师&#xff0c;它能够将我们脑海中的幻想&#xff0c;用画笔一一描绘出来。今天&#xff0c;就让我们一探这位魔法师的奥秘&#xff0c;看看它是如何从无到有&#xff0…

安装MongoDB单副本说明

参考&#xff1a;https://blog.csdn.net/weixin_43464076/article/details/126509254 https://driverzhang.github.io/post/mongo%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E4%B9%8B%E5%89%AF%E6%9C%AC%E9%9B%86%E9%87%87%E5%9D%91/ https://dev.to/alexalvess/getting-started-wi…