思维链提示促进了 LLMs 的推理能力
原文:
towardsdatascience.com/chain-of-thought-prompting-facilitate-llms-reasoning-abilities-313cd7714938
通过示例展示
·发表于Towards Data Science·阅读时间 6 分钟·2023 年 6 月 12 日
–
图片由Juan Rumimpunu提供,来源于Unsplash
大型语言模型(LLMs)被证明在解决各种任务方面非常高效,从总结文档到用不同编程语言编写代码。
此外,新发布的模型如 ChatGPT 和 GPT-4 使得 LLMs 的表现更加出色,为基于 LLM 的应用解锁了更多机会。
尽管大型语言模型(LLMs)具有非凡的技能,但它们有时未能展示非常简单的推理能力,无法解决一个四年级学生都能轻松处理的问题。
在这一领域已经进行了大量研究,旨在理解为何 LLMs 无法执行此类任务并使其表现更好。
关注这个特定问题的一个研究是思维链提示,由谷歌研究团队介绍。
思维链提示
一种结构为{输入、思维链、输出}的提示技术,其中思维链是一系列中间自然语言推理步骤。
模型会接收到一些包含输入和输出的示例(少样本学习),然后被要求解决一个涉及多步骤或算术推理任务的问题。
论文的主要结论:
-
思维链提示优于标准提示
-
思维链提示与标准提示之间的区别在于较大的模型上更为明显。思维链提示的性能提升与模型的参数数量成正比。
思路链提示技术就是逐步解决问题。每一步都基于逻辑推理。这里是一个示例:
问题:约翰有 2 栋房子。每栋房子有 3 间卧室,每间卧室有 2 个窗户。每栋房子有 1 个厨房,厨房有 2 个窗户。此外,每栋房子还有 5 个窗户不在卧室或厨房中。
约翰的房子里有多少个窗户?
答案:每栋房子有 3 间卧室,每间卧室有 2 个窗户,共计 6 个卧室窗户。每栋房子有 1 个厨房,厨房有 2 个窗户,共计 2 个厨房窗户。还有 5 个窗户不在厨房或卧室中。因此,每栋房子有 6 + 2 + 5 = 13 个窗户。由于有 2 栋房子,所以约翰的房子里总共有 2 x 13 = 26 个窗户。
你可以遵循不同的步骤来获得正确的答案。对于这类问题,几乎总有多条路径可以到达答案。
在标准提示中,我们通常会向语言模型提出上述问题,并期望它给出答案。让我们试试:
# model: text-davinci-003
prompt = """
John has 2 houses. Each house has 3 bedrooms and there are 2 windows in each bedroom.
Each house has 1 kitchen with 2 windows. Also, each house has 5 windows that are not in the bedrooms or kitchens.
How many windows are there in John's houses?
"""
# model response
"There are a total of 32 windows in John's houses."
错误的答案!
我们不知道模型如何得到这个答案,这带来了思路链提示的另一个优点。模型以逐步回答的方式回应,这使得调试过程更容易。我们可以很容易地发现问题所在。
通过思路链提示技术,我们在提示中添加了一些问题及其答案,以进行少量示例提示。这些答案以逐步解决方案的形式出现(即展示思路链)。
这里是更新后的提示和模型的回应:
# model: text-davinci-003
prompt = """
Q: There are 15 trees in the grove. Grove workers will plant trees in the grove today. After they are done, there will be 21 trees. How many trees did the grove workers plant today?
A: There are 15 trees originally. Then there were 21 trees after some more were planted. So there must have been 21 - 15 = 6\. The answer is 6.
Q: If there are 3 cars in the parking lot and 2 more cars arrive, how many cars are in the parking lot?
A: There are originally 3 cars. 2 more cars arrive. 3 + 2 = 5\. The answer is 5.
Q: Leah had 32 chocolates and her sister had 42\. If they ate 35, how many pieces do they have left in total?
A: Originally, Leah had 32 chocolates. Her sister had 42\. So in total they had 32 + 42 = 74\. After eating 35, they
had 74 - 35 = 39\. The answer is 39.
Q: Jason had 20 lollipops. He gave Denny some lollipops. Now Jason has 12 lollipops. How many lollipops did Jason give to Denny?
A: Jason started with 20 lollipops. Then he had 12 after giving some to Denny. So he gave Denny 20 - 12 = 8\. The answer is 8.
Q: Shawn has five toys. For Christmas, he got two toys each from his mom and dad. How many toys does he have now?
A: Shawn started with 5 toys. If he got 2 toys each from his mom and dad, then that is 4 more toys. 5 + 4 = 9\. The answer is 9.
Q: John has 2 houses. Each house has 3 bedrooms and there are 2 windows in each bedroom.
Each house has 1 kitchen with 2 windows. Also, each house has 5 windows that are not in the bedrooms or kitchens.
How many windows are there in John's houses?
A:
"""
# model response
"John has 2 houses. Each house has 3 bedrooms with 2 windows each,
1 kitchen with 2 windows, and 5 windows that are not in the bedrooms or
kitchens. So for each house, there are 3 x 2 + 2 + 5 = 13 windows.
In total, there are 2 x 13 = 26 windows. The answer is 26."
正确的答案!
回应是对模型思考过程的逐步解释(思路链),就像提示中展示的示例一样。
让我们再看一个例子。这里是标准提示版本:
# model: text-davinci-003
prompt = """
We have a big meeting in 10 days, which is 5 days before our product
launch on 08/24/2022\. What is the date today in MM/DD/YYYY?
"""
# model response
"08/14/2022"
错误的答案!
让我们尝试用思路链提示回答相同的问题,提供一些输入输出示例(少量示例学习):
# model: text-davinci-003
prompt = """
Q: There are 15 trees in the grove. Grove workers will plant trees in the grove today. After they are done, there will be 21 trees. How many trees did the grove workers plant today?
A: There are 15 trees originally. Then there were 21 trees after some more were planted. So there must have been 21 - 15 = 6\. The answer is 6.
Q: If there are 3 cars in the parking lot and 2 more cars arrive, how many cars are in the parking lot?
A: There are originally 3 cars. 2 more cars arrive. 3 + 2 = 5\. The answer is 5.
Q: 2015 is coming in 36 hours. What is the date one week from today in MM/DD/YYYY?
A: If 2015 is coming in 36 hours, then it is coming in 2 days. 2 days before 01/01/2015 is 12/30/2014,
so today is 12/30/2014\. So one week from today will be 01/05/2015\. So the answer is 01/05/2015.
Q: Shawn has five toys. For Christmas, he got two toys each from his mom and dad. How many toys does he have now?
A: Shawn started with 5 toys. If he got 2 toys each from his mom and dad, then that is 4 more toys. 5 + 4 = 9\. The answer is 9.
Q: We have a big meeting in 10 days, which is 5 days before our product launch on 08/24/2022.
What is the date today in MM/DD/YYYY?
A:
"""
# model response
"If the product launch is on 08/24/2022, then 10 days before that is '
'08/14/2022\. 5 days before that is 08/09/2022\. So today is 08/09/2022\. The '
'answer is 08/09/2022."
正确的答案!
结束语
思路链提示明显提高了语言模型在某些任务上的能力。如果你想了解更多关于他们进行的实验,建议阅读整篇论文。
需要注意的是,正如论文中提到的,思路链提示的好处只有在应用于大约 1000 亿参数的模型时才会显现,并且对较小模型的性能提升并不显著。
实验结果得出的结论是,较小的模型会产生流畅但不合逻辑的思路链,这导致其表现比标准提示更差。
参考文献
Wei, Jason, 等(2022)。思路链提示引发大型语言模型的推理。ArXiv。arxiv.org/abs/2201.11903
LLMs 的思维链提示
原文:
towardsdatascience.com/chain-of-thought-prompting-for-llms-33c963eead38
一个实用且简单的“推理”方法与 LLMs
·发表于 Towards Data Science ·阅读时长 16 分钟·2023 年 7 月 24 日
–
(照片由 Matthew Lancaster 提供,来自 Unsplash)
大型语言模型(LLMs)的成功源于我们能够在大量文本语料库上进行预训练(使用语言建模目标)仅解码器变换器模型。考虑到我们对足够大的模型进行预训练,LLMs 在少量样本学习方面表现出色。换句话说,这意味着我们可以通过简单地制定一个文本提示(可能包含一些正确输出的示例)并让 LLM 生成正确答案来解决各种不同的问题(例如,翻译、句子分类、摘要等)。
尽管 LLMs 非常强大,但这些模型仍然存在一些持续难以解决的问题。特别是,推理问题(例如,算术或常识推理)特别困难。最初的尝试是通过对监督数据集中的各种推理问题的解决方案和解释进行微调 LLMs 和任务特定的验证模块 [3, 4]。然而,最近的研究发现可以利用少量样本学习来找到更简单的解决方案。
“本文的目标是赋予语言模型生成思维链的能力——一系列连贯的中间推理步骤,这些步骤将引导到问题的最终答案。” — 来源于 [1]
特别是,链式思维(CoT)提示 [1] 是一种新提出的技术,通过少样本学习提升 LLM 在基于推理的任务上的表现。类似于标准的提示技术,CoT 提示将多个推理问题的示例解决方案插入到 LLM 的提示中。然后,每个示例都配有一系列思维链,即解决问题的中间推理步骤。LLM 然后以少样本的方式学习在解决推理问题时生成类似的思维链。这种方法使用最少的数据(即仅几个示例进行提示),无需特定任务的微调,并显著提高了 LLM 在基于推理的基准测试上的表现,尤其是对于较大的模型。
(来自 [1, 11])
核心概念
要理解 CoT 提示,我们需要对 LLMs 和 它们的工作原理有一个基本了解。幸运的是,我们在之前的综述中已经广泛覆盖了这个话题:
本节将不会涵盖大语言模型(LLMs)的基础知识。相反,我们将专注于提高对提示和少样本学习的理解,并探讨这些技术如何被用来解决这些模型的核心限制:它们无法解决推理任务。
提示和少样本学习
在 GPT 和 GPT-2 等语言模型提出后,我们知道通过 自监督 的下一词预测(或 语言建模)目标是非常强大的。然而,如何将这些通用的 基础模型 适配到特定的下游任务上并不十分明确。例如,GPT 在下游任务上微调模型,而 GPT-2 以零样本的方式解决问题;见下文。
(来自 [2])
在提出 GPT-3 [2] 后,我们看到足够规模的 LLM 可以非常好地进行少样本学习。在通过语言建模目标进行预训练后,GPT-3(一个 1750 亿参数的 LLM)被发现能够准确地解决各种不同的语言任务,而无需任何微调。我们可以用提示方法代替微调。
更具体地说,提示利用了语言模型的文本到文本结构,通过提供如下输入:
-
“将这个句子翻译成英语:
<sentence> =>
” -
“总结以下文档:
<document> =>
”。
这些任务解决“提示”使得在语言模型中进行零样本(即,不查看正确输出的示例;见上文)或少样本(即,在提示中插入一些正确输出的示例;见下文)推理成为可能。语言模型的最合适输出应该能够解决任务(例如,总结文档或完成推理任务),这意味着我们可以通过准确的下一个标记预测来解决各种问题!
(来自 [1, 2])
我们可以通过提示做很多事情。事实上,最近创建了一个专门的提示工程领域,研究如何优化提示的措辞或结构以提高 LLM 性能。但是,敏感性是这个发展中的领域中的一个重要考虑因素。LLM 的性能可能会因为输入提示的微小扰动而发生巨大变化(例如,少样本示例的排列导致 GPT-3 在 SST-2 [13] 上的准确率从 93.4% 降低到 54.3%)。因此,在我们对提示方法的研究中,我们旨在找到* i)* 表现良好且 ii) 不受敏感性影响的技术。
我们能通过扩大规模来解决推理问题吗?
如上所述,LLM 的少样本学习性能随着规模的增加而改善,但大模型并不是我们所需要的一切。强大的 LLM 需要与大规模预训练数据集的组合 [14]。考虑到这一点,我们可能会问自己:LLM 在基于推理的数据集上的表现如何?随着规模的扩大,LLM 是否在推理方面变得更好?
“单独扩大模型规模并不足以在如算术、常识和符号推理等具有挑战性的任务上取得高性能”— 来源于 [1]
有趣的是,我们发现使用更大的模型和预训练数据集并不会改善 LLM 的推理能力(例如,参见Gopher [15]的分析)。事实上,这些模型因无法解决基本推理任务而受到严厉批评。因此,许多研究人员声称 LLM 只是重复训练数据,而没有进行任何复杂的推理或分析。无论如何,本概述将重点关注试图解决这一问题并使 LLM 更容易解决基本推理任务的提示技术。
(来自[4])
先前的方法。 在进一步了解我们如何帮助 LLM 解决推理问题之前,了解这个领域中的先前方法是有用的。算术、常识和符号推理任务的基线技术执行任务特定的微调,即模型在每个推理问题的监督示例上进行训练。更进一步,最佳方法是训练一个补充的“验证”模块,该模块可以判断 LLM 在推理任务中的输出正确性[4]。在测试时,这个验证器可以在生成多个问题答案后推断出最佳可能的输出;参见上述内容。
尽管这些技术在某些情况下可能效果相对较好,但由于一些原因,它们有其局限性:
-
需要进行任务特定的微调。
-
模型架构必须针对每个任务进行适应(即,通过验证模型)。
-
必须收集大量的监督数据。
考虑到这些限制,显而易见,使用仅基于提示的方法(例如,CoT 提示)来解决推理任务将会简单得多。我们可以避免微调,保持相同的模型架构,收集更少的数据,并用一个单独的预训练模型检查点解决许多任务。
一些显著的 LLM…
CoT 提示是一种提示技术,旨在提高预训练 LLM 的少样本学习性能。在[1]中,使用了一个特定组的 LLM 进行评估,下面列出了这些模型并进行了说明。
-
GPT-3 [2]:一个拥有 1750 亿参数的预训练 LLM,使用标准语言建模目标进行训练。
-
LaMDA [5]:一个基于 LLM 的对话模型,使用语言建模目标进行预训练,然后在对话数据和人工反馈上进行微调(存在 422M、2B、8B、68B 和 137B 等不同规模的模型)。
-
PaLM [6]:一个使用标准语言建模目标、Google 的 Pathways 框架和大规模文本语料库进行预训练的 LLM(存在 8B、62B 和 540B 尺寸的模型)。
-
Codex [7]:一个具有 120 亿参数的 LLM,它在使用标准语言建模目标进行预训练后,针对 GitHub 上的公开 Python 代码进行了微调。
-
UL2–20B [8]:一个使用 Mixture-of-Denoisers (MoD) 目标进行预训练的 LLM,这是一个在许多数据集和设置中表现良好的统一目标。
除了这些 LLM,我们还在近期的综述中了解到其他模型(例如,LLaMA、LLaMA 扩展 和 T5)。
思维链提示
(来源于 [1])
尽管我们可能对提示的概念有一定了解,但CoT 提示是什么? CoT 仅指一种特定的提示技术,它将思维链(即一系列中间推理步骤)插入到 LLM 的提示中;见上文。对于足够大的模型(>1000 亿参数),这种方法显著提升了 LLM 在算术、常识和符号推理任务中的复杂推理能力。
CoT 提示的来源是什么? 在 CoT 提示提出之前,我们已经知道少样本学习对 LLM 极其强大;见下文。我们不是 fine-tuning LLM 以执行任务,而是“提示”一个通用模型,给出几个正确输出的例子,然后生成最终答案。这种方法在许多任务中 非常成功。
使用少样本提示进行上下文学习(来源于 [2])
此外,我们从相关研究中了解到,生成自然语言的推理来解释如何得出最终答案对算术推理任务有益。我们可以训练或微调模型来生成这些推理 [3, 4],但这需要创建一个用于不同推理任务的高质量推理数据集,这既昂贵又耗时!
“仅依靠提示的方法很重要,因为它不需要大量的训练数据集,而且单个模型可以在不丧失通用性的情况下执行许多任务。” — 来自 [1]
CoT 提示法结合了少量示例提示的优势和生成自然语言推理的好处。我们不需要额外的训练或微调,只需将一些推理示例(即思维链)插入到提示中,就可以让 LLM 通过少量示例学习生成类似的推理。
CoT 提示法是如何工作的?
当我们作为人类解决推理任务时,通常会将问题拆分为更小的任务。例如,我在计算在餐厅想要给多少小费时通常会这样做:
-
取账单总额:$56.00
-
计算总额的 10%:$5.60
-
将这个值乘以 2(产生 20%的小费):$11.20
尽管这个例子很简单,但这一理念可以扩展到我们作为人类解决的各种心理推理任务中。我们生成一个思维链(在[1]中定义为“引导问题最终答案的连贯中间推理步骤序列”)来解决这些任务。简单来说,CoT 提示法增强了 LLM 生成类似思维链的能力。
“我们探索语言模型在推理任务中进行少量示例提示的能力,前提是提示由三元组组成:[输入,思维链,输出]。” — 来自 [1]
下方展示了结合思维链解决的各种推理任务的示例。
(来自 [1])
学习思维链。 为了教导 LLM 生成问题解决的推理,我们可以将这些推理示例直接插入到提示中。然后,LLM 可以利用其少量示例学习能力在解决任何推理问题时生成类似的思维链。如下所示,提示通常包含几个思维链示例。
(来自 [1])
[1]中的作者发现,这种提示方法使 LLM 在解决问题时生成类似的思维链,这有助于推理能力,并具有几个显著的好处:
-
可解释性:LLM 生成的思维链可以用来更好地理解模型的最终答案。
-
适用性:CoT 提示法可以用于任何可以通过语言由人类解决的任务。
-
提示:不需要对任何 LLM 进行训练或微调。我们只需将一些 CoT 示例插入提示中即可!
此外,LLM 甚至可以通过生成更多步骤的思维链来分配更多计算资源给复杂的推理问题。这模仿了我们作为人类通常会做的事情!
CoT 提示法极其有益
为了评估 CoT 提示对 LLM 解决推理问题能力的影响,CoT 提示在算术、常识和符号推理基准上进行了测试。评估使用了几个不同的预训练 LLM,包括 GPT-3 [2]、LaMDA [5]、PaLM [6]、Codex [7] 和 UL2 [8]。作为基准,文献 [1] 中的作者使用了标准的少量提示,由 GPT-3 提出的。所有模型在评估过程中使用 贪婪解码,但通过对多个样本进行多数投票可以获得更好的结果 [9]。
算术推理。 算术推理任务包括数学应用题。这样的题目对人类来说很简单,但 LLM 常常对此感到困难。下面提供了 [1] 中使用的算术推理数据集的概述。
(来自 [1])
对于 CoT 提示,一组由八个少量示例组成的提示是手动编写的(无需大量提示工程),并且用于所有数据集,除了具有多项选择结构的 AQuA。下面展示了在多个 LLM 上进行 CoT 提示的算术推理数据集实验结果。
(来自 [1])
从这些实验中,我们发现 CoT 提示有几个显著的特点。首先,CoT 提示似乎在较大的 LLM(即>100B 参数)上效果更好。较小的模型通常产生不合逻辑的思考链,从而使性能低于标准提示。此外,更复杂的问题(例如 GSM8K)从 CoT 提示中获得的好处更大。与之前的最先进方法(执行任务特定的微调)相比,使用 GPT-3 和 PaLM-540B 的 CoT 提示在所有情况下都达到了相当或更好的性能。
当我们定性地检查 CoT 提示生成的正确和错误答案时,我们得到以下结论:
-
大多数正确答案是逻辑思考链的结果,除了少数偶然从错误的思考链中预测出正确答案的情况。
-
46% 的错误答案几乎是正确的,这意味着它们包含了有轻微错误的思考链。
-
56% 的错误答案是由于思考链在理解或推理上存在主要问题造成的。
[1] 中的作者还分析了 CoT 提示对不同结构(例如,置换少量示例)的鲁棒性,并剖析了 CoT 提示的各个方面,发现 CoT 对模型性能提供了一致且独特的好处。有趣的是,CoT 提示对小的提示扰动并不太敏感。
常识推理。 常识推理 问题假设对一般背景知识有掌握,并需要对物理和人类互动进行推理。作者采用类似于算术推理实验的设置(除了少数需要手动策划少量示例的数据集),评估了各种预训练的 LLM 在常识推理任务中的表现,结果如下面的图所示。
(来自 [1])
简而言之,CoT 提示在常识推理问题上也被发现提供了巨大的好处。我们再次看到,较大的模型从 CoT 提示中获益更多。然而,无论是标准提示还是 CoT 提示的表现都随着模型规模的增加而提高,其中 CoT 提示倾向于实现稍微提高的性能。
符号推理。 [1] 中的作者还在符号推理任务上评估了 CoT 提示,例如:
-
最后一个字母连接: 要求模型连接并输出序列中每个单词的最后一个字母。
-
硬币翻转: 要求模型确定经过一系列硬币翻转后,硬币是否仍然是正面朝上。
更进一步,考虑了领域内和领域外的符号推理测试,其中领域外示例被定义为那些需要比训练或少量示例中看到的更多推理步骤(例如,最后一个字母连接中更多的单词或更长的硬币翻转序列)的示例。领域内和领域外评估的结果如下所示。
(来自 [1])
尽管这些任务比较简单,但我们看到 CoT 思维提示在 i) 提升了符号推理任务的表现,并且 ii) 使模型在需要更多推理步骤的领域外问题中能够更好地泛化。此外,我们再次观察到,无论是否使用 CoT 提示,较小的模型都无法解决符号推理任务。因此,CoT 提示似乎是符号推理的一个极有益的方法。
CoT 提示的变体
在 [1] 中提出 CoT 提示后,提出了几种变体,可以提高 LLM 的推理能力。这些不同的变体为引发 LLM 中的“推理”行为提供了各种有趣和实用的方法。下方提供了一些值得注意的 CoT 提示变体列表。
(来自 [10])
零-shot CoT。 零-shot CoT 提示[10]是对 CoT 提示[1]的简单跟进。为了鼓励 LLM 生成思维链,零-shot CoT 仅在问题末尾添加了“让我们一步步思考。”这句话。通过在 LLM 的提示中加入这一简单的补充,我们在[10]中看到,LLM 即使在没有观察到这种行为的明确示例的情况下,也能生成思维链,从而在推理任务中得到更准确的答案。请参见上文,以比较零-shot CoT 与其他提示方法。
(来自 [11])
自一致性。 自一致性是 CoT 提示的一种变体,它使用 LLM 生成多个思维链,然后将这些生成的结果中多数票作为最终答案;见上文。在 CoT 提示无效的情况下,使用自一致性往往会提高结果。简单来说,自一致性只是用一个生成多个答案的 LLM 管道来替代[1]中使用的贪婪解码过程,并选择这些答案中最常见的作为最终答案。
(来自 [12])
从少到多提示。 从少到多提示通过首先将问题分解为更小的子问题,然后单独解决每个子问题,从而超越了 CoT 提示。在解决每个子问题时,其答案会被包含在提示中,用于解决下一个子问题。与 CoT 提示相比,从少到多提示在多个任务(例如,最后一个字母拼接)上提高了准确性,并改善了对需要更多推理步骤的领域外问题的泛化能力。
提示工程。 正如上述示例所示(以及 CoT 提示的想法),为 LLM 制定一个有用的提示是一门艺术。要了解更多关于如何设计更有效提示的信息,我强烈推荐访问这里提供的 Learn Prompting 网站上的课程。
关键点
在这一概述中,我们看到标准提示不足以充分发挥 LLM 的潜力。相反,它似乎提供了一种“下限”来衡量 LLM 的表现,尤其是在更困难的推理任务上。CoT 提示通过利用 LLM 的少量示例学习能力,超越了标准提示技术,从而在解决基于推理的问题时引导生成连贯的多步骤推理过程。这种方法对 LLM 的表现极为有利,尤其是对于更大的模型。以下是一些关键点。
CoT 提示的实用性。 LLMs 在处理常识、算术和符号推理等任务时表现不佳。然而,CoT 提示显著提高了这些任务的表现。此外,这种方法不需要 i) 微调和 ii) 最少的额外数据(即,仅需一组示例用于少量学习)。因此,这是一种易于使用的技术,经过一些提示工程和少量示例的策划,可以帮助预训练的 LLMs 解决它们通常面临的困难任务。
推理随着规模的增长而显现。 并非所有模型都能从 CoT 提示中受益。事实上,相较于较小的模型,较大的 LLMs 从 CoT 提示中获得的好处更加明显。在 [1] 中,作者观察到 CoT 提示的好处在参数超过 1000 亿的模型中显现。这个具体数字可能会严重依赖于实验设置,但总体思路很明确:CoT 提示的好处在较大的模型中最为明显。
“链式思维模拟了人类推理者的思维过程。这并不能回答神经网络是否真的在进行推理。” — 引自 [1]
LLMs 是否真的知道如何推理? CoT 提示帮助 LLMs 解决某些推理任务,但这并不一定意味着 LLMs 具备复杂的推理能力。[1] 的作者甚至明确指出 CoT 提示的分析并不能回答 LLMs 是否真正进行推理。相反,CoT 提示是一种经验性技术,可以更准确地解决像算术、常识和符号推理这样通常对 LLMs 成为难题的任务。无论我们是否相信 LLMs 能够推理,我们都可以同意这项技术在实际应用中非常有用。
结束语
感谢你阅读这篇文章。我是 Cameron R. Wolfe,Rebuy 的人工智能总监。我研究深度学习的经验和理论基础。你还可以查看我在 medium 上的 其他文章!如果你喜欢,请在 twitter 上关注我,或者订阅我的 Deep (Learning) Focus 新闻简报,我通过对流行论文的易懂概述帮助读者深入理解人工智能研究中的主题。
参考文献
[1] Wei, Jason, 等. “链式思维提示引发大规模语言模型的推理。” arXiv 预印本 arXiv:2201.11903 (2022)。
[2] Brown, Tom, 等. “语言模型是少量学习者。” 神经信息处理系统进展 33 (2020): 1877–1901。
[3] Wang Ling, Dani Yogatama, Chris Dyer, 和 Phil Blunsom. 2017. 通过理由生成的程序归纳:学习解决和解释代数文字问题。ACL。
[4] Karl Cobbe, Vineet Kosaraju, Mohammad Bavarian, Jacob Hilton, Reiichiro Nakano, Christopher Hesse 和 John Schulman. 2021. 训练验证者以解决数学文字问题。arXiv 预印本 arXiv:2110.14168。
[5] Thoppilan, Romal 等人。“Lamda: 对话应用的语言模型。” arXiv 预印本 arXiv:2201.08239(2022 年)。
[6] Chowdhery, Aakanksha 等人。“Palm: 扩展语言建模的途径。” arXiv 预印本 arXiv:2204.02311(2022 年)。
[7] Chen, Mark 等人。“评估训练于代码的大型语言模型。” arXiv 预印本 arXiv:2107.03374(2021 年)。
[8] Tay, Yi 等人。“Ul2: 统一语言学习范式。” 第十一届国际学习表征会议。2022 年。
[9] Xuezhi Wang, Jason Wei, Dale Schuurmans, Quoc Le, Ed Chi 和 Denny Zhou. 2022a. 自一致性改进语言模型中的思维链推理。arXiv 预印本 arXiv:2203.11171。
[10] Kojima, Takeshi 等人。“大型语言模型是零-shot 推理者。” arXiv 预印本 arXiv:2205.11916(2022 年)。
[11] Wang, Xuezhi 等人。“自一致性改进语言模型中的思维链推理。” arXiv 预印本 arXiv:2203.11171(2022 年)。
[12] Zhou, Denny 等人。“从最少到最多的提示使大型语言模型能够进行复杂推理。” arXiv 预印本 arXiv:2205.10625(2022 年)。
[13] Zhao, Zihao 等人。“使用前校准: 提升语言模型的少样本性能。” 国际机器学习会议。PMLR,2021 年。
[14] Hoffmann, Jordan 等人。“训练计算最优的大型语言模型。” arXiv 预印本 arXiv:2203.15556(2022 年)。
[15] Rae, Jack W. 等人。“扩展语言模型: 方法、分析与训练 Gopher 的见解。” arXiv 预印本 arXiv:2112.11446(2021 年)。
Llama 2 中的停止生成挑战
潜在解决方案的探索
·
关注 发表在 数据科学前沿 · 9 分钟阅读 · 2023 年 9 月 10 日
–
Llama: 图片由柳德米拉·舒瓦洛娃提供
Meta 发布的 Llama 2 在社区中引发了兴奋,标志着一个新的时代的开始,此前大型语言模型的良好表现只能通过公司特定的 API 访问。
然而,重要的是要承认这些模型固有的一些缺陷。其中,生成停止问题尤为突出。我的个人经历表明,这些模型往往难以确定合适的‘停止’点,使它们在何时结束文本生成方面感到不确定。
在这篇博客文章中,我将深入探讨最小的 Llama 2 模型——Llama 2–7b 模型中停止生成失败的问题,并讨论几种潜在的解决方案。接下来的实现可以在这个 GoogleGolab notebook中找到,运行时类型为 T4。
停止生成失败
在本节中,我们将利用 Google Colab 中配备充足高 RAM 资源的 T4 GPU 来操作 Llama 2–7b 模型(2.21 积分/小时)。需要记住的是,T4 GPU 具有 16 GB 的 VRAM 容量,刚好可以容纳 Llama 2–7b 的权重(7b × 2 字节 = 14 GB 的 FP16)。
为了有效管理 VRAM 的使用,我们将采用一种叫做量化的技术。量化是一种在推理过程中通过使用低精度数据类型表示权重和激活值来最小化计算和内存需求的方法。
现在让我们深入研究以下代码片段。在这里,我们将演示如何加载带有 Bite 和 Byte 配置的“meta-llama/Llama-2–7b-chat-hf”模型,并基于该加载模型设置文本生成管道。
# bit and byte configuration
bnb_config = transformers.BitsAndBytesConfig(
load_in_4bit=True, # 4-bit quantization
bnb_4bit_quant_type='nf4', # Normalized float 4
bnb_4bit_use_double_quant=True, # Second quantization after the first
bnb_4bit_compute_dtype=bfloat16 # Computation type
)
model_id= "meta-llama/Llama-2-7b-chat-hf"
device = f'cuda:{cuda.current_device()}' if cuda.is_available() else 'cpu'
# Llama 2 Tokenizer
tokenizer =transformers.AutoTokenizer.from_pretrained(model_id)
# Llama 2 Model
model = transformers.AutoModelForCausalLM.from_pretrained(
model_id,
trust_remote_code=True,
quantization_config=bnb_config,
device_map='auto',
)
model.eval()
# Difine pipeline
transformers.pipeline(model=model,
tokenizer=tokenizer,
return_full_text=True, # langchain expects the full text
task='text-generation',
# we pass model parameters here too
max_new_tokens=500, # max number of tokens to generate in the output
temperature=0.1,
)
这个配置使我们能够在一分钟以内为给定提示生成文本。让我们用一个简单的问题进行测试:“我在巴黎可以做些什么?”下面是答案(请注意,由于温度设置不同,您的结果可能会有所不同)。
Paris, the capital of France, is known for its stunning architecture, art museums, historical landmarks, and romantic atmosphere. everybody's dream destination. Here are some of the top things to do in Paris:
1\. Visit iconic landmarks: The Eiffel Tower, the Louvre Museum, Notre-Dame Cathedral, Arc de Triomphe, and the Champs-Élysées are must-visit attractions.
2\. Explore museums and art galleries: The Louvre, Musée d'Orsay, and Centre Pompidou are some of the world's most famous museums.
3\. Take a river cruise: A Seine River cruise is a great way to see the city's landmarks and bridges while learning about its history and culture.
4\. Discover the city's neighborhoods: From the fashionable Champs-Élysées to the charming Montmartre, each Parisian neighborhood has its own unique character and charm.
# I skipped some text here because of the limt of space#
Of course, there are countless
很明显,这个模型难以生成令人满意的响应;它似乎在确定何时结束输出方面存在困难。通过对生成的文本进行分词处理,可以明显看出最终的标记不是 2,而 2 代表了模型分词器中的 eos(序列结束)标记。
通过仔细检查模型提供的标记分数(概率),我注意到**token_id 2 (eso_token_id) 的分数为“-inf。”**这意味着它不可能被生成。
问题解决尝试
在本节中,我们将探讨几种旨在解决当前问题的潜在解决方案。需要记住的是,这里讨论的解决方案代表了积极的努力,但它们可能并不总是能解决所面临的问题。
Logits 处理器
像 Llama 2 这样的语言模型处理一系列文本标记作为输入,并根据从初始标记到当前标记的上下文生成下一标记的条件概率。鉴于此,值得考虑在接近最大标记限制时手动调整这些概率,以提高遇到 eos 标记的可能性。我们通过定义一个名为“EosTokenRewardLogitsProcessor”的自定义 Logits 处理器来实现这一点,该处理器具有两个初始输入 eos_token_id 和 max_length,其中后者表示模型应生成 eos 标记的最大长度:
class EosTokenRewardLogitsProcessor(LogitsProcessor):
def __init__(self, eos_token_id: int, max_length: int):
if not isinstance(eos_token_id, int) or eos_token_id < 0:
raise ValueError(f"`eos_token_id` has to be a positive integer, but is {eos_token_id}")
if not isinstance(max_length, int) or max_length < 1:
raise ValueError(f"`max_length` has to be a integer bigger than 1, but is {max_length}")
self.eos_token_id = eos_token_id
self.max_length=max_length
def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
cur_len = input_ids.shape[-1]
# start to increese the reward of the eos_tokekn from 80% max length progressively on length
for cur_len in (max(0,int(self.max_length*0.8)), self.max_length ):
ratio = cur_len/self.max_length
num_tokens = scores.shape[1] # size of vocab
scores[:, [i for i in range(num_tokens) if i != self.eos_token_id]] =\
scores[:, [i for i in range(num_tokens) if i != self.eos_token_id]]*ratio*10*torch.exp(-torch.sign(scores[:, [i for i in range(num_tokens) if i != self.eos_token_id]]))
scores[:, self.eos_token_id] = 1e2*ratio
return scores
在类的“call”方法中,我们根据序列的长度增强 eos_token 的概率(得分)。当长度接近指定最大长度的 80%时,我们将 eos_token_id 的得分设置为 1e2 乘以长度比例,并相应地调整其他令牌的得分。
现在在管道的定义中声明 logits 处理器:
pipe = transformers.pipeline(model=model,
tokenizer=tokenizer,
return_full_text=True, # langchain expects the full text
task='text-generation',
# we pass model parameters here too
#stopping_criteria=stopping_criteria, # without this model rambles during chat
logits_processor=logits_process_list,
max_new_tokens=500, # max number of tokens to generate in the output
temperature=0.1,
)
使用相同的提示“What Can I do in Paris”再次运行管道,我们得到:
Paris, the capital of France, is known for its stunning architecture, art museums, historical landmarks, and romantic atmosphere.
它运行得很好!我们即使得到的答案可能看起来很简短,但它是完整的。
微调
如果模型未能生成 EOS 令牌,为什么不考虑指示它这样做呢?通过使用包括以 EOS 令牌结尾的答案的数据集来微调模型,以提高模型性能的概念无疑是一个值得探索的有前景的途径。
在这一部分,我将毫不掩饰地使用这篇博客文章中奠定的基础,这篇文章采用了参数高效的微调(PEFT)方法,如 QLoRA,来微调 Llama 2–7b 模型。与其前身 LoRA 类似,QLoRA 利用一小组可训练的参数(适配器),同时保持核心模型参数不变。它引入了两个值得注意的创新:4-bit NormalFloat (NF4),一种对正常数据信息理论上最优的数据量化方法,以及双重量化。欲了解更多深入信息,请参考原始论文,如果您对该主题有进一步的兴趣。
让我们在一个名为‘timdettmers/openassistant-guanaco’的数据集上训练模型,您可以在 hugging face 数据库中找到这个数据集。该数据集的格式如下,其中人类和助手的对话由“###”分隔。
图片作者:“timdettmers/openassistant-guanaco”的数据集
在训练之前,我们需要将数据转换为 Llama 2 提示模板:
<s>[INST] <<SYS>>
{your_system_message}
<</SYS>> {user_message_1} [/INST]
我将在这里跳过数据集转换的细节。现在让我们看看以下代码给出的训练的主要部分:
# Load LoRA configuration
peft_config = LoraConfig(
lora_alpha=lora_alpha,
lora_dropout=lora_dropout,
r=lora_r,
bias="none",
task_type="CAUSAL_LM",
)
# Set supervised fine-tuning parameters
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_config,
dataset_text_field="text",
max_seq_length=max_seq_length,
tokenizer=tokenizer,
args=training_arguments,
packing=packing,
)
# Train model
trainer.train()
在一个包含指令和响应的数据集中,我们的方法涉及使用监督训练器(SFTainer)与 QLoRA 方法相结合,以微调语言模型(LLM)中的权重参数。我们的主要目标是最小化生成的答案与真实响应之间的差异,真实响应作为我们的参考标签。
在这个配置中,一个重要的参数是“lora r”,它代表了一个相对较小的值,涉及到秩分解权重矩阵的第二维和第一维。训练仅在这两个矩阵上进行,补充了现有的权重。
我们训练模型 250 步,训练损失如下图所示:
图片来源:Llama 2 训练 250 步的损失
现在让我们使用微调后的模型运行管道。这一次,我们得到了:
Paris, the capital of France, is known for its stunning architecture, rich history, and cultural attractions. Here are some popular things to do in Paris:
1\. Visit iconic landmarks: The Eiffel Tower, Arc de Triomphe, Notre-Dame Cathedral, and the Louvre Museum are some of the most famous landmarks in Paris.
2\. Explore museums and art galleries: Paris is home to many world-class museums and art galleries, including the Louvre, the Musée d'Orsay, and the Pompidou Center.
3\. Enjoy the city's gardens and parks: Paris has several beautiful gardens and parks, including the Luxembourg Gardens, the Tuileries Garden, and the Champ de Mars.
4\. Take a river cruise: A river cruise along the Seine is a great way to see the city's sights and learn about its history.
5\. Shop on the Champs-Élysées: The famous avenue is lined with high-end boutiques, department stores, and cafes.
6\. Attend a cabaret show: The Moulin Rouge is a famous cabaret that offers a lively and entertaining show.
7\. Visit Montmartre: The charming neighborhood of Montmartre is known for its artistic vibe, street performers, and stunning views of the city.
8\. Take a food tour: Paris is known for its culinary delights, and a food tour is a great way to sample the city's famous cuisine.
9\. Visit the Palace of Versailles: The Palace of Versailles is a beautiful royal palace located just outside of Paris.
10\. Attend a fashion show: Paris is the fashion capital of the world, and attending a fashion show is a great way to see the latest trends and styles.
These are just a few of the many things to do in Paris. The city has something for everyone, from history and culture to food and entertainment.
这是一个相当美丽的答案!
附加:给出不同的提示
最终,我们手头有一个简单而有效的技巧,特别是当模型的冗长不是问题时。我们可以在提示中明确说明我们需要一个简洁的回答。例如,当我问模型:“在巴黎我可以做什么?请用五句话或更少的句子回答,”它会提供:
Sure! Here are five things you can do in Paris: 1\. Visit the Eiffel Tower, a iconic landmark that offers stunning views of the city. 2\. Explore the Louvre Museum and see famous artworks like the Mona Lisa. 3\. Stroll along the Seine River and enjoy the city's picturesque bridges and charming streets. 4\. Visit the Notre-Dame Cathedral, a beautiful and historic church. 5\. Enjoy a delicious French meal at a traditional bistro or restaurant.
这是一个简短但干净且完整的回答。
停止标准:一个失败的尝试
对于感兴趣的用户,Hugging Face 推出了另一个名为 StoppingCriteria 的 API,旨在建立特定条件以强制序列停止。然而,当涉及到定义一个在遇到某些标记(例如‘\n’)时停止模型的自定义标准时,它可能无法提供一个全面的解决方案。例如,我尝试创建一个 StopOnTokens 类:
# define custom stopping criteria object
class StopOnTokens(StoppingCriteria):
def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
for stop_ids in stop_token_ids:
if torch.eq(input_ids[0][-len(stop_ids):], stop_ids).all():
return True
return False
stopping_criteria = StoppingCriteriaList([StopOnTokens()])
但是,模型仍然无法给出完整的回答。
结论
在这篇博客文章中,我强调了 Llama 2 中生成停止的问题,并介绍了几种临时解决方案。再次,我跳过了很多实施细节,我建议你深入查看我的笔记本。
图片由Jose Aragones提供
但是,需要注意的是,这些解决方案旨在在短期内提高响应的用户友好性,但我们迫切期待一个永久的解决方案来解决这个问题。
检测 AI 生成文本的挑战
我们将深入探讨检测 AI 生成文本的挑战,以及在实际应用中所使用技术的有效性。
·
关注 发表在 Towards Data Science ·15 min read·Sep 27, 2023
–
图片由 Houcine Ncib 提供,来源于 Unsplash
与 Naresh Singh 共同撰写。
目录
-
介绍
-
建立文本来源检测的直觉
-
语言模型的困惑度是什么?
-
计算语言模型预测的困惑度
-
检测 AI 生成文本
-
错误信息
-
接下来是什么?
-
结论
介绍
现在写文章或帖子用的 AI 辅助技术无处不在!ChatGPT 开启了基于语言的 AI 的众多应用,AI 在任何类型内容生成中的使用已经达到了空前的高度。
然而,在诸如创意写作之类的学校作业中,学生需要创建自己的内容。然而,由于 AI 在这些任务中的流行和有效性,学生可能会被诱惑去使用它。在这种情况下,教师拥有能够检测 AI 生成内容的可靠工具就显得尤为重要。
本文旨在提供对构建此类工具的直观理解以及技术规格。它面向那些希望直观理解 AI 检测工作原理的读者以及希望构建此类工具的技术观众。
让我们直接进入主题!
建立文本来源检测的直观理解
从高层次来看,我们试图回答的问题是,“AI 语言模型(如 GPT-3)生成全部或部分文本的可能性有多大?”
如果你退一步看,你会意识到这是一种典型的日常情境。例如,你母亲对你说以下句子的可能性有多大?
-
亲爱的,请在晚上 8 点之前上床睡觉。
-
亲爱的,请在晚上 11 点后上床睡觉。
我们猜测前者的可能性远高于后者,因为你对周围世界已经有了一定的理解,并且对哪些事件更可能发生有了感觉。
这正是语言模型的工作原理。语言模型学习有关周围世界的知识,特别是语言。它们学习在给定不完整句子的情况下预测下一个标记或单词。
在上面的例子中,如果你被告知你母亲正在说话,而迄今为止所说的是*“亲爱的,请在睡觉”,那么这个句子的最可能的继续就是“在晚上 8 点之前”,而不是“在晚上 11 点之后”。用技术术语来说,我们说你会对听到第二句话而非第一句话感到更多的困惑*。
让我们深入探讨一下在语言模型的背景下困惑度的含义。
语言模型的困惑度是什么?
根据 dictionary.com,困惑度被定义为
困惑的状态;混乱;不确定性。
在现实世界中,如果你遇到一个你没有预料到的情况,你会比遇到一个你预料到的情况感到更多的困惑。例如,当你在路上行驶时,如果你看到一个交通信号灯,那么你会比看到一只穿过街道的山羊时感到更少的困惑。
同样,对于一个试图预测句子中下一个单词的语言模型来说,我们说如果模型用一个我们没想到的单词来完成句子,它会让我们感到困惑,相比之下,如果它使用我们期待的单词。以下是一些例子。
低困惑度的句子看起来会是这样的
-
外面的天气晴朗。
-
对不起,我错过了航班,未能及时到达国家公园。
具有高困惑度的句子可能如下所示
-
外面的天气很好。
-
我错过了光线,无法到达国家公园。
接下来,让我们看看如何计算语言模型做出的预测的困惑度。
计算语言模型预测的困惑度
语言模型的困惑度与能够意料之外地预测句子下一个标记(单词)的概率相关。
假设我们用一个包含 6600 个标记的词汇表训练语言模型,并运行一个预测步骤以让模型预测句子中的下一个标记。假设选择该标记的概率是 5/6600(即,该标记的概率不是很高)。其困惑度是概率的倒数,即 6600/5 = 1320,这表明 我们对这个建议感到非常困惑。如果选择该标记的概率是 6000/6600,那么困惑度将是 6600/6000 = 1.1,这表明我们对这个建议感到仅仅是稍微困惑。
因此,模型在更可能的预测上的困惑度低于模型在不太可能的预测上的困惑度。
预测句子“x”中所有标记的困惑度形式上定义为标记概率乘积的倒数的 N 次根。
然而,为了确保数值稳定性,我们可以用对数函数来定义它。
这是 e(2.71828)到预测标记为真实标记的平均负对数似然的幂。
训练和验证困惑度
模型的训练和验证困惑度可以直接从批次或时期的损失计算得出。
预测困惑度
由于需要一组每个预测的真实标签,因此无法计算预测困惑度。
计算困惑度的 PyTorch 代码
假设变量 probs 是一个形状为 (sequence_length,) 的 torch.Tensor,它包含了语言模型在序列中该位置上预测的真实标记的概率。
可以使用以下代码计算每个标记的困惑度。
token_perplexity = (probs.log() * -1.0).exp()
print(f"Token Perplexity: {token_perplexity}")
可以使用以下代码计算样本困惑度。
# The perplexity is e^(average NLL).
sentence_perplexity = (probs.log() * -1.0).mean().exp().item()
print(f"Sentence Perplexity: {sentence_perplexity:.2f}")
接下来,让我们查看一下计算给定句子的每个标记概率的代码。
def get_pointwise_loss(self, inputs: List[str], tok):
self.model.eval()
all_probs = []
with torch.inference_mode():
for input in inputs:
ids_list: List[int] = tok.encode(input).ids
# ids has shape (1, len(ids_list))
ids: Torch.Tensor = torch.tensor(ids_list, device=self.device).unsqueeze(0)
# probs below is the probability that the token at that location
# completes the sentence (in ids) so far.
y = self.model(ids)
criterion = nn.CrossEntropyLoss(reduction='none', ignore_index=0)
# Compute the loss starting from the 2nd token in the model's output.
loss = criterion(y[:,:,:-1], ids[:,1:])
# To compute the probability of each token, we need to compute the
# negative of the log loss and exponentiate it.
loss = loss * -1.0
# Set the probabilities that we are not interested in to -inf.
# This is done to make the softmax set these values to 0.0
loss[loss == 0.0] = float("-inf")
# probs holds the probability of each token's prediction
# starting from the 2nd token since we don't want to include
# the probability of the model predicting the beginning of
# a sentence given no existing sentence context.
#
# To compute perplexity, we should probably ignore the first
# handful of predictions of the model since there's insufficient
# context. We don’t do that here, though.
probs = loss.exp()
all_probs.append(probs)
#
#
return all_probs
#
现在我们对语言模型的功能以及如何计算每个标记和每个句子的困惑度有了一些了解,让我们试着把这些信息结合起来,看看如何利用这些信息构建一个可以检测文本是否由 AI 生成的工具。
检测 AI 生成的文本
我们已经拥有检查文本是否由 AI 生成所需的所有成分。这里是我们需要的一切:
-
我们希望检查的文本(句子或段落)。
-
该文本的分词版本,使用与该模型的训练数据集相同的分词器进行分词。
-
经过训练的语言模型。
利用以上 1、2 和 3,我们可以计算以下内容:
-
模型预测的每个 token 的概率。
-
使用每个 token 的概率计算的困惑度。
-
整个句子的总困惑度。
-
模型在训练数据集上的困惑度。
要检查文本是否由 AI 生成,我们需要将句子的困惑度与模型的困惑度(经过调整的系数 alpha)进行比较。如果句子的困惑度高于调整后的模型困惑度,则可能是人类撰写的文本(即不是 AI 生成的)。否则,可能是 AI 生成的。原因在于,我们期望模型不会对它自己生成的文本感到困惑,因此如果它遇到一些自己不会生成的文本,那么就有理由相信这些文本不是 AI 生成的。如果句子的困惑度小于或等于经过调整的模型训练困惑度,那么很可能是使用该语言模型生成的,但我们不能非常确定。这是因为一个人也有可能写出这样的文本,而且这正好是模型也可能生成的内容。毕竟,模型是在大量人类写作的文本上训练的,所以在某种意义上,模型代表了一种“普通人类的写作”。
上述公式中的*ppx(x)*表示输入“x”的困惑度。
接下来,让我们查看一些人类撰写的文本与 AI 生成的文本的例子。
AI 生成的文本与人类撰写的文本的例子
我们编写了一些 Python 代码,根据每个 token 相对于模型困惑度的困惑度对其着色。如果我们不考虑其困惑度,第一个 token 总是呈黑色。困惑度小于或等于模型困惑度的 token 被着色为红色,表明它们可能是 AI 生成的,而困惑度较高的 token 被着色为绿色,表明它们肯定不是 AI 生成的。
句子前方方括号中的数字表示使用语言模型计算的句子困惑度。注意某些单词有部分红色和部分蓝色。这是因为我们使用了子词分词器。
这是生成上述 HTML 的代码。
def get_html_for_token_perplexity(tok, sentence, tok_ppx, model_ppx):
tokens = tok.encode(sentence).tokens
ids = tok.encode(sentence).ids
cleaned_tokens = []
for word in tokens:
m = list(map(ord, word))
m = list(map(lambda x: x if x != 288 else ord(' '), m))
m = list(map(chr, m))
m = ''.join(m)
cleaned_tokens.append(m)
#
html = [
f"<span>{cleaned_tokens[0]}</span>",
]
for ct, ppx in zip(cleaned_tokens[1:], tok_ppx):
color = "black"
if ppx.item() >= 0:
if ppx.item() <= model_ppx * 1.1:
color = "red"
else:
color = "green"
#
#
html.append(f"<span style='color:{color};'>{ct}</span>")
#
return "".join(html)
#
从上面的例子可以看出,如果模型将某些文本检测为人类生成的,那么这些文本确实是人类生成的,但如果模型将文本检测为 AI 生成的,那么有可能并非 AI 生成的。那么为什么会发生这种情况呢?让我们接着看!
假阳性
我们的语言模型经过大量由人类编写的文本训练。通常很难检测到某个特定人是否(数字化)编写了某些内容。模型的训练输入包含了许多不同的写作风格,很可能是由大量不同的人编写的。这使得模型学习了许多不同的写作风格和内容。很可能你的写作风格与模型训练中某些文本的写作风格非常接近。这就是假阳性出现的原因,也是模型不能确定某些文本是否是 AI 生成的原因。然而,模型可以确定某些文本是人类生成的。
OpenAI: OpenAI 最近宣布将停止其用于检测 AI 生成文本的工具,理由是准确率较低(来源:Hindustan Times)。
AI 分类器工具的原始版本从一开始就存在某些局限性和不准确性。用户需要手动输入至少 1,000 个字符的文本,然后 OpenAI 会分析这些文本以分类为 AI 或人类编写。不幸的是,该工具的表现不尽如人意,因为它仅正确识别了 26% 的 AI 生成内容,并且错误地将 9% 的人类编写文本标记为 AI。
这是 OpenAI 的博客文章。看起来他们使用了与本文中提到的不同的方法。
我们的分类器是一个语言模型,经过微调,使用的是同一主题的人工编写文本和 AI 编写文本的对照数据集。我们从多个我们认为是由人类编写的来源收集了这个数据集,比如预训练数据和提交给 InstructGPT 的人类演示。我们将每篇文本分为提示和回应。在这些提示上,我们生成了来自我们和其他组织训练的各种语言模型的回应。对于我们的网页应用,我们调整了置信度阈值,以保持低的假阳性率;换句话说,我们只有在分类器非常确信的情况下才将文本标记为可能的 AI 编写。
GPTZero: 另一个流行的 AI 生成文本检测工具是 GPTZero。看起来 GPTZero 使用 困惑度和突发性 来检测 AI 生成的文本。“突发性指的是某些词语或短语在文本中以突发的形式出现。换句话说,如果一个词在文本中出现了一次,它很可能会在接近的地方再次出现”(来源)。
GPTZero 宣称具有非常高的成功率。根据 GPTZero FAQ,“在 0.88 的阈值下,85% 的 AI 文档被分类为 AI,99% 的人工文档被分类为人工。”
这种方法的普遍性
这篇文章提到的方法不具有很好的一般化性。我们的意思是,如果你有三个语言模型,比如 GPT3、GPT3.5 和 GPT4,那么你必须将输入文本通过这三个模型,并检查它们的困惑度,以确定文本是否由其中任何一个模型生成。这是因为每个模型生成文本的方式略有不同,它们都需要独立评估文本,以确定是否有模型生成了该文本。
随着到 2023 年 8 月世界上大量语言模型的普及,似乎不太可能检查任何文本是否来自世界上的任何语言模型。
实际上,每天都有新的模型在训练,跟上这种快速进展似乎非常困难。
以下示例显示了让我们的模型预测 ChatGPT 生成的句子是否为 AI 生成的结果。如你所见,结果是混合的。
紫色框中的句子被我们的模型正确识别为 AI 生成的,而其余的则被错误识别为人工撰写的。
这可能发生的原因有很多。
-
训练语料库规模: 我们的模型在非常少的文本上进行训练,而 ChatGPT 在数 TB 的文本上进行训练。
-
数据分布: 我们的模型在与 ChatGPT 不同的数据分布上进行训练。
-
微调: 我们的模型只是一个 GPT 模型,而 ChatGPT 是针对聊天类响应进行微调的,使其生成的文本具有略微不同的语调。如果你有一个生成法律文本或医学建议的模型,那么我们的模型在这些模型生成的文本上也会表现不佳。
-
模型规模: 我们的模型非常小(少于 100M 参数,而 ChatGPT 类模型有超过 200B 参数)。
很明显,如果我们希望提供合理高质量的结果以检查文本是否为 AI 生成的,我们需要一种更好的方法。
接下来,我们来看一下关于这个话题在互联网中流传的一些错误信息。
错误信息
一些文章对困惑度的解释不正确。例如,如果你在 google.com 搜索 “人工撰写内容的困惑度高还是低?”,你会在第一个位置看到 以下结果。
这是不正确的,因为人工撰写的内容通常比 AI 生成的内容具有更高的困惑度。
让我们来看看研究人员在这一领域探索的技术,以期比目前的情况做得更好。
接下来是什么?
我们已经确定,检测 AI 生成文本是一个困难的问题,成功率低到不比猜测更好。让我们看看这一领域的最先进技术,研究人员如何探索以更好地处理这个问题。
水印: OpenAI 和 Google 已承诺为 AI 生成的文本添加水印,以便可以程序化识别。
关于这种水印如何工作的技术细节尚不清楚,两家公司都没有披露相关细节。
即使 OpenAI 和 Google 采用了水印技术,我们也不能确定所有部署的语言模型都会包含水印。人们仍然可能会部署自己的模型来生成文本并将其发布到公共平台。即使公司决定给生成的文本加水印,也不清楚这是否会成为标准,还是每家公司会有自己的专有策略和可能收费的工具来检查文本是否由其 AI 文本生成工具生成。如果这是一个开放标准,人们有可能绕过它,除非它像加密密码一样需要大量计算来解密。如果不是开放标准,那么人们将依赖这些公司提供开放和免费的工具及 API 来进行检查。此外,这些工具在长期中的有效性也是一个问题,因为甚至可能训练模型来接收带水印的 AI 生成文本,并返回没有水印的 AI 生成文本。
这篇文章讨论了一种为 AI 生成文本添加水印的可能技术,并提到这种方法的重大挑战。
个性化: 在我们看来,检测 AI 生成文本的问题在短期内仍将具有挑战性。我们相信,策略需要变得更加侵入性和个性化才能更有效。例如,与其询问某些文本是否由 AI 生成,不如询问这些文本是否由特定的人撰写。然而,这将要求系统能够访问大量该特定人撰写的文本。此外,如果某些文本由多人撰写,如本文所示,问题会变得更加复杂。
让我们看看这种个性化的系统在检测人工撰写文本方面对教育工作者和学生的影响。
如果存在这样的解决方案,教育工作者将更倾向于给学生布置个人作业而不是小组作业。这还将要求每个学生首先提供大量他们自己撰写的文本。这可能意味着在入学前需要在大学里亲自花费几个小时。这无疑会对教授学生团队合作以实现共同目标的重要性产生负面影响。
另一方面,在某些情况下,访问基于 AI 的文本生成技术可以让学生集中精力解决实际问题,例如进行研究或文献研究,而不是花时间以完善的方式撰写他们的学习成果。可以想象,学生们会在数学或科学课程中花更多时间学习概念和技术,而不是写作。那部分可以由 AI 处理。
结论
在本文中,我们建立了如何检测 AI 生成文本的直觉。我们可以使用的主要指标是生成文本的困惑度。我们看到了一些 PyTorch 代码,用于检查给定文本是否可能是 AI 生成的,方法是利用文本的困惑度。我们也看到了这种方法的一些缺点,包括可能出现假阳性。希望这能帮助你理解和欣赏检测 AI 生成文本的细节。
这是一个不断发展的领域,研究人员正努力寻找一种更高准确率检测 AI 生成文本的方法。这项技术对我们生活的影响承诺将是显著的,并且在许多方面仍然未知。
虽然我们讨论了检测 AI 生成文本的技术,但我们假设整个文本要么是人类撰写的,要么是 AI 生成的。实际上,文本往往是部分人类撰写的,部分 AI 生成的,这使得问题变得更加复杂。
如果你想了解更多检测 AI 生成文本的方法,比如使用突发性指标,你可以在这里阅读。
本文中的所有图片(除了第一张)均由作者(们)创作。
中国量产自动驾驶的挑战
原文:
towardsdatascience.com/challenges-of-mass-production-autonomous-driving-in-china-407c7e2dc5d8
以及 2023 年小鹏汽车的最新进展
·发表于 Towards Data Science ·阅读时间 7 分钟·2023 年 6 月 19 日
–
本博客文章基于在 2023 年温哥华 CVPR 的端到端自动驾驶研讨会上的主题演讲,题为“中国量产自动驾驶的实践”。主题演讲的录音可以在这里找到。
自动驾驶是一个令人望而生畏的挑战,特别是在中国,这里的人类驾驶已经是世界上最具挑战性的之一。主要涉及三个因素:动态交通参与者、静态道路结构和交通信号。特别是,交通灯控制信号带来了独特的挑战,因为它们在几何上是静态的,但在语义上是动态的。在接下来的会议中,我们将简要回顾动态对象和静态环境,并深入探讨交通灯这一有趣且特殊的话题。
[## CVPR 2023 自动驾驶研讨会 | OpenDriveLab
我们自豪地宣布今年与我们的合作伙伴 - Vision-Centric… 合作推出的四项全新挑战。
opendrivelab.com](https://opendrivelab.com/e2ead/cvpr23.html?source=post_page-----407c7e2dc5d8--------------------------------)
动态与静态挑战
动态交通参与者,如易受伤害的道路使用者(VRUs),给中国的自动驾驶车辆带来了重大挑战。VRUs 通常是不可预测的,以不同的姿态出现,常常出现在司机最意想不到的地方。大型动物可能会突然出现在乡村道路上,而宠物可能会漫游到城市街道上。此外,装载物品的车辆或三轮车的具体类型也很难确定。考虑一下中间行的最后一张照片,它实际上即使对于人类来说,第一次看到场景也非常具有挑战性。那辆装满树枝的车辆无意中完全隐匿在环境中。
各种动态道路使用者
静态道路结构和拓扑对自动驾驶车辆也可能构成重大挑战。例如,这里展示的复杂交叉口突显了需要解决的复杂程度。虽然看起来像是科幻电影中的截图,但这个交叉口实际上是在谷歌地球上可以查看的真实地点。
复杂交叉口的卫星图像
如果我们放大,就会发现一个有趣的道路元素,这可能在中国是独一无二的——左转待行区。它旨在提高左转交通的通行量,使更多的车辆在一个交通信号周期内通过交叉口。注意,这种设计可能并不对称,每个方向的设计都是根据交通模式单独设计的。我们甚至可以找到关于它及其效果的学术论文。尽管它的提出出于良好的意图,但对于新司机和自动驾驶车辆来说,可能真的很困惑。
在有待行区的交叉口左转涉及两个步骤。它们都涉及不同的交通信号灯组合。在这里,我只展示了最常见的交通信号灯模式。交通信号灯组合可能更复杂,有时涉及专门用于待行区的特殊交通信号灯。
左转待行区由科学论文支持
角落案例之王:交通信号灯
现在我们可以深入探讨交通信号灯的所有角落案例。交通信号灯可能是拥有最多长尾角落案例的对象类别。交通信号灯的感知复杂有两个原因。首先,我们必须识别交通信号灯的位置、类型和颜色,然后我们还需要知道在我们检测到的所有交通信号灯中(这里有六个),我们的车辆应该关注哪一个。为了做出这个决定,必须获得交通信号灯与不同车道之间的正确匹配。
中国典型的交通信号灯场景
一种特殊类型的灯是专为公交车设计的交通信号灯。我们需要正确识别它们有两个不同的原因。首先,为了规划和控制自车,我们需要识别它们以正确忽略它们,因为它们可能传递与我们需要关注的信号灯冲突的信息,从而给我们的自动驾驶车辆带来困惑。然而,要预测附近公交车的潜在操作,我们也需要正确了解其状态。
公交车交通信号灯
中国为公交车设计的交通信号灯有多种形式,包括标有“BRT”、“SRT”、“Bus”或单个字母“B”的 LED 灯。它们还可以具有特定的中文字符,如“公交”或“有轨电车”,有时还包括描绘可爱小公交车的图标。除了这些特征外,还可能包括交通标志修饰符,这使得自动驾驶车辆必须检测和识别这些特征,并将其准确地与相应的交通信号灯关联起来。
多灯泡交通信号灯
除了专门为公交车设计的交通信号灯外,另一种复杂的交通信号灯是多灯泡交通信号灯。与传统交通信号灯一次只点亮一个灯泡不同,多灯泡交通信号灯可能在同一个插座中同时点亮多个灯泡。因此,检测交通信号灯盒是不够的;同样重要的是要检测单个灯泡,并准确解释它们的语义。
在多灯泡交通信号灯的附加图像中,我们还看到了一些额外的数字。它们是倒计时计时器,显示下一个颜色变化的时间。我们在北美很常见到行人倒计时计时器,但这些计时器是为车辆设计的。如果正确使用这些信息,它们可能有助于改善行驶的顺畅度。
倒计时计时器交通信号灯
倒计时计时器可以采取多种形式并以不同的方式呈现。它们可以是独立显示的,也可以与交通信号灯系统集成。数字的格式可能有所不同,包括前导零的使用与否,使用的字体也可能有所不同,有些字体更具艺术性。此外,还有一些交通信号灯设计成进度条的样式。这涉及到一个动画,其中进度条逐渐缩短,然后变成不同颜色的完整进度条。虽然这种设计可能被认为是最创新的,但它也可能给我们的感知工程师带来挑战。
左转等待区交通信号灯
最后,还有专用于等待区的交通信号灯,它们可以以图标或文本的形式出现。图标类型通常还涉及动画,灯光逐渐点亮以引导你到等待区。文本类型可能在 LED 显示屏或交通标志牌上。对于文本,没有标准模式,这需要光学字符识别(OCR)和一些自然语言处理来提取语义。
XNGP:Xpeng 的自动驾驶解决方案
记录了大规模生产的 Xpeng 车辆自动左转的情况
记录了大规模生产的 Xpeng 车辆自动右转的情况
尽管面临这些挑战,截至 2023 年,Xpeng 团队成功交付了中国业界领先的自动驾驶解决方案。周围现实(SR)显示屏仅显示从车载感知系统获得的信息。左侧显示准确检测道路几何,而右侧则描绘了常见场景,即一群行人正在过马路。值得注意的是,展示的镜头代表了市场上现有的大规模生产 Xpeng 车辆的实际录制,没有任何后期修改。
如果你对这一切如何实现感兴趣,请参阅另一篇关于 XNet 部署的文章——这是 BEV(鸟瞰视角)范式中的端到端感知堆栈。它是上述大规模生产自动驾驶解决方案的关键推动力,并为完全端到端的自动驾驶解决方案奠定了坚实的基础。
XNet 的配方,Xpeng 的 BEV 感知架构
主要收获
-
在中国驾驶具有挑战性,因为动态物体无处不在,复杂的道路拓扑,以及交通信号灯的极端长尾边缘案例。
-
交通信号灯有许多特殊类型,每种类型都有很多边缘案例。有时需要综合考虑多个交通信号灯,还要考虑附近的倒计时器或交通标志。
-
截至 2023 年,Xpeng Motors 迎接了这些挑战,并在中国交付了业界领先的大规模生产自动驾驶产品。
参考文献
- Ma, Wanjing, et al. “增加左转等待区的信号化交叉口的容量。” 运输研究 A 部分:政策与实践 105 (2017): 181–196.
变化点检测 — 一种贝叶斯方法
在时间序列分析中识别变化点可以提供比你之前认为的更多信息。
·
关注 发表于 Towards Data Science ·13 分钟阅读·2023 年 5 月 4 日
–
变化点分析已经成为许多研究领域的关注点。这种分析涉及到寻找给定时间序列中的突然或突发的变化。根据 Iwata et al.(2018)的定义,变化点分析是“识别变化点的方法,即时间序列概率分布发生变化的时刻。” 根据 Van den Burg 和 Williams(2020)的说法,“时间序列行为中的突发变化时刻通常会引起警报,因为它们可能暗示数据生成过程中的重大变化。”
正如 Aminikhanghahi 和 Cook (2017) 以及 Iwata 等人 (2018) 所示,对这种分析的关注度增加是由于最近的技术发展。这些发展生成大量的数据,这些数据往往需要被密切监控,例如机器人技术、医学、气象、语音和图像识别等。应对这些问题有多种模型和方法。然而,由于本文的目标不是对这些模型进行描述性分析,我建议你参考 Van den Burg 和 Williams (2020) 的工作,以更好地了解这些方法论。在那里你可以找到在线和离线变化点检测的区别;单变量和多变量方法,这些方法可以是参数化的或非参数化的;以及监督或无监督模型。
图片来源 Tech Daily — Unsplash
从一开始,根据 Ehlers (2007) 的定义,“时间序列是指在时间上顺序进行的观测集合”,其主要特征是给定观测对邻近观测的依赖性。时间序列可以是连续的或离散的,在前一种情况下,根据 Ehlers (2007) 的定义,集合 T={t∶ t1< t < t2}, 该序列表示为 {X(t):t ∈ T}。因此,取时间序列 T 的一个观测窗口,包含 n 个观测值,我们得到一个表示为 {Xm, X(m+1),…, Xn } 的时间序列。根据 Aminikhanghahi 和 Cook (2017,第 3 页) 的说法,“变化点的检测可以定义为一个假设检验问题,存在两个备选方案”,即“原假设 H0: ‘没有变化’” 和备择假设 H1: ‘发生了变化’”。
从一开始
所以,如果你喜欢编程,是时候启动 Jupyter Notebook 并开始进行一些模拟和分析,我们将通过这种方法进行“随机漫步”。让我们导入以下包:
import numpy as np
from numpy.random import seed
from numpy.random import randn
import random
import datetime
import matplotlib.pyplot as plt
import seaborn as sns
import math
import decimal
from scipy import stats
np.seterr(divide='raise') #Make sure you set this
我们将从一个时间序列 y(t) 开始,该序列由两个时间序列组成,y(t1) 的均值是 μ=1 加上一些噪声,y(t2) 的均值是 μ=2 加上一些噪声,两个序列都有 30 个观测值。正如你可能想的那样,提议的时间序列将会有一个显著的变化点。
yt1 = u1 + 0.1*randn(30)
yt2 = u2 + 0.1*randn(30)
y = np.concatenate((yt1, yt2), axis=0)
plt.figure(figsize=(16, 10))
plt.plot(y)
一个具有两个不同均值的时间序列 — 作者提供的图片
如果你了解贝叶斯统计,你知道任何模型的构建基本上由 3 个分布组成。先验分布h(θ) 反映了我们对问题的先验知识。似然函数f(x|θ) 反映了获得的数据,并且必须纳入到先验分布中。这将导致一个后验分布*h(θ|x),这是我们感兴趣的。这就是我们如何使用贝叶斯定理。
模糊聚类
目前,我们面临的第一个(也是最重要的?)问题是从我们构建的时间序列中获得一个先验分布——这是模型的第一部分。问题是:我们没有! 如果你处理的是时间序列,一旦我们得到一个先验分布,大多数任务就已经完成了。
D’Angelo et al.(2011)采取了一种有趣的方法来解决这个问题。他使用 Kohonen 网络对时间序列进行聚类。与硬聚类不同,Kohonen 网络是一种模糊聚类算法,这意味着任何给定点 X 与组 A 的关联概率为p。这种关联由函数*fA(X)给出,该函数将每个点在 A 中的实数与区间[0, 1]*中的数值关联起来,表示 X 在 A 中的隶属度。
对 Kohonen 网络的完整和更好解释,你可以参考 Kohonen(1990)和 Haykin(2007)。使用 Python,我构建了这样的网络,使用了两个函数:
def Center_Kohonen(y, X=0, K=2, alfa=0.8, C=500):
# This kohonen network implementation finds two centers in a time series
#Params:
#Y = Time Series
#M = Number of input patterns
#N = Dimension of the input pattern (for our case it will be 1)
#K = number of neurons, for the proposed problem (number of centers)
M = y.shape[0]
N = 1
f = 0
#Initializin the neurons' weights
I = y.argsort(axis=0) # Sorted Indexes
Y = np.sort(y) # Sortes Points in the Time Series
c1 = Y[0:7] # Beginning of the series
c2 = Y[M-7:M] # End of the series
#Adjusting the values
while np.std(c2) > 0.1: #As long as the standard deviation is greater than 0.1, replace the highest value with the mean
ma = c2.argmax()
c2[ma] = np.mean(c2);
y[I[ma+60-7]] = np.mean(c2);
while np.std(c1) > 0.1: #As long as the standard deviation is greater than 0.1, replace the lowest value with the mean
mi = c1.argmin()
c1[mi] = np.mean(c1)
y[I[mi]] = np.mean(c1);
#Definition of weight values
W = [np.mean(c1), np.mean(c2)]
#Finding centers from Kohonen's network training
for l in range(1, C+1):
alfa=alfa*(1-(C-(C-l))/C)
for i in range(0, M): #For each value in the time series
a=999
for j in range(0, K): #Where K is the number of cluster
if np.linalg.norm([(y[i]-W[j])], 2) < a:
a = np.linalg.norm([(y[i]-W[j])], 2)
f = j
W[f] = W[f]+alfa*(y[i]-W[f])
return c1, c2, I, Y, W, a, alfa
def Fuzzy_Set(y, W):
# This program finds membership values for a time series from previously specified centers.
# Where y is the time series and c a vector with the found centers
center_1 = []
center_2 = []
n = y.shape[0]
l = 2
# Finding the membership association for each point in the time series
for i in range(0, l):
for t in range(0, n):
sum=0;
for k in range(0, l):
sum = sum+(y[t]-W[k])*(y[t]-W[k])
if i == 0:
center_1.append(np.round(1-((y[t]-W[i])*(y[t]-W[i]))/sum, 3))
else:
center_2.append(np.round(1-((y[t]-W[i])*(y[t]-W[i]))/sum, 3))
return center_1, center_2
如果你顺序调用这两个函数,可能会得到这样的结果图:
c1, c2, I, Y, W, a, alfa = Center_Kohonen(y, X=0, K=2, alfa=0.8, C=500)
center_1, center_2 = Fuzzy_Set(y, W)
plt.figure(figsize=(16, 10))
plt.plot(center_1, 'b') # plotting t, a separately
plt.plot(center_2, 'r') # plotting t, b separately
plt.show()
使用 Kohonen 网络对时间序列 y(t)进行的模糊聚类 — 图片由作者提供
这非常有趣!通过 Kohonen 网络,我们能够对时间序列y(t)进行分割。这个图表显示我们有两个簇,因为我们设置了K=2. 在xlabel中,我们有时间序列中的每个点,而ylabel显示某一点与两个簇中的一个相关联的概率。正如你所见,蓝线告诉我们,在到达第 30 个点之前,所有点更可能(大约~99%)属于第一个组或集合μ1(t)。红线则显示了相反的情况,因为它表示与第二组,即集合*μ2(t)*的关联。这是合理的,因为我们构建了一个具有两个不同平均值的时间序列,从图示上看,这个图与第一个图相关。
尽管很有趣,我们直到现在还没有真正找到变化点(我们有一些线索),而且这里没有贝叶斯内容。
顺便提一下,大多数情况下,时间序列的点之间的区分并不会那么简单。例如,如果我们构建了时间序列y(t),其中y(t1)的均值为μ=1加上一些噪声,而y(t2)的均值为μ=1.3(而不是 2)加上一些噪声,这样的分割会好吗?我让你试试这个练习…
Metropolis-Hastings 算法登场了
如果你尝试了上述练习,你会发现仅仅使用 Kohonen 网络来找到替代时间序列中的任何变点指示时会遇到麻烦。这是因为 Kohonen 网络不提供变点,而是两组连续变量,表示每个点与给定簇的关联。
但要记住,集合μ1(t)和μ2(t)的值在区间[0,1]内。这意味着μ1(t)和μ2(t)近似于具有不同参数的贝塔分布(你听说过 Kullback–Leibler 吗?)。根据 D’Angelo et al. (2011)的说法,假设变点由m表示,则对于t≤m,我们将有Beta(a,b)分布,对于t>m,我们将有Beta(c,d)分布。考虑到 Beta 分布的性质,如果时间序列中存在变点,参数 a在Beta(a,b)中将大于参数 b,参数 c在Beta(c,d)中将小于参数 d。
问题是: 你如何构建这两个贝塔分布?Metropolis-Hastings 算法是一种马尔可夫链蒙特卡洛方法,最初由 Metropolis et al. (1953)提出,后来由 Hastings (1970)推广。根据 Gelman et al. (2003)的说法,任何马尔可夫链模拟的目标是“创建一个稳态分布由p(θ | x)指定的马尔可夫过程”。充分运行模拟使我们能够获得足够接近稳态和后验分布的分布。后验分布可以用参数θ的特定函数的期望来概括,即∫g(θ)p(θ | x)dθ = E [g(θ) | x]。这样的积分并不轻松,这就是为什么 MCMC 方法用于近似后验分布的好处所在。
Metropolis-Hastings 算法使用拒绝的概念,这意味着它从辅助分布中生成一个值,并以一定的概率接受它。如果你对 MCMC 方法不熟悉,你可能会质疑算法如何拒绝一个抽取的值。我们使用 Hastings (1970)给出的转移规则:
将其简单说来,我们可以利用由模糊聚类给出的两组连续变量来拒绝从给定先验分布中随机抽取的值,用于变点检测。如果你想了解更多关于 MCMC 方法的信息,我建议参考 Gamerman 和 Lopes (2018)。
让我们回到 Jupyter Notebook。下面的函数是针对这个问题的 Metropolis-Hastings 算法的实现。尽管功能强大,但该算法需要一些条件。首先是为每个需要找到的参数设置先验分布。对于参数 m,我们使用了 1 到 60 之间的均匀分布,这意味着算法在时间序列中随机选择变化点候选值。对于参数 a, b, c 和 d,我选择了信息量较弱的伽马分布。该函数还需要参数,这些参数是随机变量的集合 (μ1(t) 或 μ2(t)) 和模拟次数。
def Metropolis_Hastings(center_kohonen, n_sims=1000):
n = len(y)
m = 1 + round((n-1) * np.random.uniform(0, 1))
shape, scale, loc = 10, 0.1, 0
#Lists to save the date for each parameter
a_params = []
b_params = []
c_params = []
d_params = []
m_params = []
#Prior Distributions for the Parameters
a = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
b = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
c = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
d = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
for i in range(0, n_sims):
m1 = 1+round((n-1) * np.random.uniform(0, 1));
a1 = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
b1 = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
c1 = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
d1 = stats.erlang.rvs(shape, loc=loc, scale=scale, size=1, random_state=None)[0]
#PARAM A
aux1 = 1
for j in range(0, m):
try:
aux1 = aux1 * (center_kohonen[j] ** (a1-1))
except:
aux1 = aux1
aux2 = 1
for j in range(0, m):
try:
aux2 = aux2 * center_kohonen[j] ** (a-1)
except:
aux2 = aux2
try:
ra = ((math.gamma(a1+b)/math.gamma(a1))**m)*aux1*((((a/a1)**.9)*math.exp(-.1*(a1-a)))**2)/(((math.gamma(a+b)/math.gamma(a))**m)*aux2)
if (min(1, ra) > np.random.uniform(0, 1)):
a=a1
except:
pass
#PARAM B
aux1 = 1
for j in range(0, m):
try:
aux1 = aux1*(1-center_kohonen[j])**(b1-1)
except:
aux1 = aux1
aux2 = 1
for j in range(0, m):
try:
aux2 = aux2*(1-center_kohonen[j])**(b-1)
except:
aux2 = aux2
try:
rb = ((math.gamma(a+b1)/math.gamma(b1))**m)*aux1*((((b/b1)**.9)*math.exp(-.1*(b1-b)))**2)/(((math.gamma(a+b)/math.gamma(b))**m)*aux2)
if (min(1, rb) > np.random.uniform(0, 1)):
b = b1
except:
pass
#PARAM C
aux1 = 1
for j in range(m, n):
try:
aux1=aux1*center_kohonen[j]**(c1-1)
except:
aux1 = aux1
aux2 = 1
for j in range(m, n):
try:
aux2=aux2*center_kohonen[j]**(c-1)
except:
aux2 = aux2
try:
rc = ((math.gamma(c1+d)/math.gamma(c1))**(n-m))*aux1*((((c/c1)**.9)*math.exp(-.1*(c1-c)))**2)/(((math.gamma(c+d)/math.gamma(c))**(n-m))*aux2)
if (min(1, rc) > np.random.uniform(0, 1)):
c = c1
except:
pass
#PARAM D
aux1 = 1
for j in range(m, n):
try:
aux1=aux1*(1-center_kohonen[j])**(d1-1)
except:
aux1 = aux1
aux2 = 1
for j in range(m, n):
try:
aux2=aux2*(1-center_kohonen[j])**(d-1)
except:
aux2 = aux2
try:
rd = ((math.gamma(c+d1)/math.gamma(d1))**(n-m))*aux1*((((d/d1)**.9)*math.exp(-.1*(d1-d)))**2)/(((math.gamma(c+d)/math.gamma(d))**(n-m))*aux2)
if (min(1, rd) > np.random.uniform(0, 1)):
d = d1
except:
pass
#PARAM M
aux1 = 1
for j in range(0, m1):
try:
aux1 = aux1*(center_kohonen[j]**(a-1))*((1-center_kohonen[j])**(b-1))
except:
aux1 = aux1
aux2 = 1;
for j in range(m1, n):
try:
aux2 = aux2*(center_kohonen[j]**(c-1))*((1-center_kohonen[j])**(d-1))
except:
aux2 = aux2
aux3 = 1
for j in range(0, m):
try:
aux3 = aux3*(center_kohonen[j]**(a-1))*((1-center_kohonen[j])**(b-1))
except:
aux3 = aux3
aux4 = 1
for j in range(m, n):
try:
aux4 = aux4*(center_kohonen[j]**(c-1))*((1-center_kohonen[j])**(d-1))
except:
aux4 = aux4
try:
rm = (((math.gamma(a+b)/(math.gamma(a)*math.gamma(b)))**m1)*((math.gamma(c+d)/(math.gamma(c)*math.gamma(d)))**(n-m1))*aux1*aux2)/(((math.gamma(a+b)/(math.gamma(a)*math.gamma(b)))**m)*((math.gamma(c+d)/(math.gamma(c)*math.gamma(d)))**(n-m))*aux3*aux4)
if (min(1, rm) > np.random.uniform(0, 1)):
m = m1
except:
pass
a_params.append(a)
b_params.append(b)
c_params.append(c)
d_params.append(d)
m_params.append(m)
return a_params, b_params, c_params, d_params, m_params
用两个所需参数调用那个函数:在这里,我传递了由函数 Fuzzy_Set 给出的 center_1 和 n_sims=1000
a_params, b_params, c_params, d_params, m_params = Metropolis_Hastings(center_1, n_sims=1000)
fig_dims = (16, 10)
fig, ax = plt.subplots(figsize=fig_dims)
plt.plot(m_params, 'r')
ax.set(xlabel='# Simulations', ylabel='Change Point Candidates (m)')
Metropolis-Hastings 算法模拟 — 图片由作者提供
你现在终于找到了变化点。这张图很有趣,因为它展示了绘图过程。第一次由均匀分布给出的绘制值是 m=55。算法拒绝了它,然后尝试其他值,直到得到令人满意且稳定的结果。经过大约 150 次额外运行后,m=30 的值再也不能被算法拒绝。
由于函数返回了每个参数的采样值,我们也可以绘制它们的值。从参数 m 开始,这是所有变化点的绘制结果。要查看密度图,你可以丢弃前 200 次模拟作为“烧入”:
fig_dims = (16, 10)
fig, ax = plt.subplots(figsize=fig_dims)
ax.set(xlabel='Change Point Candidates', ylabel='Density')
sns.kdeplot(m_params[200:])
变化点候选密度图 — 图片由作者提供
我们还可以使用四个其他参数的均值来创建 Beta 分布,即参数 a, b, c 和 d。正如我们之前讨论的,这些参数对于 Metropolis-Hastings 算法至关重要,因为当拒绝规则必须断言 t≤m 时,我们将有 Beta(a,b) 分布,而 t>m 时将有 Beta(c,d) 分布。
让我们使用变量 a_params, b_params, c_params 和 d_params 来构建这种表示,这些变量包含了 a, b, c 和 d 的采样值
fig, ax = plt.subplots(1, 1, figsize=(16, 8))
ax.set_ylabel('Density')
beta_1 = np.random.beta(np.mean(a_params[200:]), np.mean(b_params[200:]), size=1000)
beta_2 = np.random.beta(np.mean(c_params[200:]), np.mean(d_params[200:]), size=1000)
sns.kdeplot(beta_1, color='b', fill=True, common_norm=False, alpha=.5, linewidth=0)
sns.kdeplot(beta_2, color='r', fill=True, common_norm=False, alpha=.5, linewidth=0)
用参数 a 和 b 的均值构建的第一个 Beta 分布是红色的,第二个是用参数 c 和 d 的均值构建的,呈蓝色。在中间,两个分布的密度较低,我们找到了变化点。毫无疑问,使用这种方法的一个巨大优势是可以得到这样的分布,因为我们可以用它们进行贝叶斯推断,丰富预测模型,甚至使用其他类型的 Monte Carlo 模拟。
两个 Beta 分布的表示 — 图片由作者提供
结论
寻找时间序列中的变化点可以防止系统陷入严重故障。试想一下,必须控制温度的机器。任何突然的变化必须尽快被识别,以便工程师进行检查。或者各种生产设施中的能源消耗。任何过度的消耗都必须被分析,因为它可能表示生产中存在某种偏差或能源泄漏,从而显著影响生产成本。
也就是说,D’Angelo(2011)开发的方法并在这里用 Python 实现,证明在检测给定时间序列中的变化点方面非常有价值。此外,如前所述,这种方法的另一个优点正是我们获得了两个 beta 分布作为输出,这可能非常有用。
参考文献
AMINIKHANGHAHI, Samaneh 和 COOK, J. Diane. 时间序列变化点检测方法综述。知识与信息系统,51,2017 年。
D’ANGELO, Marcos Flávio 等 时间序列变化点检测问题的模糊/贝叶斯方法。运筹学研究,31(2),2011 年。
EHLERS, Ricardo S. 贝叶斯推断。第 5 版。巴拉那联邦大学统计系,2007 年。
FAMA, Eugene. 股票市场价格的随机游走。金融分析师,21,1965 年。
_____________ 有效资本市场: 理论与实证工作的回顾。《金融杂志》,25,1970 年。
GAMERMAN, Dani. LOPES, Hedibert Freitas. 马尔科夫链蒙特卡罗: 贝叶斯推断的随机模拟。第 2 版。佛罗里达州:Chapman & Hall/CRC,2006 年。315 页。
GELMAN, Andrew 等 贝叶斯数据分析。第 2 版。佛罗里达州:Chapman & Hall/CRC,2003 年。668 页。
HASTINGS, W. K. 使用马尔科夫链的蒙特卡罗抽样方法及其应用。生物统计学,57,1970 年。
HAYKIN, Simon. 神经网络:原理与实践。第 2 版。阿雷格里港:Bookman,2007 年。900 页。
IWATA, Takuma 等 使用 10GbE FPGA NIC 加速在线变化点检测算法。在第 24 届国际并行与分布式计算会议上提出。都灵:2018 年。
KOHONEN, Teuvo. 自组织映射。纽约:Springer,1990 年,501 页。
METROPOLIS, Nicholas 等 通过快速计算机计算状态方程。化学物理学杂志,21,1953 年。
OH KJ, 等 开发基于时间的聚类神经网络用于变化点检测:应用于金融时间序列。亚太运营研究杂志,22(1),2005 年。
PAULINO, Carlos Daniel 等 贝叶斯统计。第 2 版。里斯本:卡洛斯·古尔本基安基金会,2018 年,601 页。
VAN DEN BURG, Gerrit J. J., WILLIAMS, Christopher K. I. 变化点检测算法评估。stat.ML,arXiv:2003.06222,2020 年。
在 DAX 测量中随着时间改变你的关注点
原文:
towardsdatascience.com/change-your-focus-over-time-in-dax-measures-292ff012643a
如何确定当你随着时间推移广告产品时投资是否有所回报
·发表于 Towards Data Science ·7 分钟阅读·2023 年 5 月 19 日
–
图片由 David Travis 提供,来源于 Unsplash
介绍
如何衡量广告活动的成功?
尤其是当你想要随着时间推移广告不同品牌时?
一个类似的问题曾由我的客户提问。
他希望分析其品牌的销售情况,并将其与广告品牌的销售情况进行比较,以确定投资是否有所回报。
挑战在于修改数据模型,使得在不破坏现有报告和分析的情况下能够进行此分析。
专注于选择的品牌
第一步是拥有一个随时间变化的广告品牌表。
如下所示:
图 1 — 每月的重点品牌表(作者提供的图)
在此表中,几乎每个月都会找到一个或多个品牌。
现在我可以扩展我的数据模型。
我在 Contoso 数据模型中的起点如下(从整个数据模型中摘录):
图 2 — 初始数据模型(作者提供的图)
如你所见,我有一个品牌名称列,但没有品牌 ID。
在这种情况下,我必须通过 [BrandName] 列创建一个关系。
集成 Focus Brands 表
将 Focus Brands 表添加到我的数据模型后,我添加了以下关系:
图 3 — 新数据模型及新关系(作者提供的图)
我设置了过滤器“聚焦品牌”过滤“产品”来代替“聚焦品牌”和“产品”表之间的双向过滤。但双向过滤也有效,只是引入了一个不必要的过滤方向。我们需要设置正确的过滤方向,以便我们能够根据“产品”表中的属性深入挖掘结果。
由于“产品”表中有多个相同名称的产品,我们必须与“产品”表建立多对多(m:n)关系。
在这种情况下创建数据模型的另一种方法是添加一个包含每个品牌一行的“品牌”表,并从这两个表到这个新表创建 1:n 关系。
为了简化起见,我在这里没有进行额外的步骤,而是坚持使用 m:n 关系。正如下面“参考文献”部分的 SQLBI 文章中描述的,还有更好的解决方案。
同样的情况适用于“聚焦品牌”表和“日期”表之间基于“MonthKey”列的关系。
但为了避免数据模型中的歧义,两个关系都必须被禁用。
关键关系是“聚焦品牌”和“在线销售”表之间的关系。
我的第一个方法是没有与“在线销售”表的关系。但我不得不在表之间使用交叉过滤来正确计算结果。
这种方法带来了一些问题:
-
无法计算广告产品和非广告产品的销售部分。
-
无法正确计算时间序列。
-
最重要的是,报告对所有用户不起作用。
最后一点至关重要。我在我的度量中使用了CROSSFILTER()函数。
正如你在微软文档的备注中可以读到的,当数据模型中实施了行级安全时,CROSSFILTER()是不支持的,我的客户就有这种情况。
为了实现“聚焦品牌”和“在线销售”表之间的关系,我不得不在每个表中添加一个新列,以将每个品牌映射到每个月。
在“聚焦品牌”表中,我用以下表达式添加了这一列:
图 4 — 带有每月品牌列的“聚焦品牌”表(图由作者提供)
在“在线销售”表中,我使用了这个表达式来添加相应的列:
Brand per Month = RELATED('Product'[BrandName])
& "_" & CONVERT(RELATED('Date'[MonthKey]),STRING)
现在,我已经能够添加新的关系。
创建度量并检查结果
计算结果的度量如下:
Online Sales for Focus Brands =
CALCULATE([Sum Online Sales]
,USERELATIONSHIP('Online Sales'[Brand per Month]
,'Focus Brands'[Brand per Month]
)
,USERELATIONSHIP('Focus Brands'[MonthKey]
,'Date'[MonthKey]
)
)
添加了带有[Sum Online Sales]和新[Online Sales for Focus Brands]度量的视觉效果后,2019 年 3 月的结果如下所示:
图 5 — 检查“聚焦品牌”度量的结果(图由作者提供)
如你所见,2019 年 3 月的每个“聚焦品牌”中两个度量的结果是相同的(用蓝色标记)。
新的度量正在为“聚焦品牌”计算正确的结果。
但现在,我们必须使用来自重点品牌列的品牌名称列来获得这些结果。
但最大的问题是,我得到了所有销售额的空白行,而没有对应的重点品牌。
当仅在列视觉中使用新度量时,这一点更为明显:
图 6 — 带空白的每月重点销售(作者绘制)
我可以向视觉中添加过滤器,以排除所有[BrandName] = Blank 的行,但我希望避免这样做,因为数据模型的所有用户都需要这样做,而不是通过良好的数据模型一次性解决这个问题。
目标是仅在报告中一次性提供品牌名称列,而不干扰使用产品表的所有现有视觉效果或报告。
改进数据模型
为了实现这一点,我必须确保在计算重点品牌的销售时,过滤器上下文能够正确流动。
请查看下面的图片以了解所需的流向:
图 7 — 所需的过滤器流向(作者绘制)
在这种情况下,我必须在重点品牌表和产品表之间设置双向过滤。
然后,我必须更改我的度量以强制过滤器上下文从产品表通过重点品牌表流动。
为此,我调整了度量以包含 CROSSFILTER():
Online Sales for Focus Brands =
CALCULATE([Sum Online Sales]
,USERELATIONSHIP('Online Sales'[Brand per Month]
,'Focus Brands'[Brand per Month]
)
,USERELATIONSHIP('Focus Brands'[MonthKey]
,'Date'[MonthKey]
)
,CROSSFILTER('Online Sales'[ProductKey]
,'Product'[ProductKey]
,None
)
)
这样,我们面临的问题是这个度量对应用 RLS 规则的所有用户都不起作用。
没有这种限制,这个度量在使用产品表中的品牌名称列时将有效。
我尝试了其他解决方法,但无论我做什么,要么不能按需工作,要么会干扰现有报告。
我甚至添加了一个品牌表,并故意将品牌表和重点品牌表之间的关系设置为多对多。但这仍然没有解决对 CROSSFILTER()函数的需求:
图 8 — 带品牌表的数据模型(作者绘制)
我将重点品牌和品牌表之间的关系设置为多对多,因为该关系变为限制关系,从而避免在结果中创建行。
但它仍然仅与度量中的 CROSSFILTER()函数一起工作。
而下钻仍然不起作用。
目前我没有解决此问题的方案。
结论
起初,我认为这个要求相对容易解决。
结果是一个完美的示例,说明了良好的数据模型如何解决问题,以及如何操作关系以实现目标。
即便如此,我仍然无法消除对额外过滤器的需求。
有时我们必须接受需求冲突并寻找解决办法以实现目标。
根据上面展示的解决方案,我现在可以创建度量来计算广告活动的成功或重点品牌的销售如何与所有其他品牌相关。
参考资料
阅读 SQLBI 关于处理 m:n 关系时可能的解决方案的这篇文章:
在 Power BI 和 Tabular 中建模多对多关系的不同选项 — SQLBI
我使用了 Contoso 示例数据集,就像在我之前的文章中一样。您可以从微软这里免费下载 ContosoRetailDW 数据集。
表格 Focus Brands 是通过这种数据集的半随机过程生成的。
Contoso 数据可以在 MIT 许可证下自由使用,如这里所述。
我扩大了数据集,以使 DAX 引擎更加努力地工作。
在线销售表包含 7100 万行(而不是 1260 万行),零售销售表包含 1850 万行(而不是 340 万行)。
[## 使用我的推荐链接加入 Medium - Salvatore Cagliari
阅读 Salvatore Cagliari 的每一个故事(以及 Medium 上其他成千上万的作者)。您的会员费直接…
medium.com](https://medium.com/@salvatorecagliari/membership?source=post_page-----292ff012643a--------------------------------)
在 Power BI 中改变数据视角
原文:
towardsdatascience.com/changing-perspective-on-your-data-in-power-bi-4cca965f5fe7
通常,我们在报告页面上需要比实际拥有的空间更多。但如果我们能在同一页面上切换数据视角呢?让我们看看怎么做。
·发布于 Towards Data Science ·阅读时间 7 分钟 ·2023 年 7 月 24 日
–
由 Nathan Dumlao 在 Unsplash 提供的照片
介绍
想象一个包含一些卡片、列和折线图的报告页面。
在页面顶部,你会看到四个按钮:
-
实际数据
-
YTD(年初至今)
-
YE(年末)
-
最近三个月
类似这样的:
图 1 — 实际数据的模型图(作者提供的图)
当你点击“YTD”按钮时,你的数据将会更改为显示 YTD 结果,从而改变我们结果的视角:
图 2 — YTD 结果的模型图(作者提供的图)
这就是我们想要实现的目标。
最后,我们想根据选择来更改结果的格式。
重要的是要理解,我们需要一个日期或年月筛选器来进行我们的报告。我们想要更改结构数据的结果,比如:
-
地理
-
门店
-
产品类别
-
客户组
-
等等。
通常,选择日期周期(如年份或月份)的筛选器,然后以时间序列显示年份或月份的数据并没有意义。我们可能只能看到数据的一个实例。
好的,你可以选择一年以按月份查看结果。但这与预期的场景不同。
准备数据模型
第一步是添加一个场景表。
这个表格包含每个需要的场景的一行。
我在 Power BI 中使用“输入数据”功能创建了这个表格,如下所示:
图 3 — 场景表(作者提供的图)
该表与其他任何表没有关系。这样,我避免了使用时的任何副作用。
现在,我需要为每个场景创建一个度量值。
我不会详细介绍如何编写每个度量值,因为这会使文章过长。
可以将所有逻辑包含在一个度量值中。但我有几个理由创建单独的度量值:
-
可重用性:这些度量值可以在其他报告中重用。
-
简单性:每个度量值本身都很简单。没有必要将多个度量值合并为一个度量值。
-
可测试性:独立测试每个度量值要容易得多。
下一步是创建一个度量值,该度量值根据选定的场景返回正确的结果。
添加动态度量值
现在,我可以添加度量值,它可以根据切片器中选择的项目动态使用正确的度量值。
这个度量值很简单:
Online Sale (By scenario) =
VAR SelectedScenario = SELECTEDVALUE('Reporting Scenarios'[Scenario])
RETURN
SWITCH(SelectedScenario
,"Actuals", [Sum Online Sales]
,"YTD", [Online Sales (YTD)]
,"YE", [Online Sales (YE)]
,"Last three Months", [Online Sales (Last 3 Months)]
)
我在报告页面上添加了一个切片器,将其样式设置为 Tile,并启用单选,以确保始终选择一个值,并且永远不会选择多个值。
当我将单独的度量值和动态度量值添加到矩阵视觉对象中并选择 YTD 时,我得到的是:
图 4 — 使用动态度量值的结果(图由作者提供)
我检查了日期层级的结果以进行测试,以查看所有计算是否正确。
使用计算组
为了使内容更通用,我添加了两个计算组:
第一个包含我在场景中需要使用的所有时间智能函数。
无论你是否打算使用这种方法,我都建议使用计算组来处理时间智能逻辑。这样,我们可以只编程一次你的逻辑,并在所有度量值中重用它。
如果你需要学习如何使用计算组,请跳到下面的参考部分,找到 SQLBI 的介绍文章链接。
第二个计算组只有一个计算项:
VAR SelectedScenario = SELECTEDVALUE('Reporting Scenarios'[Scenario])
RETURN
SWITCH(SelectedScenario
,"Actuals", SELECTEDMEASURE()
,"YTD", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YTD")
,"YE", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YE")
,"Last three Months", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "Last three Months")
,SELECTEDMEASURE()
)
最后一行确保返回结果,即使没有选择场景或选择了多个场景。
在 Tabular Editor 中,它的显示效果如下:
图 5 — 按场景划分的计算组(图由作者提供)
最后,我将我的在线销售(按场景)度量值更改为以下内容,以使用新的计算组:
Online Sale (By scenario) =
CALCULATE([Sum Online Sales]
,'By Scenario'[Scenario] = "By Scenario"
)
当我将两个矩阵视觉对象并排放置,一个使用时间智能计算,另一个使用动态度量值时,结果如预期:
图 6 — 使用计算组的结果(图由作者提供)
所以,第一步已经完成。让我们看看如何处理结果的格式化。
那么动态格式化呢?
想象一下,我们想选择是否查看实际结果、相对于去年绝对数值的差异,还是百分比的差异:
图 7 — 差异类型的选择(图由作者提供)
对于这个案例,我扩展了报告场景表,新增了一个类型列和几个新行:
图 8 — 带有类型列的场景表(作者绘制)
现在,我可以添加进一步的切片器,并通过类型列限制每个切片器的可用选项,仅显示实际需求所需的选项,借助过滤面板:
图 9 — 使用新类型列过滤切片器(作者绘制)
接下来,我在我的时间智能计算组中添加了两个计算项:
-
YoY:按绝对数字计算的年同比差异
-
YoY %:按百分比计算的年同比差异
计算项默认从源度量获取数字格式。
由于与计算项一起使用的度量具有数字格式,因此它将返回一个数字结果,而不是百分比。
但我为百分比结果的计算项添加了格式字符串,如下所示,以解决这个问题:
“0.00%;-0.00%;0.00%”
这是我对“YoY %”计算项所做的:
图 10 — 带有格式字符串的 YoY % 计算项(作者绘制)
我为动态场景的计算项添加了两个额外的案例:
VAR SelectedScenario = SELECTEDVALUE('Reporting Scenarios'[Scenario])
RETURN
SWITCH(SelectedScenario
,"Actuals", SELECTEDMEASURE()
,"YTD", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YTD")
,"YE", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YE")
,"Last three Months", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "Last three Months")
,"Absolute YoY", CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YoY")
,"Relative YoY", FORMAT(CALCULATE(SELECTEDMEASURE(), 'Time Intelligence'[Time Functions] = "YoY %"), "0.00%;-0.00%;0.00%")
,SELECTEDMEASURE()
)
不幸的是,计算项的格式字符串未应用于场景的计算项。因此,我们必须使用FORMAT()函数明确设置格式为百分比。
(并排视图与明确的度量)结果如下:
图 11 — 格式正确的结果(作者绘制)
当我添加一个用于周期的切片器并将矩阵更改为按产品层级报告时,结果接近最终版本:
图 12 — 带有周期切片器和产品层级的结果(作者绘制)
现在,我可以添加更多视觉效果与其他动态度量来提高报告的信息密度,而无需添加大量视觉效果。
结论
在这一部分,我结合了几种技术来实现新的功能:
-
无关系的表格
-
时间智能的计算组
-
一个用于场景的计算组,使用来自另一个计算组的计算项
-
在计算项中格式化输出
这种特性的组合对找到挑战的最佳解决方案至关重要。
当我调查解决此问题的可能方法时,我对如何进行有了清晰的想法。
尽管如此,我还是在网上搜索了其他方法,并找到了另一种使用计算表处理每个场景的所有日期的方法。
如该示例视频所解释:
但我的需求需要一种更灵活的方法。计算表中使用的每个场景只有基于实际日期的日期范围。这一日期将是最后一次刷新日期。
只有在刷新数据集后,你才会得到正确的结果。不刷新数据集,你将得到错误的结果。
但我需要能够动态定义报告的日期范围,然后设置所需的计算方法,比如 YTD 或前一年。
当我选择一个可能的解决方案时,我会考虑以下几个关键因素:
-
所选的方法是否满足所有要求?
-
它是否引入了任何限制?
-
它是否引入了不必要的复杂性?
-
是否足够通用以便重用?
我希望这些建议能帮助你应对未来的挑战。
参考文献
SQLBI 关于计算组的介绍:www.sqlbi.com/articles/introducing-calculation-groups/
我使用了 Contoso 示例数据集,就像我之前的文章中一样。你可以从微软这里免费下载 ContosoRetailDW 数据集。
Contoso 数据可以根据这里的 MIT 许可协议自由使用。
[## 获取 Salvatore Cagliari 发布内容的邮件通知。
获取 Salvatore Cagliari 发布内容的邮件通知。通过注册,如果你还没有 Medium 账户,将会创建一个…
medium.com](https://medium.com/@salvatorecagliari/subscribe?source=post_page-----4cca965f5fe7--------------------------------)
自然语言处理中的字符编码:ASCII 和 Unicode 的角色
更详细地审视技术细节和实际应用
·
关注 发布于 Towards Data Science ·7 min read·2023 年 1 月 12 日
–
介绍
在本文中,我们将探讨字符编码标准的主题,特别是 ASCII 和 Unicode 系统。我们将深入了解它们的工作原理及其在深度学习中的作用。此外,我们还将提供一些使用 Tensorflow 进行字符编码的示例,以便概览该库如何处理字符串。
首先,我们将介绍一些重要的概念。
什么是字符编码标准?
字符编码是一种将字符表示为数值(即编码点)的系统。这些编码点允许计算机存储和处理文本,然后可以以其他方式显示或使用。在本文中,我们将解释 ASCII 和 Unicode 字符编码系统,并讨论它们在自然语言处理(NLP)领域的实用性。
ASCII
ASCII(美国信息交换标准代码)是一种字符编码标准,为书面文本中的每个字母、数字和其他符号分配唯一的数字。它被广泛使用,但也存在一些限制。
ASCII 具有 128 个编码点,这意味着它可以表示 128 个字符和符号。其中一些编码点代表计算机的指令,而另一些代表可打印的字符,如字母和数字。
ASCII 中使用的映射系统可以在此表格中找到:
ASCII 表格, 链接
如我们所见,在 128 个编码点中,只有 94 个是可打印的。
例如,使用此表格的十六进制列,我们可以将字符串“Language”编码为“4C 61 6E 67 75 61 67 65”。
ASCII 的限制
正如我们之前所说,ASCII 码的主要限制是它只有 94 个可打印字符。这些字符包括大小写英文字母(52 个字符)、数字(10 个字符)以及标点符号和符号(32 个字符)。因此,ASCII 不适用于使用超过基本拉丁字母的语言。其他语言中有不同的字符(如中文、俄文、挪威文),甚至有法语和西班牙语中的带重音字母,这些都无法使用这种字符编码系统显示。此外,像表情符号或货币符号这样的特殊符号也不包含在 ASCII 中,这限制了它的潜力。因此,需要一种新的字符编码系统,以使其更具扩展性,并考虑到所有这些在 ASCII 码中被忽略的字符和符号。这就是 Unicode 标准的出现。
Unicode
Unicode 是一种字符编码标准,开发于 1980 年代末至 1990 年代初,旨在扩展 ASCII 及其他现有标准的功能。其主要开发动机之一是需要一个可以表示任何语言文本的单一字符编码标准。为了解决这个问题,Unicode 联盟应运而生,创建了一个能够表示世界所有语言的单一通用字符编码标准。Unicode 使用 16 位编码方案,这使其能够表示超过 65,000 种不同的字符。这比 ASCII 可以表示的 128 个字符要多得多。它已经成为 WWW 的主流字符编码标准,并被现代计算系统和软件广泛支持。它可以编码和显示多种语言的文本,包括使用拉丁字母以外的字符集的语言(如中文、日文、阿拉伯文),以及像表情符号和货币符号等特殊符号。
你可以在他们的网站上找到更多信息。
编辑描述
home.unicode.org](https://home.unicode.org/?source=post_page-----9349b4fe3cee--------------------------------)
它是如何工作的?
Unicode 定义了一个代码空间,一组从 0 到 10FFFF(十六进制)的数值,称为代码点,并以 U 开头表示,因此范围从 U+0000 到 U+10FFFF。我们将使用 U 后跟字符的十六进制代码点值,并在必要时使用前导零(例如,U+00F7)。Unicode 代码空间分为十七个平面,编号从 0 到 16。每个平面由 65,536(2¹⁶)个连续的代码点组成。平面 0,称为基本多语言平面(BMP),包含了最常用的字符。其余的平面(1 到 16)被称为补充平面。在每个平面中,字符被分配在命名的相关字符块中。Unicode 块是多个连续的数字字符代码范围之一。它们用于组织 Unicode 标准中的大量字符。每个块通常但不总是用来提供一种或多种特定语言使用的字形,或者在某些通用应用领域中使用。
映射和编码
Unicode 定义了两种映射方法:UTF 编码和 UCS 编码。编码将 Unicode 代码点范围映射到固定范围内的一系列值。所有 UTF 编码将代码点映射到唯一的字节序列。编码名称中的数字表示每个代码单元的位数。UTF-8 和 UTF-16 是最常用的编码。
-
UTF-8 对每个代码点使用一到四个字节。它与 ASCII 非常兼容。
-
UTF-16 对每个代码点使用一个或两个 16 位代码单元。
Unicode 在自然语言处理中的应用
在本节中,我们将看到如何在 NLP 任务中使用 Unicode 以及它的作用。我们将使用一些 Tensorflow 代码使这些示例更加生动。
NLP 模型通常处理具有不同字符集的不同语言。最具代表性的任务可能是神经机器翻译(NMT),在这种任务中,模型必须将句子翻译成其他语言。但一般来说,所有语言模型都必须使用字符串序列作为输入,因此 Unicode 是一个相当重要的步骤。使用 Unicode 表示通常是最有效的选择。
在这里我们将看到如何在 Tensorflow 中表示字符串并使用 Unicode 对其进行操作。基本的 TensorFlow tf.string 类型允许我们构建字节字符串的张量。Unicode 字符串默认是 UTF-8。
tf.constant(u"Hello world 🌎")
>>> tf.Tensor(b'Hello world \\xf0\\x9f\\x8c\\x8e', shape=(), dtype=string)
在这里我们可以看到,表情符号被编码为“\xf0\x9f\x8c\x8e”。它以 UTF-8 表示。
表示
我们可以在 Tensorflow 中使用两种标准表示 Unicode 字符串:
-
字符串标量——其中代码点序列使用已知字符编码(例如 Unicode)进行编码。
-
int32 向量——其中每个位置包含一个单一的代码点。
例如,以下值都表示 Unicode 字符串“语言处理”(在中文中意为“language processing”)。
# Unicode string, represented as a UTF-8 encoded string scalar
text_utf8 = tf.constant(u"语言处理")
print(text_utf8)
>>> tf.Tensor(b'\\xe8\\xaf\\xad\\xe8\\xa8\\x80\\xe5\\xa4\\x84\\xe7\\x90\\x86', shape=(), dtype=string)
我们也可以使用 UTF-16 进行表示。
# Unicode string, represented as a UTF-16-BE encoded string scalar
text_utf16be = tf.constant(u"语言处理".encode("UTF-16-BE"))
print(text_utf16be)
>>> tf.Tensor(b'\\x8b\\xed\\x8a\\x00Y\\x04t\\x06', shape=(), dtype=string)
最终,在一个 Unicode 代码点向量中。
# Unicode string, represented as a vector of Unicode code points
text_chars = tf.constant([ord(char) for char in u"语言处理"])
print(text_chars)
>>> tf.Tensor: shape=(4,), dtype=int32, numpy=array([35821, 35328, 22788, 29702], dtype=int32)
转换
Tensorflow 提供了在这些不同表示之间转换的操作:
- tf.strings.unicode_decode:将编码的字符串标量转换为代码点向量。
text_chars_converted = tf.strings.unicode_decode(text_utf8, input_encoding='UTF-8')
print(text_chars)
print(text_chars_converted)
>>> tf.Tensor([35821 35328 22788 29702], shape=(4,), dtype=int32)
>>> tf.Tensor([35821 35328 22788 29702], shape=(4,), dtype=int32)
- tf.strings.unicode_encode:将代码点向量转换为编码的字符串标量。
text_utf8_converted = tf.strings.unicode_encode(text_chars, output_encoding='UTF-8')
print(text_utf8)
print(text_utf8_converted)
>>> tf.Tensor(b'\\xe8\\xaf\\xad\\xe8\\xa8\\x80\\xe5\\xa4\\x84\\xe7\\x90\\x86', shape=(), dtype=string)
>>> tf.Tensor(b'\\xe8\\xaf\\xad\\xe8\\xa8\\x80\\xe5\\xa4\\x84\\xe7\\x90\\x86', shape=(), dtype=string)
- tf.strings.unicode_transcode:将编码的字符串标量转换为不同的编码。
text_utf16be_converted = tf.strings.unicode_transcode(text_utf8, input_encoding='UTF-8', output_encoding='UTF-16-BE')
print(text_utf16be)
print(text_utf16be_converted)
>>> tf.Tensor(b'\\x8b\\xed\\x8a\\x00Y\\x04t\\x06', shape=(), dtype=string)
>>> tf.Tensor(b'\\x8b\\xed\\x8a\\x00Y\\x04t\\x06', shape=(), dtype=string)
字符长度
我们可以使用tf.strings.length操作的 unit 参数来指示字符长度的计算方式。默认的单位值是“BYTE”,但可以设置为其他值,例如“UTF8_CHAR”或“UTF16_CHAR”,以确定每个编码字符串中的 Unicode 代码点数量。
# Note that the final character (emoji) takes up 4 bytes in UTF8.
helloWorld = u"Hello World 🌍".encode('UTF-8')
print(helloWorld)
>>> b'Hello World \\xf0\\x9f\\x8c\\x8d'
num_bytes = tf.strings.length(helloWorld).numpy()
num_chars = tf.strings.length(helloWorld, unit='UTF8_CHAR').numpy()
print('{} bytes; {} UTF-8 characters'.format(num_bytes, num_chars))
>>> 16 bytes; 13 UTF-8 characters
如果你计算字符串“Hello World \xf0\x9f\x8c\x8d”的字节数(包括每个字母、空格和字节),你会看到总共有 16 个字节,如输出代码所示。
如果我们像之前一样计算这字符串的字符数,但将表情符号视为一个字符而不是 4 个字节,这个字符串包含 13 个 UTF-8 字符。
如果你想了解更完整的教程,我建议你访问这个 TensorFlow 教程。
## Unicode strings | Text | TensorFlow
NLP 模型通常处理具有不同字符集的不同语言。Unicode 是一个标准编码系统,它…
结论
总之,字符编码是计算机系统和自然语言处理(NLP)中的一个重要方面。ASCII 是一种广泛使用的标准,为文本中的每个字母、数字和符号分配唯一的编号,但它在字符表示上存在局限性。Unicode 标准的开发旨在解决 ASCII 的局限性,它使用 16 位编码方案,使其能够表示超过 65,000 个不同的字符,并支持任何语言的文本。Unicode 已成为全球互联网和现代计算系统中主流的字符编码标准,对于显示和处理各种语言和符号的文本至关重要。在这篇文章中,我们详细概述了 ASCII 和 Unicode 编码系统,以及 Tensorflow 如何管理 Unicode 中的字符串。
如果你有任何疑问或建议,请留下评论。感谢阅读!
探索最终边界:完成 #30DayMapChallenge 之旅
·
关注 发布于 Towards Data Science ·6 分钟阅读·2023 年 11 月 29 日
–
图片由作者提供
随着 #30DayMapChallenge 的结束,我深刻感受到社区和协作的力量。每天都有新的主题,每个主题带来了新的见解,而在这个过程中,呈现出了一幅地理可视化故事的挂毯。这个挑战不仅仅是对技能的考验,它是对共享知识和集体创造力的庆祝。
反思 #30DayMapChallenge:
对我而言,#30DayMapChallenge 不仅仅是每天制作一张地图的承诺;它是对数据讲故事核心的探索。通过这项挑战,我在每张我设计的地图中将迁移的片段故事、复杂的交通网络和城市生活的脉动缝合在一起,我很高兴与大家分享这些。在这个过程中,我学到了很多关于地理可视化的知识。
延续在#30DayChartChallenge中的实践,我利用Observable Plot的简洁性为数据注入生命。在我之前的文章中,我分享了这次挑战前半部分我最喜欢的可视化。在这篇总结文章中,我将揭示一些剩余的地理可视化作品,每一件都融合了数据、设计和发现。你可以在我的#30DayMapChallenge收藏中找到所有的可视化作品及其数据源和代码。
本文中的所有图像均由作者创作。
第 16 天 — 大洋洲
第 16 天 — 大洋洲
利用来自ala.org.au的详细观察记录,我力图通过对澳大利亚独特有袋类动物栖息地的复杂描绘来展示澳大利亚袋鼹鼠的观察情况。
在创建这张地图时,挑战在于以既美观又科学准确的方式呈现空间数据。为了实现这一目标,我将记录到的观察点叠加在澳大利亚的轮廓上,明亮的点表示袋鼹鼠的存在。最终结果是一个信息丰富且引人注目的插图,展示了袋鼹鼠如今稀疏的分布,便于快速视觉评估种群密度和地理分布。
来自wikipedia.org的袋鼹鼠背景图像与澳大利亚地图美妙叠加,使得故事更加吸引人、强大和连贯。
第 17 天 — 流动
第 17 天 — 流动
来自databank.worldbank.org的全面数据集提供了全球迁移的视角,使我能够将跨越大陆和文化的路线串联起来。在这张图像中,我以全球迁移模式的流动性和动态性捕捉了“流动”主题,从美国到 2000 年排名前 10 的国家。它使用弧线来表示人们在地球上的移动,每条曲线都从美国起点,延伸到世界各地的不同国家。
这种可视化不仅反映了从一个国家到另一个国家的物理移动,还 encapsulates 了迁移过程中固有的文化、思想和联系的转移。
第 21 天 — 栅格
第 21 天 — 栅格
对于这个主题,我想创建一个鲜明的西雅图交通碰撞可视化,数据来源于IBM 课程的毕业项目。
我使用了栅格图形方法有效地绘制了城市范围内的每一个事件,这本质上涉及将图像分解成像素或颜色点的网格。每个碰撞事件都表示为一个像素化的点,这强调了数据的颗粒度。这种方法允许表示高水平的细节,并创建一个密度图,可以揭示在其他数据可视化形式中不易察觉的模式。
第 21 天 — 栅格插值选项
在上面的图像系列中,我通过一个迷人的视角探索了“栅格”主题,展示了通过 Observable Plot 提供的各种插值方法,应用于西雅图交通碰撞数据。每个面板代表一种不同的方法——默认、最近邻、重心和随机游走——从单一数据集中创造出不同的视觉效果,每种方法都影响数据的空间分布和视觉纹理。‘默认’保持数据的原始颗粒度,而‘最近邻’引入了更加分段、几乎是立体主义的失真。‘重心’提供了数据点的棱镜状折射,而‘随机游走’则创造了扩散、几乎印象派的效果。这确实让我觉得我创造了意外的艺术。
第 23 天–3D
第 23 天–3D
在这个图像中,我想展示一个光滑而简约的全球钻石生产图像,通过在黑暗的世界地图上用发光的点来象征,数据来自theglobaleconomy.com。
为了创建 3D 效果,我绘制了亮点来标记钻石开采的重要位置,这些亮点在世界地图的黑色背景下熠熠生辉,体现了钻石本身的珍贵。为了增强这些点的发光效果,我在它们下方添加了密度可视化。地球的旋转进一步通过这些钻石生产点的出现和消失来增强 3D 效果。
第 24 天 — 黑白
第 24 天 — 黑白
我想展示 2016 年至 2020 年间华盛顿州迁移趋势的单色解释,数据来自美国人口普查局。这种黑白选择不仅符合美学主题,还突显了人们流入和流出的对比——白色表示净迁入,黑色表示净迁出。
地图上大胆的对比尖峰是该州人口统计变化的图形表示。它们的不同长度和颜色表示迁移的规模和方向,两种颜色的配色方案提供了清晰的视觉差异,增强了理解。通过为这些尖峰和州的边界创建阴影,我想在单色主题的基础上赋予其 3D 效果。
第 30 天——我最喜欢的
第 30 天——我最喜欢的
这张图片是对“我最喜欢的……”主题的生动致敬,展示了瑞士复杂而广泛的铁路网络,这一网络被誉为欧洲最密集的。我喜欢欧洲铁路网络的强大,它无疑是我最喜欢的旅行方式。
在这次可视化中,我另一个最喜欢的地方是类型——栅格。使用栅格图,这张地图确实让瑞士铁路网络的工程和组织奇迹如星空般闪耀。我在#30DayMapChallenge 期间学会了如何制作这个,并深深地爱上了这种图表在表示复杂点系统时的强大能力。
结束制图探险
这些地图不仅仅是每日练习;它们是放大我们世界复杂性和美丽的透镜。挑战的后半部分与前半部分一样引人入胜,每张地图都是数据与设计、故事与空间交汇的更深入探讨。从濒危物种到国际迁移的脉络,从人们的移动到引导他们的轨迹,#30DayMapChallenge 是对我们如何可视化和解释我们所居住空间的深刻探索。
对于那些一直关注的人,你们的好奇心和参与是这项工作的推动力。对于未来可能踏上这条道路的人:愿每个主题挑战你,社区激励你,愿你创建的每一张地图都成为你探索之旅中的一个里程碑。
所有的可视化,包括它们的底层代码和数据,都可以在我的Observable 集合中找到,供那些渴望开始自己制图冒险的人参考。
如果你愿意,可以在Linkedin上找到我。
绘制非参数探索:无分布假设检验的统计框架
评估符号检验和 Wilcoxon 符号秩检验的机制
·
关注 发布于 Towards Data Science ·19 分钟阅读·2023 年 5 月 10 日
–
内容
-
介绍
-
工具 1:单样本符号检验
-
工具 2:双样本符号检验
-
符号检验的局限性
-
工具 3:单样本 Wilcoxon 符号秩检验
-
威尔科克森符号秩检验:可能的并发症
-
工具 4:两样本威尔科克森符号秩检验
-
结论
介绍
统计学是知识工具的集合,允许我们通过包括但不限于参数估计、置信区间构建和假设检验等工具从数据中推断以验证我们的假设。在本文中,我们将学习允许我们检验有关不同数据分位数值的假设的框架,即符号检验和威尔科克森符号秩检验。这些框架的独特之处在于,与 z 检验或 t 检验等流行的假设检验不同,这些检验不需要对数据做任何假设,无论是通过直觉还是通过中央极限定理强加的,即,它们是无分布的或非参数的。您只需拥有来自对称和连续分布的数据,您将配备检验如下主张的工具:
工具 1:单样本符号检验
让我们从一个简单的检验开始,它只涉及计算小于或等于阈值的值,用于假设检验:符号检验(即二项检验)。特别是,我们考虑一个大小为 n 的样本 X₁, …, Xₙ 以及以下陈述的简单零假设和相应的替代假设:
其中 m 表示给定数据的中位数。作为起点,我们来考虑在传统 t 检验设置下我们如何处理这个问题。在这种情况下,我们会假设 n 很大,使得中央极限定理发挥作用。此外,由于分布总是假设为对称的,检验中位数应该与检验均值相同。因此,我们可以定义检验统计量和相应的临界区域如下:
这很简单且相当强大(正如我们稍后将看到的),但它基于一个假设,即分布收敛到一个自由度为 n — 1 的 t 分布。但这可能不一定成立,特别是当 n 不够大时。这需要一个替代框架,让我们可以在不引入数据的分布假设的情况下检验这个假设。这引出了符号检验,它只是涉及统计总数大于 m⁰ 的观察值。例如,考虑以下的 n 个样本数据:
假设如下:
如上所述,我们首先计算大于 m⁰ 的 Xᵢ 的数量。令 N⁺ 表示大于 m⁰ 的 Xᵢ 的随机变量,令 n⁺ 为给定样本的实际值:
现在,我们确定在原假设下上述检验统计量的分布。由于在原假设下 m = m⁰,样本大于 m⁰ 的概率必须是 0.5。因此,N⁺ 衡量的是大于 m⁰ 的样本数,每个样本在原假设下有 0.5 的概率贡献到 N⁺。换句话说,N⁺ 计算的是成功次数,每次成功的概率为 0.5。这定义了一个二项随机变量,参数为样本数 n = 10 和成功概率 p = 0.5。因此,
现在,已知检验统计量在原假设下的分布,我们可以继续计算给定样本的 p 值。请记住,p 值表示在原假设为真的假设下观察到比检验统计量样本值更极端值的概率。因此,
显然,p 值相当大。因此,即使在 10% 的显著性水平下,由于 p 值 > 0.10,我们也未能拒绝原假设!这就结束了简单却有用的符号检验应用。这也引出了另一个重要问题:如果备择假设在另一个方向,或者如果是双侧的情况呢?过程依然相同,只是我们计算比 m⁰(N⁻)更少的观察次数。具体来说,假设我们有兴趣进行测试:
然后,
请注意,分布仍然遵循二项分布,参数与前一个案例的推理相同。最后,我们讨论双侧假设的情况:
对于这种情况,我们计算样本的 N⁺ 和 N⁻:
与之前一样,p 值给出了比 6 或更多大于 0.5 的数值更极端的结果的概率。因为这是一个双侧检验,所以极端结果可以是 6 或更多大于 0.5 的数值,或者 4 或更少大于 0.5 的数值。
和以前一样,p 值相当大。因此,即使在 10% 的显著性水平下,由于 p 值 > 0.10,我们也未能拒绝原假设!这难道不令人着迷吗?仅仅是简单的计数和最基本的概率分布就能让我们测试这样的假设。但我们能否推广结果?换句话说,我们能否将此检验通用于任何特定分位数,而不仅仅是中位数?当然,方法论保持完全相同。例如,假设对于上述相同的数据集,我们有以下假设:
注意π₀.₂₅表示数据的第 25 百分位数或第 1 四分位数。和以前一样,我们计算小于 3 的 Xᵢ数量:
现在,我们确定在零假设下上述检验统计量的分布。由于在零假设下π₀.₂₅ = 3,因此样本小于 3 的概率必须是 0.25。因此,N⁻测量小于 3 的样本数量,每个样本在零假设下有 0.25 的概率贡献给 N⁻。换句话说,N⁻计算成功的数量,每个成功的概率是 0.25。这定义了一个参数化为样本数量 n = 10,成功概率 p = 0.25 的二项随机变量。因此,
因此,
这是一个较低的 p 值,但仍不足以在 5%或 10%的显著性水平下拒绝。由此,我们结束了对单样本符号检验的讨论。
工具 2:两样本符号检验
在本节中,我们将尝试将前面介绍的符号检验推广到两样本的情况。之前,我们提供了数据(由单一样本 X 的观察值组成),我们可以检验中位数(或任何分位数)是否大于、小于或不等于给定的阈值。在本节中,我们将上述概念扩展到两样本的情况。特别地,假设我们得到独立的样本对数据(x₁, y₁),· · ·, (xₙ, yₙ)。零假设声明两个样本大于对方的概率相等,即它们的中位数差为 0,而备择假设则建议两个样本之间存在差异,即中位数差异为正、负或非零。数学上,零假设和备择假设如下:
示例:假设我们给出了以下配对数据:
假设如下:
推导检验统计量并找到其分布的过程保持类似。在前面的案例中,我们只是检查了样本是否大于或小于阈值(零假设下的值)。在这个案例中,我们通过比较每对观察值来检查符号。换句话说,我们检查每个观察值的 Wᵢ = Xᵢ − Yᵢ的符号,从 i = 1 到 n:
表 1:作者提供的图片
检验统计量定义为:
根据之前的逻辑,在原假设下,检验统计量的分布是 Bin(n, 0.5)(可以将检验统计量的值看作在 n 次试验中的成功次数,其中每次成功即 Xᵢ > Yᵢ 的概率为 0.5,因为两个样本都同样可能大于对方)。因此,p 值由以下公式给出:
确实,p 值要小得多,我们可以在 10%的显著性水平下拒绝原假设!最后,如果备择假设是双侧的,我们来尝试计算相同数据的 p 值:
因为这是一个双侧检验,极端结果可以是 8 个或更多正符号,或者 2 个或更少正符号:
因此,我们无法在 10%的显著性水平下拒绝双侧假设。这结束了我们关于进行单样本和双样本符号检验的讨论。
符号检验的局限性
在前两节中,我们使用符号检验进行不同类型的假设检验。由于其非参数性(即分布无关性),符号检验被发现非常有用。然而,一般来说,符号检验的能力并不是很强(即,对于相同的显著性水平,第二类错误的概率仍然很高)。主要原因是符号检验只考虑值的符号,即它们是否小于原假设下的阈值(对于单样本)或是否小于其对应值(对于双样本)。它没有考虑差异的大小,即偏离 0 的程度。在实践中,符号检验很少使用,但由于其极大的简单性,它仍然是引入非参数假设检验讨论的一个很好的工具。这引导我们进入一个新的假设检验框架:威尔科克森符号秩检验,这在某种程度上是对符号检验的扩展,考虑了偏离 0 的大小顺序,并为每个样本值分配秩。在下一节中,我们将更详细地描述该检验。
工具 3:单样本威尔科克森符号秩检验
威尔科克森符号秩检验背后的理论稍微复杂一些。但不用担心。让我们重新审视上一节中的例子,并依次应用威尔科克森检验:
步骤 1: 计算每个 Xᵢ 和 m⁰ 之间差值的绝对值:
表 2:作者提供的图片
步骤 2: 对步骤 1 中计算出的每个值进行排名,即为每个 | Xᵢ − m⁰| 分配排名 (Rᵢ),从 1 到 n:
表 3:作者提供的图片
步骤 3: 计算每个样本的符号秩 (Rₛᵢ),其中符号由 Xᵢ − 4 的符号给出(与符号检验中使用的符号相同),即:
表 4:作者提供的图像
步骤 4: 计算 Wilcoxon 符号秩检验统计量,其由所有数据点的符号秩之和给出:
在讨论 W 的分布之前,让我们暂停一下,思考这些步骤的逻辑。在符号检验中,我们只是计算了大于或小于 m⁰ 的样本数量。在这里,我们通过秩来加权计数,这衡量了不同样本相对于 m⁰ 的绝对偏差。这使我们能够对远小于或远大于 m⁰ 的值给予更高的权重,帮助我们克服符号检验的局限性。
现在,让我们评估 W 的分布。需要提到的是,W 的分布没有封闭形式的公式(虽然其矩生成函数有封闭形式的表达式,但其质量函数没有这样的表达式)。一种方法是使用表格(是的,有专门为不同样本量设计的 W 临界值表)。另一种替代方法是使用 Lyapunov CLT 来近似 W 的分布(CDF):
其中 Φ 是标准正态分布的累积分布函数。精确的数学公式相当复杂,超出了本文的范围。但是,我们仍将尽力理解它。让我们尝试计算 W 的期望和方差:
其中 Sᵣ 表示第 rᵗʰ 秩的符号(所有秩值将从 1 到 n)。因此,
如果我们对 W 进行标准化,我们得到:
确实,它与 Φ 内部的表达式非常相似。实际上,通过 Lyapunov CLT(不是传统的 CLT,因为尽管 rSᵣ 是独立的,但它们不一定是同分布的),我们 h
这导致了 W 分布中的Φ项。你可能还会注意到 W 的 CDF 包含一个额外的 1. 这只是一个单位修正。回忆一下 W 是一个离散随机变量。每当离散随机变量被连续随机变量(例如正态分布)近似时,添加修正项总是很重要的,通常是半单位修正。半单位修正通过调整连续分布的概率,使其更接近离散分布的概率,从而帮助解决这个差异。具体来说,这个修正涉及将用于定义连续分布的区间的中点向相反的四舍五入约定方向移动 0.5 单位。这确保了连续分布中分配给区间的概率更接近离散分布的概率,从而提高了近似的准确性。然而,对于近似 W,我们倾向于使用全单位修正(而不是传统的半单位修正)。这是因为 W 的值只能以 2 的倍数不同。这样考虑:如果你有一个 W 值为 w,并且你有兴趣将 W 值减少 1,你将不得不翻转一个正排名,这会使 W 的值减少 2。例如,在我们的示例中,W 被计算为 3。如果我们想减少 W 值 1,我们能做的最好是将+1 翻转为-1,但这将使 W 的值减少 2(-1–1 = -2)。类似的逻辑适用于增加 W 的值。因此,为了控制 W 可以取的值范围,使用全单位修正(0.5 × 2 = 1)而不是传统的半单位修正(0.5 × 1 = 0.5)。因此,在应用全单位修正并使用 Lyapunov CLT 之后,我们得到:
现在我们已经获得了 W 分布的近似表达式,我们继续计算我们示例的 p 值。回忆一下,p 值表示在原假设为真的假设下观察到比样本观测值更极端的值的概率。因此,
显然,p 值相当大。因此,即使在 10%的显著性水平下,由于 p 值 > 0.10,我们未能拒绝原假设!这就是 Wilcoxon 符号秩检验的简单而有用的应用。现在让我们考虑当备择假设在另一个方向上的情况。特别是,假设我们有兴趣测试:
检验统计量仍然保持不变。然而,由于支持备择假设的方向发生变化,p 值计算也相应调整(根据 p 值的定义):
再次,p 值较大,我们在 10% 的显著性水平下未能拒绝原假设。最后,让我们看一下双边情况:
检验统计量仍然保持不变。然而,就像之前一样,由于支持替代假设的方向发生了变化,p 值的计算也会相应调整(按照 p 值的定义):
再次,p 值较大,我们在 10% 的显著性水平下未能拒绝原假设。现在,让我们将检验统计量推广到任何特定的分位数,而不仅仅是中位数。方法完全相同。例如,假设对于上面的相同数据集,我们给出以下假设:
就像之前一样,我们构建表格并汇总符号秩以得到检验统计量:
表 5:作者提供的图片
现在,我们确定上述检验统计量在原假设下的分布:
如果我们标准化 W,我们得到
根据 Lyapunov CLT,我们有:
因此,
这是一个较低的 p 值,但仍然不够低,无法在 5% 或 10% 显著性水平下拒绝原假设。至此,我们结束了对单样本 Wilcoxon 符号秩检验的讨论。
Wilcoxon 符号秩检验:可能的复杂情况
使用 Wilcoxon 符号秩检验时可能会出现两种可能的复杂情况:
-
对于 i ≠ j,|Xᵢ − m⁰| = |Xᵢⱼ − m⁰| 即,绝对偏差与 m⁰ 相同。在这种情况下,哪个观察值会被分配更高的秩?首先,在数据遵循连续分布的假设下,相同的数据理论上不应出现多次。但是,实际上,往往会发生这种情况。有很多方法可以解决这个问题,但最常见的策略是为每个样本分配秩的平均值。例如,如果有 4 个样本值,它们与 m⁰ 的绝对偏差相同。如果这些观察值的秩为 7、8、9 和 10,则为每个样本分配平均秩:(7 + 8 + 9 + 10)/4 = 8.5。
-
如果 |Xᵢ − m⁰| = 0,对于某些 i,我们从分析中排除该样本。我们仅使用减少后的样本(以及相应的减少样本量)来计算检验统计量及其分布。
例如,如果我们给出以下数据和假设:
我们排除第 5 个样本(因为 |X₅ − 3| = 0),并使用剩余的样本来计算平均秩:
表 6:作者提供的图片
工具 4: 两样本 Wilcoxon 符号秩检验
作为我们最后的非参数假设检验工具包,让我们看一下 Wilcoxon 符号秩检验的两样本扩展。如前所述,原假设认为中位数的差异为 0,而备择假设则建议两个样本之间存在差异,即中位数的差异为正、负或非零。数学上,原假设和备择假设如下:
首先看一下总体框架,然后考虑一个示例。假设我们有两个样本的数据:X₁, X₂, · · ·, Xₙ₁ 和 Y₁, Y₂, · · ·, Yₙ₂。我们将两个样本组合成一个样本,并将所有观测值按升序排列。对于每个观测值,我们分配排名(如有争议则使用平均排名),从 1, 2, · · ·, n1 + n2 开始。最后,我们计算所有 X 样本观测值的排名总和,我们称之为测试统计量 W。例如,考虑以下配对数据:
假设如下:
步骤 1: 组合 Xᵢ 和 Yᵢ:
24.27, 8.63, 16.76, 21.92, 29.59, 4.01, 7.28, −7.75, −6.61, 13.05, 13.47, 24.6, −4.97, 0.07, 6.96, −0.53, 7.26, −11.7, −5.01, −4.43
步骤 2: 将组合排列成升序(记得跟踪哪些观测值来自哪个样本):
表 7: 作者提供的图片
步骤 3: 分配排名:
表 8: 作者提供的图片
步骤 4: 通过对 X 样本的排名求和来计算测试统计量:
接下来,我们找到 W 在原假设下的分布。如前所述,W 的分布没有封闭公式,因此我们使用 Lyapunov CLT 来近似 W 的分布(CDF):
其中 Φ 是标准正态分布的累积分布函数。我们可以通过计算 W 的期望和方差来检查这一点。请注意,这一计算相当复杂,因此您可以跳过它,直接进行 p 值计算。但我们仍包括这一部分以求完整。让 Rˣᵢ 表示分配给 X 的第 i 个样本的排名,而 Rʸⱼ 表示分配给 Y 的第 j 个样本的排名:
在原假设下,由于分布相同,Rˣᵢ 和 Rʸⱼ 必须在 1 ≤ i ≤ n₁; 1 ≤ j ≤ n₂ 的范围内完全分布。因此,
方差的计算略微复杂。我们利用以下事实:
因此,
类似地,对于 i ̸= j:
因此,根据方差和协方差的定义,我们有:
因此,通过方差的扩展和求和:
因此,如果我们标准化 W 并应用 CLT,我们得到:
因此,
因此,在 10% 的显著性水平下,由于 p 值 < 0.10,我们可以拒绝零假设!最后,让我们尝试计算相同数据的 p 值,如果备择假设是双侧的:
测试统计量仍然保持不变。然而,就像以前一样,由于支持备择假设的方向改变,p 值的计算相应地进行了调整(根据 p 值的定义):
因此,在双侧情况下,我们无法在 10% 的显著性水平下拒绝零假设。这结束了我们对进行 Wilcoxon 符号秩检验进行单样本和双样本情况讨论。
结论
在本文中,我们熟悉了一些最知名的非参数或无分布假设检验框架。我们查看了符号检验和 Wilcoxon 符号秩检验在单样本和双样本情况下的表现,并比较了它们在样本观察中的表现。我们探讨了每个测试的单侧和双侧情况,以及如何将它们推广为测试数据的任何给定分位数。符号检验虽然一般不太强大,但非常简单,仅依赖于二项分布的累积分布函数来推导相关的 p 值。另一方面,Wilcoxon 符号秩检验在理论上更为复杂,但往往能够给出更好的结果,因为它不仅考虑值是否小于或大于阈值,还考虑它们绝对偏差的相对大小。
希望您喜欢阅读本文!如果您有任何疑问或建议,请在评论框中回复。
如果您喜欢我的文章并希望阅读更多,请随时通过 邮件 联系我。访问此 链接。
注:所有图片均由作者制作。