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_id timestamp group landing_page converted 0 851104 2017-01-21 22:11:48.556739 control old_page 0 1 804228 2017-01-12 08:01:45.159739 control old_page 0 2 661590 2017-01-11 16:55:06.154213 treatment new_page 0 3 853541 2017-01-08 18:28:03.143765 treatment new_page 0 4 864975 2017-01-21 01:52:26.210827 control old_page 1 - 查看数据基本情况
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
- 访问的用户IDtimestamp
- 访问的时间group
- 该用户被放到那一组 {control
对照,treatment
实验}landing_page
-该用户看到的是哪一种落地页 {old_page
老页面,new_page
新页面}converted
- 改次访问是否有转化 (binary,0
=无转化,1
=转化)
-
在后续的分析中,我们实际上主要用到的是
group
和converted
这两个字段 -
创建透视表, 查询是否对照组看到的都是老页面
df.pivot_table(index = 'group',columns='landing_page',values = 'user_id',aggfunc='count')
landing_page new_page old_page group control 1928 145274 treatment 145311 1965 - 在我们进行后续处理之前, 还要查看是否有用户进行了多次操作
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_id timestamp group landing_page converted 0 763854 2017-01-21 03:43:17.188315 control old_page 0 1 690555 2017-01-18 06:38:13.079449 control old_page 0 2 861520 2017-01-06 21:13:40.044766 control old_page 0 3 630778 2017-01-05 16:42:36.995204 control old_page 0 4 656634 2017-01-04 15:31:21.676130 control old_page 0 … … … … … … 9435 908512 2017-01-14 22:02:29.922674 treatment new_page 0 9436 873211 2017-01-05 00:57:16.167151 treatment new_page 0 9437 631276 2017-01-20 18:56:58.167809 treatment new_page 0 9438 662301 2017-01-03 08:10:57.768806 treatment new_page 0 9439 944623 2017-01-19 10:56:01.648653 treatment new_page 1 - 查看两组数据情况
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}')
group conversion_rate control 0.123 treatment 0.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值和置信区间
相关文章:
AB测试实战
AB测试实战 1、AB测试介绍🐾 很多网站/APP的首页都会挂一张头图(Banner),用来展示重要信息,头图是否吸引人会对公司的营收带来重大影响,一家寿险公司Humana设计了如下三张头图,现在需要决定使用哪一张放到首页&#x…...
Java高级面试精粹:问题与解答集锦(六)
Java 面试问题及答案 1. 请解释Java中的多线程概念,并说明如何实现它? 答案: 多线程是指在Java程序中同时运行多个线程的功能。线程是程序执行的最小单元,Java中的多线程可以通过继承Thread类或实现Runnable接口来实现。 继承Th…...
MySQL之数据库数据库范式学习笔记(二)
三大范式 范式是数据库设计中的概念,用于规范化数据结构,以减少数据冗余并确保数据的一致性和完整性。MySQL 数据库设计通常遵循一定的范式,其中最常见的是第一至第三范式。以下是各个范式的简要说明: 第一范式(1NF&…...
【Qt】 new成功,但是没有进入到构造函数。
NameTest工程中 nametest.cpp NameTest::NameTest() {pdata new privateAB; }NameTest::~NameTest() {if (pdata){privateAB *p (privateAB *)pData; //void *pdata nullptr;delete p;pdata nullptr;} }内部类: privateAB #include "private.h"#i…...
高清多媒体接口(High Definition Multimedia Interface, HDMI)
目录 1. Overview1.1. Time Minimized Differential Signal(TMDS)1.2. Display Data Channel(DDC)1.3. Consumer Electronics Control(CEC)1.4. HDMI Ethernet and Audio Return Channel(HEAC)1.5. Hot Plug Detected(HPD)2. Signaling and Encoding3. Video4. Control and Con…...
Spring AI 第二讲 之 Chat Model API 第五节HuggingFace Chat
HuggingFace Inference Endpoints 允许您在云中部署和提供机器学习模型,并通过 API 对其进行访问。 开始使用 有关 HuggingFace Inference Endpoints 的更多详细信息,请访问此处。 前提条件 添加 spring-ai-huggingface 依赖关系: <d…...
【笔记】Sturctured Streaming笔记总结(Python版)
目录 相关资料 一、概述 1.1 基本概念 1.2 两种处理模型 (1)微批处理 (2)持续处理 1.3 Structured Streaming和Spark SQL、Spark Streaming关系 二、编写Structured Streaming程序的基本步骤 三、输入源 3.1 File源 &a…...
Python函数进阶
文章目录 1 函数多返回值2 函数多种传参方式2.1 位置参数2.2 关键字参数2.3 缺省参数2.4 不定长参数 3 匿名函数函数作为参数传递lambda匿名函数 1 函数多返回值 def test_return():return 1,2,3 x,y,z test_return() print(x) print(y) print(z)2 函数多种传参方式 2.1 位置参…...
[知识点]c++ delete与delete[ ]
在C中,delete 和 delete[] 是用于释放动态分配的内存的关键字。它们的使用取决于内存是如何分配的。具体来说: delete 用于释放通过 new 分配的单个对象。delete[] 用于释放通过 new[] 分配的数组。 如果你通过 new 分配了一个单个对象,那么…...
iCloud如何被高效利用?
1.同步设备 同步设备是指利用云服务(如iCloud)将多台设备上的数据保持同步,确保这些设备上的信息始终保持一致。以下是详细说明如何同步设备使用iCloud: 1. 打开iCloud设置:在iOS设备上,打开“设置”应用…...
月入30000的软件测试人员,简历是什么样子的?
我们都知道,简历是一个人进入职场的敲门砖。从某种层面来说,简历也像一个人的具象身份证,或者专业资格证。所以,一份简历的好坏,不仅关乎个人的“脸面”,更关乎你是不是一个有“含金量”的技术人员。 所以…...
nginx官网源代码方式安装nginx并编译
从Nginx官网下载特定版本的源代码并编译安装的步骤如下: 确定需要的版本: 前往Nginx 官方网站下载页面,选择你需要的Nginx版本。 下载源代码: 使用wget命令下载源代码压缩包。例如,下载1.21.0版本的Nginx:…...
iOS ActivityViewController使用
UIActivityViewController是iOS中用于展示一个活动列表的视图控制器,允许用户通过各种内置或第三方的应用来分享内容。以下是使用UIActivityViewController分享文本内容的示例代码: import UIKit class ViewController: UIViewController { IBA…...
新手快速上手IDEA【常用快捷键】
目录 一、常用二、进阶(提高编码速度)三、其他四、查找、替换与关闭最后 一、常用 说明快捷键复制代码ctrl c粘贴ctrl v剪切ctrl x撤销ctrl z反撤销ctrl shift z保存-save allctrl s全选-select allctrl a 二、进阶(提高编码速度&a…...
MySQL里如果有字段是function怎么查询呢?
在MySQL中,字段名通常不会命名为function,因为FUNCTION是MySQL的保留关键字,用于定义存储函数。但是,如果你确实有一个字段名叫做function(尽管这通常不是一个好的实践),你仍然可以查询它。你只…...
从高海拔到严寒季的测量作业更要「快准稳」,怎么实现?
西藏那曲海拔4500米公路勘测项目赶工期 “必须要保障在西藏那曲地区承接的公路勘测项目赶工期需求,海拔高达4500米、网络通讯不足、部分范围存在无网以及地基信号覆盖可能不足的情况,需要能满足环境和项目需求的专业RTK设备紧急送到。” 客户的一个电话…...
WowTab:简洁界面,效率神器,重塑新标签页浏览体验
目录 一、插件简介 二、插件功能 2.1 支持两种模式切换 2.2 效率组件介绍 2.3 设置中心 三、使用总结 四、插件安装说明 4.1 Edge安装 4.2 Chrome安装 大家在日常办公当中,是不是觉得新标签页太平淡无奇?来,给自己的浏览器加点料&…...
PostgreSQL 17 Beta1 发布,酷克数据再次贡献核心力量
得益于全球的开发者贡献,PostgreSQL已成长为一款拥有众多全球用户和贡献者、成熟稳定的开源数据库。2024年5月23日,PostgreSQL全球开发组宣布,PostgreSQL 17的首个 Beta 版本现已开放下载。本次新版本带来了众多惊喜。值得一提的是࿰…...
CDH服务红,查看日志发现host有问题
看host后,发现里面节点ip都是127.0.0.1然后全部改成对应的ip, 1.在/etc/hosts里面全部加上了 ip以及对应的角色名称 2然后注释了127.0.0.1 hostname 3.然后重启所有的机器agent和server,在重新登录,点击重新部署。 重启agent sy…...
数据分析------统计学知识点(三)
相关性分析 1.趋势分析与散点图 散点图可帮助我们发现和理解变量间的关系,可直观观察是否有相关性。 (1)散点图定义及组成要素 散点图是一种以点的形式在直角坐标系上表示两个数值变量间关系的图表 横坐标(x轴)&a…...
MySQL 导出一条数据的插入语句
1.MySQL 导出一条数据的插入语句的方法 在MySQL中,如果我们想要导出一条数据的插入语句,我们可以使用SELECT ... INTO OUTFILE语句(但这通常用于将整个表或查询结果导出到一个文件中),或者我们可以手动构建插入语句。…...
隐藏 IP 地址的重要性是什么?
在当今的数字时代,保护我们的在线身份至关重要。从保护个人信息到保护隐私,互联网用户越来越多地寻求增强在线安全性的方法。保持匿名和保护敏感数据的一个关键方面是隐藏您的 IP 地址。在这篇博文中,我们将深入探讨隐藏 IP 地址的重要性&…...
Oracle 19c linux安装
下载Oracle Database Preinstallation RPM,该包会自动下载依赖,创建oracle用户, 手动下载地址:https://yum.oracle.com/repo/OracleLinux/OL7/latest/x86_64/index.html wget http://yum.oracle.com/repo/OracleLinux/OL7/latest…...
AI音乐生成流程
suno.com...
android room数据库升级脚本常见问题
room数据库升级很容易遇到一个问题, java.lang.IllegalStateException: Migration didnt properly handle: Expected:xxx Found:xxx 意思是数据库执行完你编写的升级脚本后,发现数据库当前的表结构与你代码中的Entity class结构不一致,所…...
在 iCloud.com 上导入、导出或打印联系人
想将iPhone上的电话本备份一份到本地电脑上,发现iTunes好像只是音乐播放了,不再支持像电话本等功能,也不想通过其他第三方软件,好在可以通过iCloud进行导入导出。下面只是对操作过程进行一个图片记录而已,文字说明可以…...
JavaScript中this方法;var,let,constd区别;JSON是什么
this方法 1、在对象方法中, this 指向调用它所在方法的对象。 2、单独使用 this,它指向全局(Global)对象。 3、函数使用中,this 指向函数的所属者。 4、严格模式下函数是没有绑定到 this 上,这时候 this 是 undefined。 5、在 HT…...
Mybatis不明白?就这一篇带你轻松入门
引言:烧脑的我一直在烧脑的寻找资料,寻找网课,历经磨难让一个在大一期间只会算法的我逐渐走入Java前后端开发,也是一直在自学的道路上磕磕碰碰,也希望这篇文章对于也是同处于自学的你有所帮助,也希望你继续…...
pymupdf提取pdf表格及表格数据合并
pymupdf提取pdf表格非常快速,相比其他库是个更好的选择. 一个行列多的表格打印成pdf后会由于页宽分页原因变成多个表格,提取的多个表格需要合并为一个表格,再来处理数据. 下面代码中merge函数用于合并表格࿰…...
门外汉一次过软考中级(系统集成项目管理工程师)秘笈,请收藏!
24上软考考试已经结束,24下软考备考又要开启了!今年软考发生了改革,很多考试由一年考两次变成了一年考一次,比如高级信息系统项目管理师,比如中级系统集成项目管理工程师,这两科是高、中级里相对简单&#…...
做班级网站的素材/三个关键词介绍自己
注: 某些输入文件使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 在项目的build.gradle文件中添加下面的代码 allprojects {...gradle.projectsEvaluated {tasks.withType(JavaCompile) {options.compilerArgs << "-Xlint:…...
河南省豫建设计院网站/新媒体营销案例ppt
原网址:http://www.xshellcn.com/zhishi/shezhi-bianma.html。 在Xftp远程连接的时候,经常会出现中文乱码(仅指Linux主机使用UTF-8的情况下),为了解决该问题,我们需要通过设置UTF-8编码方式,防…...
网站不能访问的原因/重庆黄埔seo整站优化
大致情况:我用TP5.1和ajax想要实现图片上传的需求,开始我是把ajax写在html模板中的图片上传没有问题,后来考虑到代码规范的问题,不想把代码都写在一起,而是单独写在一个js文件中去引入,结果图片上传失败。a…...
小型企业网站建设项目/网站关键字优化价格
简介Windows 安全模型安全场景:创建一个文件驱动程序安全责任行动指南和资源本文提供关于为 Microsoft Windows 家族操作系统编写安全的内核模式驱动程序的信息。其中描述了如何将 Windows 安全模型应用于驱动程序,并解释驱动程序作者必须采取哪些措施来…...
用什么网站做动感相册/竞价外包
参考:http://www.jianshu.com/p/9d408e21dc3a http://www.cnblogs.com/luxiaojun/p/6144748.html 豆瓣应该是ip被封了。 转载于:https://www.cnblogs.com/cuzz/p/7696584.html...
天河移动网站建设/微信广告投放推广平台多少费用
文章目录五大数据类型StringListSetHashzSet事务和乐观锁主从复制哨兵模式配置原理缓存穿透、击穿、雪崩五大数据类型 String 方法用法set a b插入一条键为a,值为b的数据(如果有空格,字符串需加引号)get a查询键为a的值mset a x…...