TowardsDataScience 2024 中文翻译(十八)
原文:TowardsDataScience协议:CC BY-NC-SA 4.0语言模型是基准测试天才还是现实世界问题解决者?原文:towardsdatascience.com/are-language-models-benchmark-savants-or-real-world-problem-solvers-725a7e1524e1?source=collection_archive------
语言模型是基准测试天才还是现实世界问题解决者?
评估语言模型在现实任务中的演变与应用
https://medium.com/@tula.masterman?source=post_page---byline--725a7e1524e1--------------------------------https://towardsdatascience.com/?source=post_page---byline--725a7e1524e1-------------------------------- Tula Masterman
·发布于 Towards Data Science ·7 分钟阅读·2024 年 3 月 23 日
–
AI 学生在教室里参加考试。图片由作者和 DALL-E 3 创作。
在教育领域,最好的考试是那些挑战学生将所学知识应用于新的和不可预测的方式的考试,这种考试不仅仅是让学生记住事实,而是展示他们的真正理解。我们对语言模型的评估也应遵循相同的模式。随着我们每天看到新的模型涌入 AI 领域,无论是来自像 OpenAI 和 Anthropic 这样的巨头,还是来自较小的研究团队和大学,至关重要的是,我们的模型评估应深入到标准基准测试的表现之上。新兴研究表明,我们一直以来用来衡量模型能力的基准并不像我们曾经认为的那样可靠。为了能够适当地支持新模型,我们的基准必须发展成为与我们要求这些模型和新兴 AI 代理架构解决的现实世界挑战一样动态和复杂。
在本文中,我们将通过回答以下问题来探讨语言模型评估的复杂性:
-
目前语言模型是如何评估的?
-
在基准测试中表现优秀的语言模型有多可靠?
-
语言模型和 AI 代理能否将知识转化为行动?
-
为什么语言模型(或基础模型)需要掌握的不仅仅是文本?
那么,今天语言模型是如何评估的?
今天,大多数模型,无论是大型语言模型(LLM)还是小型语言模型(SLM),都在一组共同的基准上进行评估,包括大规模多任务语言理解(MMLU)、小学数学(GSM8K)和 Big-Bench Hard(BBH)数据集等。
为了更深入地理解每个基准评估的任务类型,以下是来自每个数据集的一些示例问题:
-
MMLU:旨在通过多项选择题衡量模型在预训练过程中学习到的关于 STEM 和人文学科各个学科以及从小学到高级专业理解的各个难度水平的信息。
MMLU 中的医学类大学问题示例:“在对新生儿进行基因检测时,发现了一种罕见的遗传病,该病具有 X 连锁隐性遗传方式。以下哪项陈述可能是关于该病家族系谱的正确描述? A. 所有母系后代都会患此病 B. 女性的发病率大约是男性的两倍 C. 所有患病男性的女儿都会患病 D. 男性和女性的发病率将相等。”(正确答案是 C) [2]
-
GSM8K:语言模型通常难以解答数学问题,GSM8K 数据集评估模型在解答 8.5k 个多样化的小学数学问题时的推理能力和解题能力。
示例:“Dean 的母亲给了他 28 美元去杂货店。Dean 买了 6 辆玩具车和 5 只泰迪熊。每辆玩具车的价格是 12 美元,每只泰迪熊的价格是 1 美元。之后,他的母亲心情好,决定再给他 10 美元。那么 Dean 剩下多少钱?” [3]
-
BBH:该数据集由 23 个任务组成,这些任务来自 Big Bench 数据集,语言模型通常难以解决这些任务。这些任务通常需要多步推理才能成功完成。
示例:“如果你按照这些指示走,你是否会回到起点?左转。右转。走 5 步。走 4 步。转身。走 9 步。选项:— 是 — 否” [4]
Anthropic 最近宣布,Claude-3 模型凭借其 Opus 版本在大多数常见基准上超越了 GPT-4,成为领先的模型。例如,Claude-3 Opus 在 MMLU 上取得了 86.8%的成绩,略微超越了 GPT-4 的 86.4%。Claude-3 Opus 还在 GSM8K 上得到了 95%的成绩,在 BBH 上得到了 86.8%,而 GPT-4 分别为 92%和 83.1% [1]。
尽管像 GPT-4 和 Claude 这样的模型在这些基准测试中的表现令人印象深刻,但这些任务并不总是代表企业想要解决的挑战类型。此外,越来越多的研究表明,模型正在记住基准问题,而不是理解它们。这并不意味着这些模型不能推广到新任务,我们每天都看到 LLM 和 SLM 完成惊人的任务,但这意味着我们应该重新考虑如何评估、打分和推广模型。
在基准测试中表现出色的语言模型有多可靠?
来自微软、自动化研究所(中国科学院)和中国科学技术大学的研究表明,当向不同的语言模型提问经过改写或修改的基准问题时,这些模型的表现明显比直接提问相同基准问题时差。为了展示他们研究的目的,研究人员在论文中展示了 DyVal 2,研究者从像 MMLU 这样的基准中取出问题,通过改写问题、为问题添加额外的答案、改写答案、排列答案顺序或为问题增加额外内容等方式进行修改。在比较“原始”数据集与修改后问题的模型表现时,他们发现性能下降,例如GPT-4 在原始 MMLU 问题上的得分为 84.4,在修改后的 MMLU 问题上的得分为 68.86 [5]。
来源:DyVal2,原始基准与探测基准上模型表现比较
同样,来自亚利桑那大学计算机科学系的研究表明,语言模型中存在大量数据污染 [6]。这意味着基准中的信息正成为模型训练数据的一部分,实际上使得基准得分变得无关紧要,因为模型是在自己已被训练过的信息上进行测试的。
来自复旦大学、同济大学和阿里巴巴的额外研究强调了需要为 AI 代理设计自我进化的动态评估,以应对数据污染和基准记忆化的问题 [7]。这些动态基准将有助于防止模型在预训练过程中记住或学习它们后续将被测试的信息。尽管不断增加新的基准可能会在将旧模型与新模型进行比较时带来挑战,但理想情况下,这些基准将减轻数据污染问题,并使得评估模型理解训练中话题的能力变得更容易。
在评估模型在特定问题上的能力时,我们需要理解模型在预训练过程中学到的信息的理解程度,以及它能多好地将这些知识推广到新的任务或概念,超越它的训练数据。
语言模型和 AI 智能体能否将知识转化为行动?
当我们考虑使用模型作为 AI 智能体代表我们执行任务时,无论是预订假期、写报告,还是为我们研究新话题,我们都需要额外的基准或评估机制来评估这些智能体的可靠性和准确性。大多数希望利用基础模型力量的企业需要允许模型访问集成其独特数据源的各种工具,并要求模型推理和规划何时以及如何有效地使用这些工具。这些类型的任务在许多传统的 LLM 基准中并未得到体现。
来源:AgentVerse,智能体团队与单一智能体在涉及工具调用和代码执行的软件开发任务中的比较结果
为了解决这个问题,许多研究团队正在创建自己的基准和框架,用于评估智能体在涉及工具使用和超出模型训练数据的知识任务中的表现。例如,AgentVerse 的作者评估了智能体团队在执行现实世界任务(如活动策划、软件开发和咨询)方面的表现。研究人员创建了自己的一套 10 个测试任务,并通过人工评估来判断智能体是否执行了正确的操作、使用了合适的工具,并得出了准确的结果。他们发现,采用包含明确阶段(智能体招募、任务规划、独立执行任务和后续评估)周期的智能体团队,比独立智能体的表现更优秀 [8]。
超越单一模态,走向现实世界。为什么语言模型(或基础模型)要掌握文本之外的内容?
在我看来,正在出现的智能体架构和基准是理解语言模型在商业问题上表现如何的重要一步,但一个限制是,大多数仍然集中于文本。随着我们考虑到世界及大多数工作的动态性,我们需要评估模型在文本任务、视觉和听觉任务上表现的智能体系统和模型。AlgoPuzzleVQA 数据集就是一个评估模型是否能够推理、阅读和视觉解读数学和算法谜题的例子 [9]。
来源:语言模型是谜题天才吗? 来自 AlgoPuzzleVQA 数据集的示例问题
尽管企业可能不关心模型能多好地解答难题,但这仍然是理解模型如何推理多模态信息的一个正确方向。
结论
随着我们在日常生活和职业工作中不断采用基础模型,我们需要更多能够反映现实世界问题的评估选项。动态和多模态基准是其中的一个关键组成部分。然而,随着我们引入更多的代理框架和架构,多个 AI 代理协同解决问题,跨模型和框架的评估与比较变得更加具有挑战性。基础模型的真正衡量标准,不在于它们能否征服标准化测试,而在于它们在复杂且往往不可预测的现实世界中理解、适应和行动的能力。通过改变我们对语言模型的评估方式,我们挑战这些模型从基于文本的智力和基准测试专家,发展成为能够应对多方面(和多模态)挑战的全面思考者。
有兴趣进一步讨论或合作?请通过 LinkedIn联系!
离群点更难预测吗?
一项关于机器学习模型在预测离群点时是否更容易出错的实证分析
https://medium.com/@mazzanti.sam?source=post_page---byline--ae84dd4be465--------------------------------https://towardsdatascience.com/?source=post_page---byline--ae84dd4be465-------------------------------- Samuele Mazzanti
·发布于 Towards Data Science ·阅读时间:8 分钟·2024 年 2 月 4 日
–
[图像由作者提供]
离群点是与大多数数据群体差异很大的个体。传统上,在实践者中,离群点往往不被信任,这也是为什么通常会采取删除离群点的措施来处理数据集。
然而,在处理真实数据时,离群点是常见的现象。有时候,它们比其他数据点还要重要! 例如,假设有一些离群点是因为他们是非常高付费的客户:你肯定不想丢弃他们,实际上,你可能希望特别关注他们。
离群点的一个有趣的——且未被充分探索的——方面是它们与机器学习模型的互动。我的感觉是,数据科学家们认为离群点会损害他们模型的表现。但这种看法很可能是基于一种先入为主的观念,而非真实的证据。
因此,我在本文中将尝试回答以下问题:
机器学习模型在预测离群点时是否更容易出错?
问题框架
类人机器人会一直存在吗?
类人机器人可能最终解决困扰机器人适应的“旧场地”问题,而最近在多模态变换器和扩散模型方面的突破,可能真的让这一切成为现实。
https://medium.com/@nikolaus.correll?source=post_page---byline--050da171530b--------------------------------https://towardsdatascience.com/?source=post_page---byline--050da171530b-------------------------------- Nikolaus Correll
·发表于 Towards Data Science ·10 分钟阅读·2024 年 3 月 1 日
–
几乎每周都有类人公司发布新更新。Optimus 能走路了?Digit 刚刚移动了一个空的购物篮?Figure 也做到了!似乎真正的公司终于开始关注了。从特斯拉开始,类人机器人现在已经在亚马逊和宝马“工作”,距离进入我们的家庭和花园只差一步。
如果你不是 Medium 的订阅者,你可以 在这里免费阅读这篇文章。
一位类人机器人正在清理(它自己的?)乱摊子,同时准备做饭。类人形态在无缝集成现有价值创造流程方面具有巨大潜力。图片:作者通过 miramuseai.net 提供
我们是孤独的吗?
遭遇外星生命的真实概率(德雷克方程系列的第五部分)
https://medium.com/@james.r.gearheart?source=post_page---byline--344db95c0166--------------------------------https://towardsdatascience.com/?source=post_page---byline--344db95c0166-------------------------------- James Gearheart
·发表于Towards Data Science ·阅读时间 11 分钟·2024 年 9 月 8 日
–
回顾:
在本系列文章中,我们探讨了可能导致外星文明存在的各种因素,从宜居行星的数量到智能文明是否发展出通讯技术的概率。在本文的最后一篇,我们探讨了终极问题:我们曾经遇到过外星生命吗?我们未来会遇到它们吗?
所有图片均由作者使用 Midjourney 创作。
第 10 步:理性应对外星遭遇
对外星生命的探索长期以来一直是科学、猜测和耸人听闻的混合体。从 UFO 目击到政府的 UAP(不明空中现象)报告,公众的想象力一直被外星遭遇的想法所吸引。然而,从科学的角度来看,我们是否已经遇到过外星生命——或者将来是否有可能遇到外星生命,究竟有多大可能?
这时,理性、数据驱动的方法就显得尤为重要。通过结合德雷克方程、现代模拟和贝叶斯概率模型,我们终于可以计算出过去和未来遭遇外星生命的可能性。
为什么这一步很重要
很容易被潜在外星遭遇的兴奋所感染,但现实却远比想象复杂。即使银河系中存在智能文明,它们与我们文明在时间和距离上的重叠几率也极其微小。本文将帮助我们量化这些遭遇的可能性,基于过去和未来的可能性,为我们提供一个更清晰的概率图景。
贝叶斯概率与外星遭遇
贝叶斯推理使我们能够在新证据(或证据缺乏)出现时更新我们的概率估计。在外星接触的案例中,我们可以使用这种方法来评估过去和未来接触的概率。
让我们来解析贝叶斯方法:
-
P(H|E):给定当前证据,外星人存在并且我们已与其接触的概率。
-
P(H):我们的先验概率,或是我们对外星人相遇已经发生或将要发生的可能性的初步假设。
-
P(E|H):假设相遇假设为真,当前证据(例如没有确认的外星接触)出现的可能性。
-
P(E):证据的总体概率,它考虑了所有可能的假设。
我们将使用这个框架来计算过去和未来的相遇。
外星接触的贝叶斯蒙特卡洛模拟:理解方法
为了量化过去和未来外星接触的概率,我们采用了贝叶斯框架,并结合蒙特卡洛模拟来处理参数中固有的不确定性。本节将带您了解这两种方法背后的基本原理和方法论,然后展示实际代码。
为什么使用贝叶斯分析?
贝叶斯分析是一种基于新证据更新事件概率的强大方法。在我们的例子中,事件是我们是否已经遇到或将遇到外星文明。通过结合先验知识和现有的(尽管有限的)证据——例如缺乏确认的接触——我们可以细化我们的估计并量化过去和未来外星人接触的相关不确定性。
贝叶斯定理允许我们计算后验概率——换句话说,在我们假设和观察的基础上,外星人相遇的可能性。这个过程至关重要,因为它会随着新信息的出现不断更新我们的理解,无论是外星生命的确凿证据,还是继续缺乏接触的情况。
为什么使用蒙特卡洛模拟?
鉴于德雷克方程和其他与外星人接触相关的概率中的不确定性和变异性,使用一组固定的值来估计概率是不现实的。相反,蒙特卡洛模拟使我们能够为每个参数(例如接触的可能性或外星生命存在的先验概率)采样一组广泛的合理值。
通过使用这些不同的值进行数千次模拟,我们可以探索一系列结果,而不是依赖于僵化的点估计。结果是我们对过去和未来相遇的可能性有了更细致的理解,同时对每种情景的概率分布也有了更清晰的认识。
现在,让我们深入了解实际的代码实现:
**********************************;
**********************************;
/* Set the random seed for reproducibility */
data _null_;
call streaminit(1234);
run;
/* Number of simulations */
%let num_simulations = 100000;
/* Number of civilizations to generate */
%let num_civilizations = 2364;
/* Galactic radius and height in light years */
%let galactic_radius = 50000;
%let galactic_height = 1300;
/* Earth's position (assumed to be at 3/4 of the galactic radius) */
%let earth_position_x = &galactic_radius * 3 / 4;
%let earth_position_y = 0;
%let earth_position_z = 0;
/* Create a dataset to store civilization positions */
data civilization_positions;
length Civilization $10.;
input Civilization $ Position_X Position_Y Position_Z;
datalines;
Earth &earth_position_x &earth_position_y &earth_position_z
;
run;
/* Generate random positions for other civilizations */
data civilization_positions;
set civilization_positions;
do i = 1 to &num_civilizations;
Position_X = rand("Uniform") * &galactic_radius;
Position_Y = rand("Uniform") * 2 * &galactic_height - &galactic_height;
Position_Z = rand("Uniform") * 2 * &galactic_height - &galactic_height;
Civilization = "Civilization " || strip(put(i, 8.));
output;
end;
drop i;
run;
/* Calculate the distance between civilizations and Earth */
data civilization_distances;
set civilization_positions;
Distance = sqrt((Position_X - &earth_position_x)**2 + (Position_Y - &earth_position_y)**2 + (Position_Z - &earth_position_z)**2);
run;
/* Calculate the minimum distance to Earth for each civilization */
proc sql;
create table civilization_min_distance as
select Civilization, Distance as Min_Distance
from civilization_distances
order by Distance;
quit;
/* Calculate the probability of encountering civilizations based on distance */
data probability_encounter;
set civilization_min_distance;
Probability = 1 / (1 + Min_Distance);
run;
/* Calculate the average probability for each distance band */
proc sql;
create table average_probability as
select case
when Min_Distance <= 1000 then 'Close'
when Min_Distance > 1000 and Min_Distance <= 3000 then 'Medium'
when Min_Distance > 3000 then 'Far'
end as Distance_Band,
avg(Probability) as Average_Probability
from probability_encounter
group by case
when Min_Distance <= 1000 then 'Close'
when Min_Distance > 1000 and Min_Distance <= 3000 then 'Medium'
when Min_Distance > 3000 then 'Far'
end;
quit;
/* Print the result */
proc print data=average_probability;
run;
/* Select the closest civilization to Earth and its associated probability */
proc sql;
create table closest_civilization as
select Civilization, Min_Distance, Probability
from probability_encounter
where Min_Distance = (select min(Min_Distance) from probability_encounter);
quit;
/* Print the result */
proc print data=closest_civilization;
run;
/*Bayesian analysis for probability of encountering aliens in the past or future*/
/* Set seed for reproducibility */
%let num_iterations = 100;
/* Create Bayesian analysis dataset */
data bayesian_analysis;
call streaminit(123);
/* Define variables for posterior probabilities */
array posterior_past[&num_iterations];
array posterior_future[&num_iterations];
do i = 1 to &num_iterations;
/* Sample prior probabilities and likelihoods for past encounters */
prior_past = rand("Uniform", 0.0001, 0.01); /* P(Past encounter) */
likelihood_past_encounter = rand("Uniform", 0.001, 0.1); /* P(No contact | Past encounter) */
likelihood_no_encounter_past = rand("Uniform", 0.8, 0.99); /* P(No contact | No encounter) */
/* Calculate posterior probability for past encounter using Bayes' Theorem */
numerator_past = prior_past * likelihood_past_encounter;
denominator_past = numerator_past + (1 - prior_past) * likelihood_no_encounter_past;
posterior_past[i] = numerator_past / denominator_past;
/* Sample prior probabilities and likelihoods for future encounters */
prior_future = rand("Uniform", 0.001, 0.05); /* P(Future encounter) */
likelihood_future_encounter = rand("Uniform", 0.01, 0.1); /* P(No contact | Future encounter) */
likelihood_no_encounter_future = rand("Uniform", 0.8, 0.99); /* P(No contact | No encounter) */
/* Calculate posterior probability for future encounter using Bayes' Theorem */
numerator_future = prior_future * likelihood_future_encounter;
denominator_future = numerator_future + (1 - prior_future) * likelihood_no_encounter_future;
posterior_future[i] = numerator_future / denominator_future;
end;
/* Output the results */
do i = 1 to &num_iterations;
posterior_past_value = posterior_past[i];
posterior_future_value = posterior_future[i];
output;
end;
keep posterior_past_value posterior_future_value;
run;
/* Summary statistics for the posterior probabilities */
proc means data=bayesian_analysis mean std min max;
var posterior_past_value posterior_future_value;
run;
/* Distribution histograms for the posterior probabilities */
proc sgplot data=bayesian_analysis;
histogram posterior_past_value / transparency=0.5 fillattrs=(color=blue) binwidth=0.00001;
title "Distribution of Posterior Probabilities for Past Encounters";
run;
proc sgplot data=bayesian_analysis;
histogram posterior_future_value / transparency=0.5 fillattrs=(color=green) binwidth=0.0001;
title "Distribution of Posterior Probabilities for Future Encounters";
run;
使用这段代码,我们在一系列假设下模拟了过去和未来的外星人遭遇,从而利用贝叶斯推理估算每种情境的可能性。在过程结束时,我们得到了过去和未来外星人接触的概率分布,接下来我们将分析这些分布以获取更多洞见。
分析表格和图形输出
表格输出
该表格展示了后验概率的汇总统计数据,这些概率表示了过去和未来外星人遭遇的可能性:
posterior_past_value:
-
平均值:0.000306778
-
标准差:0.000262715
-
最小值:8.258388E-6
-
最大值:0.0010357
posterior_future_value:
-
平均值:0.0015038
-
标准差:0.0012378
-
最小值:0.000036464
-
最大值:0.0052718
解释:
-
过去遭遇:过去遭遇的平均概率约为 0.0003,或约 0.03%。更直观地说,这意味着我们过去遇到外星人的几率约为1/3,260。
-
未来遭遇:未来遭遇的平均概率较高,大约为 0.0015,即 0.15%。这意味着未来遇到外星人的几率大约为1/667。
这些数值的范围表明存在相当大的不确定性,这也符合数据和假设的局限性。过去遭遇的最小值低至 0.000008(即 1/125,000),而最大值则接近 0.001(即 1/1,000)。未来遭遇的值从 0.000036(1/27,397)到 0.005(即 1/190)不等。
图形输出
-
过去遭遇的后验概率分布:
直方图显示了一个广泛的分布,大多数概率集中在较低的范围内,低于 0.0005。 这表明,在我们的模拟中,过去遭遇外星人的可能性普遍较低,但仍然有少数几次情况下,概率较高,接近 0.001(即千分之一)。
2. 未来遭遇的后验概率分布:
未来遭遇的分布更为分散,最高概率的发生集中在 0.0005 到 0.002 之间。 这表明,尽管未来遭遇外星人的可能性仍然较低,但其概率比过去的遭遇更高。分布的形态表明,尽管接触的几率较低,但根据不同假设的结果,未来遭遇发生的可能性并非微不足道。
关键要点和概率计算
过去遭遇:
过去接触的平均后验概率约为 0.0003。用简单的概率来说,这相当于1/3,260的机会表明人类可能已经与外星生命接触过,只是没有意识到。这个广泛的分布反映了不确定性,概率从最低的 1/125,000 到最高的 1/1,000 不等,这取决于我们对先验概率和证据的假设。
未来的接触:
未来接触的平均后验概率为 0.0015,这意味着有1/667的机会我们将来某个时候会遇到外星生命。尽管这种可能性仍然不大,但与过去的接触相比,这个更高的概率表明未来接触的机会更大(尽管仍然微小)。该分布的范围从最低的 1/27,397 到更乐观的 1/190,反映了可能结果的广泛范围。
将一切联系起来:这意味着什么?
在这系列研究中,我们的旅程是一次令人着迷的概率、不确定性和最宏大的问题的探索:我们在宇宙中是否孤独?以德雷克方程为框架,我们探讨了从适宜居住行星的形成到智能、能沟通的文明的发展每一个步骤。但这一切意味着什么,为什么我们要采取这种方法?
更大的图景
-
我们为什么要这么做: 我们的目标简单却深刻:理性地评估外星文明存在的可能性,更重要的是,评估我们是否已经与它们接触过,或者未来是否会接触。流行文化中有很多关于 UFO、目击事件和神秘信号的猜测,但我们希望以科学的方式来处理这个问题。通过运用德雷克方程,使用蒙特卡洛模拟,并应用贝叶斯推理,我们试图为这个模糊的问题提供一些具体的数字。
-
我们是如何做到的: 我们采用的方法不是寻求确定的答案,而是理解可能性范围。德雷克方程的每一步都带来了巨大的不确定性——有多少适宜居住的行星,多少发展出了生命,多少文明在向宇宙发出信号。为了应对这种不确定性,我们使用了蒙特卡洛模拟,这使我们能够考虑广泛的结果并计算分布,而不是单一的估算值。贝叶斯分析帮助我们根据当前的证据(或者缺乏证据)来细化这些概率,从而提供更细致的外星接触预测。
-
结果意味着什么: 这些数字乍一看可能很小,但它们的意义却非常重大。过去接触的概率(大约为 1/3,260)较低,这并不奇怪,因为缺乏确凿证据。然而,这些概率并非为零,这本身就值得注意——尽管概率很小,但我们已经可能遇到过外星生命,只是我们没有意识到。
-
未来接触的概率稍微乐观一些:大约是 1/667。尽管仍然是一个小概率事件,但这表明如果我们继续寻找,未来某个时刻我们可能会发现或与外星文明沟通。未来是不可预测的,但随着技术的进步,以及天体生物学和太空探索领域的不断扩展,这一可能性依然存在。
总结:
这项分析带给我们一个令人深思但充满希望的结论。宇宙浩瀚,星际之间的距离——更不用说文明之间的距离——令人震撼。宇宙的结构,再加上文明兴衰的时间尺度,表明遭遇的可能性微乎其微,但并非不可能。
这里的真正奇迹不仅仅在于数字,而在于它们所代表的意义:人类好奇心与我们基于理性和证据的探索能力的交汇点。我们可能是孤独的,或者我们可能在某一天与另一个智能文明共享信号。无论如何,我们为了量化这些概率所做的工作表明,这项搜索本身是值得的。它揭示了我们仍然需要了解宇宙及我们在其中的位置的多么庞大的知识。
虽然成功的机会可能不大,但未来相遇的可能性——无论多么渺茫——依然给我们提供了继续仰望星空的理由。宇宙充满了谜团,我们解决这些谜团的旅程仍在继续。无论我们是否能够与外星文明取得联系,寻找的过程本身就推动了科学、哲学以及我们集体想象力的边界。
这就是这项工作的结论——并没有给出具体的答案,而是提出了深刻的问题,这些问题将继续激发好奇心、探索和对未来几代人的奇迹感。寻找外星生命不仅是对宇宙的探索,也是对我们自身的探索。
如果你错过了之前的部分,可以从这里开始。
除非另有说明,所有图片均为作者提供
你意识到你数据专长在推动商业盈利能力方面的潜力吗?
一位供应链数据科学家的反思,他偶然发现了数据分析在帮助大小企业方面的力量。
https://s-saci95.medium.com/?source=post_page---byline--16cffb607437--------------------------------https://towardsdatascience.com/?source=post_page---byline--16cffb607437-------------------------------- Samir Saci
·发表于Towards Data Science ·11 分钟阅读·2024 年 10 月 24 日
–
图片来源:Fabian Blank via Unsplash
我在分析项目中面临的最大挑战是估算一个解决方案的投资回报率(ROI)。
销售预测引擎的投资回报率(ROI)是多少?
这是决策者在你提议设计工具来解决他们的运营或业务问题时常常会问的第一个问题。
作为物流解决方案设计经理,我的工作是为零售和时尚公司定价仓储和运输运营。
因此,估算我方案的投资回报率(ROI)变得稍微可控一些,但仍然很难说服决策者。
例如,我会解释:“这个算法将提高拣货生产力 25%,这将导致可变成本减少 12%。”
这些成功激励我分享涵盖 60 多个运营案例研究的解决方案,已发布在这个Medium 博客上。
虽然我的重点是改善物流运营,但在过程中发生了一些意想不到的事情:
如果我将重点转向商业盈利能力会怎样?
在一个项目中,我将这些工具应用于一个商业案例研究:最大化一家面包店的盈利能力.
我收到的反馈让我意识到,无论是小企业还是大企业,都需要优化他们的利润率,并且自动化数据驱动的决策。
通过使用商业语言,我能够更有效地销售我的分析解决方案。
在这篇文章中,我想分享我通过发现数据的力量来帮助企业所获得的见解——以及为什么我认为你也应该考虑这条道路。
Summary
**I. Introduction**
Exploring the challenge of proving ROI in analytics projects
**II. How Did I Develop My Business Acumen?**
Sharing my early career experience as a Solution Design Manager
**III. My journey discovering data analytics for business optimization**
Optimization methods to help a bakery business improve profitability.
**VI. Use your Analytics Skills to Solve Business Problems**
How data analytics can answer the needs of decision makers.
**V. How to Adapt your Analytics Approach to Business Problems?**
The importance of translating business problems into simple analytics solutions
**VI. Conclusion**
Understanding processes is an important skill to answer business problems
我是如何培养我的商业敏锐度的?
在我职业生涯的前四年,我为跨越亚洲的主要国际公司设计了仓储和运输解决方案。
供应链解决方案设计经理的工作是什么?
例如,想象一下像 Costco 这样的零售商希望在上海建立一个配送中心。
-
他们提供关于交易量和过程需求的数据,通常是在 RFP 中。
-
我的工作是设计解决方案(布局、人员配置、设备)并基于超过 100 个参数的成本模型来制定定价。
-
我们向客户展示解决方案,并提供详细的定价表。
我们最关心的是什么?毛利率!
为了赢得这个项目,我必须确保具有竞争力的定价,同时保持最低利润率,并且不能低于成本定价。
定价结构 — (图片来自作者)
例如,如果我报价每箱€1.25 用于拣货,我就能准确知道成本和利润是如何分解的
-
€0.57用于劳动力成本
-
€0.37用于设备和消耗品
-
€0.20用于固定仓储成本
-
€0.11为我们的毛利(销售额的 8.8%利润)
接下来是什么?你赢得了这笔生意,并签署了一个为期三年的 500 万欧元预算合同。
但是,如果客户希望将价格降低到每箱€1.10 会发生什么呢?
这在低利润公司中经常发生,比如传统零售商、汽车售后分销商或消费品公司。
你必须找到减少成本的方式,同时保持 8.8%的利润率不变。
因此,我一直在使用数据分析来
-
使用帕累托原则和 Python 减少仓库空间
-
使用路径规划算法提高仓库拣货效率
-
使用图论和 Python 优化运输路线
持续改进举措 — (图片来自作者)
以及许多其他由数据分析支持的运营改进,这些内容在这篇 Medium 博客中分享。
我可以将类似的方法应用到物流以外的领域吗?
我探索数据分析进行商业优化的旅程
这始于我为一家小型物流公司提供咨询服务,该公司将产品运送到巴黎的面包店。
以我作为解决方案设计师的天真视角,我与一家面包店连锁的老板交谈,了解他们的商业模式:
-
一根售价 €1.50 的法棍的利润率是多少(%)?
-
每卖出一个可颂,劳动力成本是多少(€)?
-
你的成本中有多少比例(%)是固定的?
-
你店里最有利润的商品是什么?
令我惊讶的是,他们无法回答这些问题中的任何一个。
我意识到,还有一种做生意的方式,其中价格的设定并不明确了解基础成本,而运营的可视性几乎为零。
这是一个巨大的机会——如果我们为这些企业主提供他们迫切需要的可视性和洞察力,会怎么样?
所以,我接受了模拟一家面包店的挑战。
我应用了在物流持续改进项目中使用的相同方法论:
-
了解他们当前的运营:固定和变动成本、瓶颈和收入来源。
-
收集和处理数据,做出必要的假设(例如,每种商品的生产成本和销售价格)。
-
建立一个 Python 模型来复制他们当前的设置并模拟不同的场景。
结果是文章中提出的解决方案:使用 Python 最大化商业盈利。
应用于面包店盈利案例的方法论 — (图像来源:作者)
最有利可图的产品组合是什么?
考虑到有限的资源来生产和储存产品,这个模型可以提供最佳的产品组合来销售。
对客户的影响超出了我的预期。
“这是我第一次能够估算我的商业策略对整体盈利能力的影响,”那位老板说。
添加指标:设备和劳动力使用比例 — (图像来源:作者)
经过几次迭代,我们改进了算法,提供了有趣的见解。
Samir:“你们生产的瓶颈是人力资源和烤箱的产能。”
对于这样一个简单的算法,用不到一小时编写,感知到的商业价值远远超过我过去的实验。
这标志着我在使用数据分析来推动商业影响的方法上的转折点。
你如何利用你的分析技能来支持企业?
利用你的分析技能来解决商业问题
自从开始我的咨询业务并开发我的可持续供应链 SaaS以来,我与来自多个行业的几十位企业家进行了交流。
这是一个评估我用数据和商业洞察力解决他们问题能力的机会。
他们需要什么?让我们来看看一个例子!
我的一个朋友,他经营着一家小型餐饮企业,使用我的模型来支持决策并最大化收入。
我朋友的商业模型 —— (图片来源:作者)
他们从中国采购可再生杯子,并通过空运或海运将其运送到当地仓库。
从仓库出发,杯子被送到咖啡店和分销商。
数据分析在这种情况下能解决哪些问题?
他面临的最大挑战之一是库存管理和现金流。
“我们不得不拒绝订单,因为我们没有足够的现金支付供应商补货费用,”他解释道。
核心问题很明确:他们需要清楚了解他们的财务流动。
咖啡杯的价值链 —— (图片来源:作者)
我需要列出所有相关参数,来解决这个问题并构建价值链模型。
-
供应商的付款条款和交货周期。
-
与客户的服务水平协议和付款条款,按销售渠道(直接客户与分销商)进行细分。
-
固定的运营成本和现金流管理。
业务的模拟引擎 —— (图片来源:作者)
结果是一个用 Python 编写的模拟引擎(具有合理的粒度),它复制了我朋友的业务。
接下来是什么?我们可以回答我朋友所有的问题!
我朋友最大的不满是缺乏可视化和无法验证假设。
-
如果我们将库存覆盖周期从 8 周减少到 6 周,会怎么样?
-
使用空运交付会更具成本效益吗?
-
我们是否应该改变销售策略,专注于分销商?
由于涉及的参数复杂,他之前无法得到明确的答案。
所有场景的总结 —— (图片来源:作者)
使用该模型模拟这些假设仅需几秒钟。
这种方法通过确认他们可以安全地减少库存覆盖,而不会影响客户供应,节省了数千欧元。
事实证明,这是一个非常强大的工具,通过简单的分析构建,帮助管理他的业务
-
了解影响价值链的参数
-
模拟“如果”场景来评估商业战略
-
寻找最优设置以最小化成本并最大化盈利
这听起来像是你的业务面临的问题吗?欲了解更多详情,请查看本文
## 使用 Python 进行商业规划 — 库存和现金流管理
小企业的商业规划,用于管理库存、预测流动性需求并最大化盈利能力……
towardsdatascience.com
模型提供的洞察帮助我的朋友减少了运营所需的现金,并降低了销售成本(COGS)。
后来,我们通过解决收入最大化问题,超越了成本降低。
他回来说有另一个与定价策略相关的请求。
https://towardsdatascience.com/business-planning-with-python-revenue-optimization-83387074826d
定价策略示例 — (图片来源:作者)
与他们的新商业伙伴——一位在餐饮业拥有资本和市场专业知识的专家合作,他们正在制定促进营业额增长的策略。
她提出了多种定价策略,见上文,旨在增加客户的订单数量。
我的朋友:“我怎么评估这些策略及其对盈利能力的影响?”
你只需要通过添加定价模块来调整模型,并估算其对盈利能力的影响。
我们可以通过多种销售量场景估算每个定价策略的盈利能力及其他商业指标。
https://towardsdatascience.com/business-planning-with-python-revenue-optimization-83387074826d
模拟定价策略 2 文章: [链接] — (图片来源:作者)
在上表中,我们模拟了定价策略二的影响,假设了七种营业额情景。
Samir:“你需要获得+200%的增长,才能通过这个策略恢复你的基线情景的盈利能力。”
我们可以通过几次点击评估每个提议的策略。
你如何利用数据分析帮助小企业在保持或改善其他方面的同时,最大化收入?
towardsdatascience.com
模型生成的洞察帮助解决了联合创始人之间的激烈讨论。
这一过程使他们就定价策略达成共识,且基于精确的盈利预测。
听起来不错,对吧?
但是,成功实施这种项目需要什么?
如何将分析方法适应商业问题?
正如我多次提到的,为这些项目设计的分析解决方案通常是“技术性基础”的。
我会说,80%的努力都在于将商业问题转化为分析解决方案。
保持好奇心!表现出对商业模式的兴趣。
这是一个积极的过程,要求你提出正确的问题,以了解哪些指标对企业主重要,以及如何建模这些流程。
<http://A reflection of a supply chain data scientist who randomly discovered the power of data analytics to help small and large businesses.>
咖啡杯的价值链 — (图片来源:作者)
在达到这种模型化水平之前,我与我的朋友进行了多次迭代,确保我的模型准确反映了他业务的现实。
因此,你需要使你的模型洞察结果对非技术观众可访问,以便他们能帮助你评估结果的准确性。
这种解决方案有需求吗?
这是一个市场需求。
自从我开始全职担任顾问以来,我收到了更多这种类型项目的请求,而不是依赖我的核心供应链工程技能。
由于你直接影响盈利能力并为商业决策者提供可见性,因此获得项目的资本支出(CAPEX)和参与变得更容易。
我们从这两个例子中学到了什么?
-
企业主缺乏对其流程和财务流动的可见性。
-
了解商业模式和流程对于设计正确的仿真模型至关重要。
-
决策者重视数据驱动的洞察力,以支持战略项目。
这种方法适用于各种不同的行业和公司规模的商业案例。
结论
我从未想到过,我会从一个优化物流运营的解决方案设计经理,踏上成为帮助企业提高盈利能力的顾问之路。
这是因为我发现先进的分析工具在业务优化中非常有效。
你不需要关注分析解决方案的复杂性(机器学习、优化或生成 AI),而是要理解业务本身。
你听说过可持续性吗?
我目前正在学习关于欧洲**企业可持续发展报告指令(CSRD)**的内容。
这将塑造公司如何报告其可持续发展努力。
这个想法是引入更严格的透明度要求,特别是在环境、社会和治理(ESG)指标方面。
https://towardsdatascience.com/what-is-esg-reporting-d610535eed9c
ESG 支柱展示 文章:[链接] — (图片来源:作者)
本文中介绍的我们在商业盈利能力方面的方法也可以应用于可持续性挑战。
决策者:“我们需要将分销网络的范围 3 排放量减少 30%。”
例如,在这篇关于绿色库存管理的文章中,我分享了一个关于减少商店配送碳排放的案例研究。
这个方法的目标是找到最优配送频率,以最小化 CO2 排放。
绿色库存管理文章:[链接] — (图片由作者提供)
文章中提出的解决这个操作问题的方法是类似的。
-
了解运营情况
为时尚零售商店准备并交付订单
-
使用 Python 构建一个仿真模型来估算排放量。
输入:销售数据和配送频率 / 输出:CO2 排放量
-
测试多个配送频率的不同情境,并计算排放量的减少。
如果你有兴趣寻找减少排放的解决方案,
模拟商店配送频率对时尚零售商 CO2 排放的影响。
towardsdatascience.com
针对不同问题的类似方法。
对于任何案例研究,保持好奇心、提出正确的问题并与决策者互动是至关重要的,这样才能真正理解他们的痛点。
通过这样做,你可以创建出能为技术和非技术受众提供可操作性洞察的模型。
根据我的经验,这些洞察可以显著提高盈利能力,并支持运营转型中的决策制定。
如果你还没有考虑将你的专业知识应用到商业挑战中,现在是时候了!
你可能会发现一种新的方式来创造影响——就像我做的一样。
关于我
让我们在Linkedin和Twitter上建立联系。我是一名使用数据分析来改善物流运营并降低成本的供应链工程师。
若需关于商业分析和可持续供应链转型的咨询或建议,欢迎通过Logigreen Consulting与我联系。
如果你对数据分析和供应链感兴趣,请访问我的网站。
这是一个专注于数据科学、个人生产力、自动化、运筹学和可持续发展的技术博客。
你确定要成为数据科学经理吗?
在你阅读完这些内容之前,不要急于追求这个华丽的职位。
https://medium.com/@joparga3?source=post_page---byline--89fb4f64baaa--------------------------------https://towardsdatascience.com/?source=post_page---byline--89fb4f64baaa-------------------------------- Jose Parreño
·发表于Towards Data Science ·阅读时间 15 分钟·2024 年 11 月 22 日
–
图片由Benjamin Elliott提供,来自Unsplash
想象一下。 你刚刚交付了一个绝妙的项目,团队气氛热烈,然后——砰!你被问到,‘你有没有考虑过领导这个团队?’ 听起来很诱人,对吧?但等等——你真的知道自己在做什么吗?
作为一名数据科学经理,我亲眼见证了我的团队从 0 人增长到 12 名数据科学家,并帮助我们将数据科学领域的规模从 20 人扩大到 50 人以上。我还看到一些同事经理们离开,寻求新的挑战。这两种情况都产生了一个空缺:需要一位经理来领导数据科学团队。填补这个空缺可能是一个绝佳的机会,但我也看到许多同事未能适应这一转变。
向管理层的过渡可不是小事。的确,它有其好处。但没有人谈论其中的取舍。大多数初任经理完全没有准备——这就是挫败感开始的地方。
你在这篇博客中将能阅读到什么?
我将介绍在你转向管理岗位之前需要考虑的主要因素。
你将阅读到以下内容:
- 进行高层次的自我反思。 你为什么会考虑做出这个决定?
ARIMA:一种预测时间序列数据的模型
学习 ARIMA 模型如何工作,并学习如何在 Python 中实现它们以进行准确预测
https://medium.com/@niklas_lang?source=post_page---byline--a34c7638310b--------------------------------https://towardsdatascience.com/?source=post_page---byline--a34c7638310b-------------------------------- Niklas Lang
·发表于Towards Data Science ·14 分钟阅读·2024 年 10 月 30 日
–
图片由Jean-Luc Picard提供,来源:Unsplash
缩写 ARIMA 代表自回归积分滑动平均,是一类用于分析时间序列数据的统计模型。这个模型可以用来预测数据未来的发展趋势,例如在科学或技术领域。ARIMA 方法主要用于存在所谓的时间自相关的情况,也就是说,简单来说,时间序列表现出某种趋势。
在本文中,我们将解释与 ARIMA 模型相关的所有方面,从时间序列数据及其特殊特征的简单介绍开始,直到在文章末尾训练我们自己的模型并进行详细评估。
什么是时间序列数据?
时间序列数据是一种特殊形式的数据集,其中测量是按规律的时间间隔进行的。这使得这样的数据集合具有其他数据集所缺少的一个额外维度,即时间维度。时间序列数据通常用于金融和经济领域,或者在自然科学中,当需要测量一个系统随时间变化时。
数组 — 数据科学家的数据结构与算法
动态数组和静态数组在后台是如何工作的
https://medium.com/@egorhowell?source=post_page---byline--b2e39e25136d--------------------------------https://towardsdatascience.com/?source=post_page---byline--b2e39e25136d-------------------------------- Egor Howell
·发表于 Towards Data Science ·阅读时长 6 分钟·2024 年 10 月 7 日
–
图片由 Caspar Camille Rubin 提供,来源于 Unsplash
作为数据科学家,我们很少会被问到类似 LeetCode 的问题,因此我们学习数据结构和算法的需求不如软件工程师那样迫切。
然而,能够编写高效的代码对于你的数据科学职业生涯是一个巨大的助推器。试想,如果你能成为一名既懂得实现机器学习模型,又理解写代码的最佳实践,同时对软件工程有一定了解并拥有相关知识的“数据科学家”会怎样?
你突然变得非常有价值,几乎成了市场上的独角兽。这就是为什么我开始学习数据结构与算法课程,并计划分享我所学到的内容。
本文将专门讨论数组、它们是如何在后台工作的以及它们的不同类型。
数据结构
数据结构是计算机内存储信息的一种便捷方式。正如 维基百科 所定义的:
数据结构是一种数据组织和存储格式,通常选择它是为了高效访问数据。更准确地说,数据结构是一种…
Python 和 Excel VBA 中的数组
通过简单的例子学习数组
https://medium.com/@himalaya.birshrestha?source=post_page---byline--efd73b649d6d--------------------------------https://towardsdatascience.com/?source=post_page---byline--efd73b649d6d-------------------------------- Himalaya Bir Shrestha
·发表于 Towards Data Science ·阅读时间 8 分钟·2024 年 1 月 23 日
–
作为一个没有接受过正式编程教育的人,我的编程旅程一直由自学塑造。意识到回顾基础编程概念的重要性,我发现扎实的基础能够提升整体编程体验。在本教程中,我们将深入探讨一个基本概念——数组。具体来说,我们将通过简单的例子,探讨 Python 和 Excel VBA 中的数组概念。让我们开始吧。
图片由 Nathan Dumlao 提供,来源于 Unsplash
1. Python 中的数组
数组是一个特殊的变量,可以保存一个或多个任何数据类型的值。在 Python 中,与类似的数据类型(如列表)不同,没有内置的数组支持。然而,可以使用 numpy 包的 array 模块来创建数组。numpy 数组对象的索引总是从 0 开始。可以通过引用 -1 来访问 numpy 数组中的最后一个项。一个 numpy 数组可以包含某一特定数据类型的变量或多种数据类型。
下面的代码片段展示了这一点。代码片段还展示了如何从 numpy 数组中访问形状(维度,即行、列)、大小(元素个数)和长度(容器中的项目数量,即行数)。
import numpy as np
simple_array = np.array([1, 2, 3])
mixed_array = np.array([1, 2, 3, "a", "b", "c", 4.5])
print ("Simple array: ", simple_array)
print ("First element of simple_array: ", simple_array[0])
print ("Shape of simple_array: ", simple_array.shape)
print ("Size of simple_array; ", simple_array.size)
print ("\n")
print ("Mixed array: ", mixed_array)
print ("Last element of mixed_array: ", mixed_array[-1])
print ("Length of mixed_array: ", len(mixed_array))
1.1 使用 numpy 数组进行代数矩阵运算
由于其灵活的结构,numpy 数组在创建不同维度的矩阵对象并对其进行操作时非常方便。上面的截图展示了 1 维数组对象的例子。
在下面,我创建了两个数组对象 a
和 b
,它们都是二维数组,可以看作是 2*2 的矩阵。计算这两个矩阵的点积就像执行 np.dot(a, b)
一样简单。在点积中,a
和 b
被视为向量(既有大小又有方向的对象)。在矩阵乘法中,矩阵 a
中的每个元素与矩阵 b
中对应的元素相乘。例如,a11(第一行第一列的元素)与 b11 相乘,以此类推。
a = np.array([[0, 1],[2,3]])
b = np.array([[3,4],[5,6]])
print ("Dot Product of a and b: \n", np.dot(a,b))
print ("Matrix multiplication of a and b \n",a*b)
此外,还可以执行其他矩阵操作,如加法、减法和转置。要获得矩阵的行列式,可以使用 np.linalg.det(a)
。要获得矩阵的乘法逆,可以使用 np.linalg.inv(a)
。
print (“Addition of a and b:\n”, np.add(a, b))
print ("Also addition of a and b:\n", a+b)
print ("Transpose of a:\n", a.T)
print ("Determinant of a:\n", np.linalg.det(a))
print ("Inverse of a:\n", np.linalg.inv(a))
1.2 从列表对象创建 m*n 形状的 numpy 数组
我有两个列表,分别叫做 countries_lived
和 capitals
,它们包含我曾居住过的国家及其对应的首都。
countries_lived = [“Nepal”,”India”,”Germany”,”Netherlands”]
capitals = [“Kathmandu”,”New Delhi”,”Berlin”,”Amsterdam”]
要创建一个包含这些列表对象的数组,我可以使用 np.array([countries_lived, capitals])
。这将返回一个形状为 2*4(即 2 行 4 列)的数组。如果我希望每一行包含一个国家及其对应的首都,我只需转置该数组即可。
array1 = np.array([countries_lived, capitals])
print ("array1:\n", array1)
print ("Shape of array1:\n", array1.shape)
print ("Size of array1:\n", array1.size)
array2 = np.array([countries_lived, capitals]).T
print ("array2:\n", array2)
print ("Shape of array2:\n", array2.shape)
print ("Size of array2:\n", array2.size)
1.3 向 numpy 数组追加一个元素并创建一个 dataframe
比如说,我想将 France 和 Paris 作为新的一行追加到 array2
中,可以使用语法 np.append(arr, values, axis = None)
来实现。values 必须与 arr
具有相同的形状,轴(axis)除外。如果未指定轴,arr 和 values 会在使用之前被展平。
如下所示,我将新元素作为新的一行追加到数组中。最后,形状为 (5,2) 的 array2
被用来创建一个包含 Country 和 Capital 列的数据框对象 df
。
array2 = np.append(array2, [[“France”,”Paris”]], axis = 0)
print ("array2 after appening new row: \n", array2)
import pandas as pd
df = pd.DataFrame(array2,
columns = ["Country", "Capital"])
df
2. Excel VBA 中的数组
与 Python 类似,Excel VBA 中的数组也是一组变量。数组的下界可以从 0 或 1 开始,Excel VBA 的默认下界是 0。但是,可以通过在每个模块顶部声明 Option Base 0
或 Option Base 1
来指定数组的下界。
要检测数组的下界和上界,可以分别使用 Lbound(array_name)
和 Ubound(array_name)
。
2.1 声明数组
数组可以通过使用 Public
关键字声明为公共(即全局)数组。在 Excel VBA 中将数组或任何其他变量声明为公共变量,允许在任何模块或子程序中使用,无需重新声明。
Public countries(1 to 4) as String
Public capitals(4) as String
Public countries_visited() as String
另外,数组也可以在子程序内局部声明,只需使用 Dim
关键字即可。这样声明的数组只能在特定的子程序内部使用。
Dim countries(1 to 4) as String
Dim capitals(4) as String
在上述示例中,数组的大小也被指定。指定 1 到 4 或仅指定 4 都表示数组的大小为 4。
2.2 一维数组
一维数组是通过声明行数(例如,从 1 到 5),即数组包含的元素数量来赋值的。下面给出了一个创建我曾经居住过的四个国家的一维数组的示例。它将把这些国家的名称打印到 Excel 文件工作表的 A 列中。
Option Base 1
Sub array_1d()
countries(1) = "Nepal"
countries(2) = "India"
countries(3) = "Germany"
countries(4) = "Netherlands"
Dim i As Integer
Range("A1").Value = "Country"
For i = 1 To 4
Range("A" & i + 1).Value = countries(i)
Next i
End Sub
运行array_1d
子程序的输出如下:
array_1d 子程序的输出。图片来源:作者。
2.2 二维数组
二维数组通过声明行数和列数来定义。在以下示例中,我声明了一个名为country_capital
的二维数组。每一行的第一个元素对应上一节中声明的countries
数组中的元素。每一行的第二个元素对应于这些国家的首都,它们已经在下面的代码中单独声明。
Sub array_2d()
Dim country_capital(4, 2) As String
For i = 1 To 4
country_capital(i, 1) = countries(i)
Next i
country_capital(1, 2) = "Kathmandu"
country_capital(2, 2) = "New Delhi"
country_capital(3, 2) = "Berlin"
country_capital(4, 2) = "Amsterdam"
Range("B1").Value = "Capital"
For i = 1 To 4
Range("A" & i + 1).Value = country_capital(i, 1)
Range("B" & i + 1).Value = country_capital(i, 2)
Next i
End Sub
运行此子程序返回以下结果:
array_2d 子程序的输出。图片来源:作者。
2.3 动态数组
动态数组在无法确定数组大小并且数组大小可能在未来发生变化的情况下非常有用。在下面的代码中,我声明了两个数组countries_visited
和population
,但没有指定数组的大小。在dynamic_array
子程序内,我通过使用ReDim
语句将这两个数组的大小指定为 4。接下来,我根据我访问过的四个国家及其人口分别指定了数组的每个元素。
Option Base 1
Public countries_visited() As String
Public population() As Long
Sub dynamic_array()
Dim wb As Workbook
Dim ws2 As Worksheet
Set wb = ThisWorkbook
Set ws2 = wb.Worksheets("Sheet2")
ReDim countries_visisted(4)
ReDim population(4)
countries_visited(1) = "France"
population(1) = 68
countries_visited(2) = "Spain"
population(2) = 48
countries_visited(3) = "Iran"
population(3) = 88
countries_visited(4) = "Indonesia"
population(4) = 274
End Sub
一段时间后,我意识到我还访问了一个新国家(葡萄牙)。我在保留这些数组原始内容/元素的情况下重新定义了数组的大小。我通过增加数组的大小 1 来进行操作。为此,我使用了ReDim Preserve
语句,如下所示。
ReDim Preserve countries_visited(1 to 5)
ReDim Preserve population(1 to 5)
完整代码如下:
Option Base 1
Public countries_visited() As String
Public population() As Long
Sub dynamic_array()
Dim wb As Workbook
Dim ws2 As Worksheet
Set wb = ThisWorkbook
Set ws2 = wb.Worksheets("Sheet2")
ReDim countries_visisted(4)
ReDim population(4)
countries_visited(1) = "France"
population(1) = 68
countries_visited(2) = "Spain"
population(2) = 48
countries_visited(3) = "Iran"
population(3) = 88
countries_visited(4) = "Indonesia"
population(4) = 274
ws2.Range("A1").Value = "Countries visited"
ws2.Range("B1").Value = "Population (million)"
ReDim Preserve countries_visited(5)
ReDim Preserve population(5)
countries_visited(5) = "Portugal"
population(5) = 10
Dim i As Integer
For i = 2 To 6
Range("A" & i).Value = countries_visited(i - 1)
Range("B" & i).Value = population(i - 1)
Next i
End Sub
上述代码的输出如下所示:
动态数组子程序的输出。图片来源:作者。
2.4 声明数组以存储不同数据类型的变量
在上面的章节中,countries_visited
数组声明用于存储String数据类型的变量,population
数组声明用于存储Long数据类型的变量。与 Python 的 numpy 数组类似,在 Excel VBA 中也可以在数组中存储不同数据类型的变量。在这种情况下,数组必须声明为Variant
类型。
在下面的示例中,声明了一个名为test
的数组作为Variant。其大小通过ReDim
语句指定为 3。test
中的三个元素分别为String、Integer和Date类型。通过将变量传递给TypeName()
函数,可以识别这些数据类型。
Option Base 0
Sub variant_test()
Dim test() As Variant
ReDim test(3)
test = Array("Germany population in million: ", 83, Date)
Dim i As Integer
For i = 0 To 2
Debug.Print "Element " & i & " of test array is: " & test(i) & " of type " & TypeName(test(i))
Next i
End Sub
输出如下所示:
variant_test 子程序的输出。图片由作者提供。
结论
数组是由一个或多个数据类型的值/变量组成的集合。每个变量都与数组中的特定索引号相关联。数组可以是单维的、二维的或多维的。在 Python 中,没有内建的数组支持,但可以使用 numpy 包创建数组。除了存储值,numpy 数组在进行矩阵运算时也非常有用。在 Excel VBA 中,数组在处理大型数据元素数据库时非常有用。在 Excel VBA 中,数组可以是静态的,即数组的大小是预定义的。或者,数组也可以是动态的,即数组的大小不是预定义的,但我们可以在使用过程中指定其大小,甚至在保持已存储元素的情况下调整数组大小。
这个 GitHub 仓库提供了 Python 笔记本、Excel 工作簿以及 VBA 脚本。感谢阅读!
艺术守护:保护你的在线图像免受生成式 AI 的侵害
你可以采取的步骤,以防止机器人爬取并使用你的艺术作品训练 AI 模型,如 Stable Diffusion、Midjourney 和 DALL-E
https://robgon.medium.com/?source=post_page---byline--ef09b8aa1a5a--------------------------------https://towardsdatascience.com/?source=post_page---byline--ef09b8aa1a5a-------------------------------- 罗伯特·A·冈萨尔维斯
·发布于 Towards Data Science ·18 分钟阅读·2024 年 8 月 23 日
–
艺术守护,DALL-E 3 生成的 AI 图像,作者编辑
很多艺术家都对生成式 AI 感到担忧。他们担心网络爬虫未经许可和/或补偿,爬取他们网页上的图像用于训练 AI 模型。
我花了过去四周的时间研究这个话题,并找到了很多关于这些模型如何工作以及如何防止机器人窃取你作品的信息。
TL;DR — 你可以做的最简单的事情是通过你的托管服务的设置关闭 AI 爬虫访问你的网站,比如 SquareSpace 和 其他服务。更多关于这个和其他你可以采取的步骤的信息在下面。
在这篇文章中,我将提供一些关于文本生成图像的 AI 模型如何工作的背景知识,包括 Stable Diffusion、Midjourney 和 DALL-E 3。接下来,我将向你展示如何检测这些模型是否使用了你的图像进行训练。最后,我将提供一些建议和步骤,帮助你防止机器人窃取你的作品。
ASA 的警示:重新思考我们在研究中如何使用 p 值
理解 ASA 的声明,提升你的数据科学实践
https://medium.com/@shreef.nasser?source=post_page---byline--17c10c073d23--------------------------------https://towardsdatascience.com/?source=post_page---byline--17c10c073d23-------------------------------- Sheref Nasereldin 博士
·发表于 Towards Data Science ·8 分钟阅读·2024 年 6 月 11 日
–
图片由 Jason Dent 提供,来源于 Unsplash
引言:
在数据科学领域,计算 p 值是一项非常常见的任务,是假设检验的核心。无论你是在分析 A/B 测试结果、进行医学研究,还是评估市场趋势,p 值都是解读数据的重要指标。然而,误解这一指标可能导致错误的结论。近七年前,**美国统计协会(ASA)**发布了关于最佳实践和常见误用的声明,提醒人们在解读 p 值时应避免的错误做法。尽管如此,自那时以来,这一指标的误用并未显著减少。
假设检验:
为了希望能够全面理解这一声明,我将首先列出成功进行假设检验所需的步骤:
-
写下零假设(H0)和备择假设(H1)。
-
为了保证结果的严谨性,决定显著性水平(𝛂)——这是犯第一类错误的概率,即当零假设 H0 为真时却错误地拒绝它。显著性水平通常设定为𝛂 = 0.05,但这仅仅是一个…
ASCVIT V1:自动化统计计算、可视化和解释工具
轻松实现自动化数据分析:ASCVIT 工具的第一个版本,提供统计计算、可视化和解释功能
https://medium.com/@stefanpietrusky?source=post_page---byline--aa910001a3a7--------------------------------https://towardsdatascience.com/?source=post_page---byline--aa910001a3a7-------------------------------- Stefan Pietrusky
·发表于Towards Data Science ·阅读时间 30 分钟·2024 年 9 月 16 日
–
在我的学习过程中,我参加了一个数据科学研讨会,并首次接触到了统计编程语言 R。当时,我对其可能带来的应用潜力感到着迷。与此同时,得益于机器学习领域的进展,数据的统计评估变得更加简便。当然,这需要一定的技术理解,并且你需要知道某些方法的实际作用。还需要了解哪些数据或输入是某些方法能够正常工作或得出有意义结果的前提。在本文中,我将讨论开发本地应用的第一个版本(V1)的过程,该应用可以用于自动地将各种统计方法应用于任何数据集。这是一个开源项目,旨在用于教育和研究目的。
数据可以以.csv 或.xlsx 格式上传。应用的第一版本提供了一个通用的数据概览(数据预览、数据描述、数据点数量和变量分类)、描述性统计分析(直方图、箱型图、散点图矩阵和相关矩阵)、各种假设检验(t 检验、方差分析和卡方检验)、回归分析(线性回归、逻辑回归和多元回归)、时间序列分析,并支持各种聚类方法(k 均值、层次聚类和 DBSCAN)。该应用是使用 Python 框架 Streamlit 创建的。
ASCVIT V1 分析方法概览(图片来自作者)
由于代码的模块化结构,可以轻松实现进一步的统计程序。代码中有注释,这使得你更容易上手。当应用程序运行时,上传数据集后界面如下所示。
ASCVIT V1 Streamlit 应用程序(图片来自作者)
除了在前述各个领域的自动分析外,还集成了一个功能,能够自动分析统计记录的数值。“query_llm_via_cli” 功能使得通过 CLI(命令行界面)与 LLM 进行交流成为可能,使用的是 Ollama。
我已经在我发布的Towards Data Science [1] 文章中解释了这一原理。在应用程序的第一个版本中,此功能仅限于描述性统计分析,但也可以扩展到其他分析上。具体来说,这意味着除了自动统计计算外,应用程序还会自动解读数据。
ASCVIT V1 CLI + OLLAMA + LMS(图片来自作者)
测试应用程序的数据集
如果你没有自己的数据,可以访问互联网上的多个网站,这些网站提供免费的数据集。用于开发和测试此应用程序的数据集来自Maven Analytics(许可证:ODC-BY) [2]。
MAVEN Analytics 数据游乐场(截图来自作者)
网站上有大量免费的数据集。我所查看的数据涉及从 1976 年到 2024 年间的视频游戏销售数据。具体来说,它记录了北美、日本、欧盟、非洲和其他地区的销售数据。总共有 64016 个游戏标题以及它们的评分、类型、平台等信息。
不幸的是,并非所有标题都有完整的信息。有很多 NaN(非数字)值,这在用 Python 分析时会导致问题或扭曲某些统计分析结果。下面我将简要讨论数据记录的清理过程。
MAVEN Analytics 的视频游戏销售数据(截图来自作者)
清理数据集
你可以在将数据集加载到应用程序之前,通过使用单独的脚本清理数据集,或者直接在应用程序中进行清理。在本文的应用程序中,我已在应用程序中直接实现了数据清理。如果你希望提前清理数据记录,可以使用以下脚本进行操作。
import pandas as pd
df = pd.read_csv('YOUR .CSV FILE')
df_cleaned = df.dropna()
df_cleaned.to_csv('cleaned_file.csv', index=False)
print("Lines with missing data have been removed and saved in 'cleaned_file.csv'.")
使用*“pd.read_csv(‘.csv’)”读取文件,并将数据保存到 DataFrame“df”中。“df.dropna()”删除 DataFrame 中包含缺失值‘NaN’的所有行。清洗后的 DataFrame 保存在变量“df_cleaned”中。使用“df_cleaned.to_csv(‘cleaned_file.csv’, index=False)”将数据保存到新的.csv 文件中,且不保存行索引。接下来,输出成功完成的过程“print(…)”。该数据集清洗的代码可以在文件“clean.py”*中找到,并且稍后也可以下载。接下来,让我们进入应用程序的实际代码部分。
ASCVIT V1 Python 代码片段(作者制作的 GIF)
所需的库和模块
使用此应用程序需要各种库和模块,这些库和模块结合在一起执行数据可视化、统计分析和机器学习任务。
import re
import subprocess
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import seaborn as sns
from matplotlib.patches import Patch
from scipy import stats
from sklearn.cluster import KMeans, AgglomerativeClustering, DBSCAN
from sklearn.decomposition import PCA
from sklearn.linear_model import LinearRegression, LogisticRegression
from statsmodels.stats.multicomp import pairwise_tukeyhsd
import streamlit as st
关于图表表示的说明。 有些使用*“pyplot”(Matplotlib),而有些使用“plotly”(例如箱形图)。尽管使用“plotly”*会产生更互动的图形,但并不意味着每种图表类型都需要使用它。最终,用户必须自行决定图表应如何显示。代码必须相应地进行调整。
可以通过 ZIP 目录中的 requirements.txt 文件使用以下命令安装应用程序所需的库。
pip install -r requirements.txt
数据概览
函数*“display_data_info()”专门分析 Pandas DataFrame “df”并输出统计关键数据(均值、标准差等)“df.describe()”。DataFrame 的总数据点(行数)通过“len(df)”输出。同样,DataFrame 的数值型变量“numerical_columns”和分类变量“categorical_columns”*(字符串类型)也会被输出。
ASCVIT V1 应用数据概览(作者制作的图片)
数据集总共有 64016 个数据点,其中 6 个数值型变量和 8 个分类变量。在开始进行某些统计处理之前,首先应该查看数据。在*“数据概览”*部分,您可以获取各种信息,以得出是否可以进行某些测试的结论。
例如,如果数据集中没有日期变量,则无法进行时间序列分析。如果没有二元变量,则无法进行逻辑回归。该应用程序已经设计为在变量类别不正确时询问或显示错误信息。接下来,让我们继续描述性统计部分。
def display_data_info(df):
st.write("**Data description:**")
st.write(df.describe())
st.write(f"**Number of data points:** {len(df)}")
numerical_columns = df.select_dtypes(include=np.number).columns.tolist()
categorical_columns = df.select_dtypes(include='object').columns.tolist()
st.write("**Numerical variables:** ", ", ".join(numerical_columns))
st.write("**Categorical variables:** ", ", ".join(categorical_columns))
return numerical_columns, categorical_columns
描述性统计
“descriptive_statistics()”函数允许用户选择不同的图表类型(直方图、箱型图、对角线图和相关矩阵)。通过“st.markdown(”“”…“”“)”可以对这些类型进行简要解释。然后需要选择一个或多个数值变量“selected_vars”。除了相关矩阵外,还可以选择是否应用对数缩放“apply_log_scale”。如果数据严重扭曲,应用对数缩放对变量尤其有用。使用相应的图表函数来创建可视化。
def descriptive_statistics(df, numerical_columns):
chart_type = st.selectbox("Select the diagram:", ["Histogram", "Boxplot", "Pairplot", "Correlation matrix"])
if chart_type == "Histogram":
st.markdown("""
**Histogram:**
A histogram shows the distribution of a numerical variable. It helps to
recognize how frequently certain values occur in the data and whether there are patterns, such as a normal distribution.
""")
elif chart_type == "Boxplot":
st.markdown("""
**Boxplot:**
A boxplot shows the distribution of a numerical variable through its quartiles.
It helps to identify outliers and visualize the dispersion of the data.
""")
elif chart_type == "Pairplot":
st.markdown("""
**Pairplot:**
A pairplot shows the relationships between different numerical variables through scatterplots.
It helps to identify possible relationships between variables.
""")
elif chart_type == "Correlation matrix":
st.markdown("""
*Correlation matrix:**
The correlation matrix shows the linear relationships between numerical variables.
A positive correlation indicates that high values in one variable also correlate with high values in another.
""")
if chart_type in ["Pairplot", "Correlation matrix"]:
selected_vars = st.multiselect("Select variables:", numerical_columns, default=numerical_columns)
else:
selected_vars = [st.selectbox("Select a variable:", numerical_columns)]
if chart_type != "Correlation matrix":
apply_log_scale = st.checkbox("Apply logarithmic scaling?", value=False)
else:
apply_log_scale = False
if st.button("Create diagram"):
if chart_type == "Histogram":
plot_histogram(df, selected_vars[0], apply_log_scale)
elif chart_type == "Boxplot":
plot_boxplot(df, selected_vars[0], apply_log_scale)
elif chart_type == "Pairplot":
plot_pairplot(df, selected_vars)
elif chart_type == "Correlation matrix":
plot_correlation_matrix(df, selected_vars)
直方图函数
“plot_histogram()”函数用于根据用户选择的变量创建直方图。开始时,所有 NaN 值都会从变量“cleaned_data”中去除。然后计算各种统计关键数字(均值“mean_value”、中位数*“median_value”、标准差“std_value”、最小值“min_value”、最大值“max_value”*以及标准差的上下限)。
由于数据是由 LLM(大语言模型)进行解读的,正如前面提到的,数据的离散度(与数据范围相关的标准差)和分布(均值与中位数的差异)被分类。直方图是通过*“fix, ax = plt.subplots()”创建的,随后添加垂直线以增加信息量,最后通过“st.pyplot(fig)”*显示直方图。如果数据是扭曲的或呈指数分布,可以激活对数缩放,进而调整直方图的 y 轴。此时,图表看起来如下所示[3]。
ASCVIT V1 直方图(pyplot)与 LLM 解释(作者提供的图片)
由于目前没有可以直接读取图形的模型,我们为 LLM 创建了一个通用的分析上下文。该上下文包含统计计算结果及附加说明或所需的解释。这意味着,作为 LLM 输入的上下文,可以应用于任何数据集。
具体而言,输入包括上述统计关键数字、分布的分析(对称、右偏或左偏)、扩展范围的估计(低、中或高)以及为 LLM 格式化的解释。根据所需的输出,可以单独调整和进一步指定上下文。
LLM 上下文示例(作者提供的图片)
分析结果通过*“response = query_llm_via_cli(context)”发送到 LLM,之后在短时间间隔内,根据本地系统的性能,进行直方图的解释“st.write(f”Histogram Interpretation: {response}”)”*。
def plot_histogram(df, variable, apply_log_scale):
cleaned_data = df[variable].dropna()
mean_value = cleaned_data.mean()
median_value = cleaned_data.median()
std_value = cleaned_data.std()
min_value = cleaned_data.min()
max_value = cleaned_data.max()
std_upper = mean_value + std_value
std_lower = max(0, mean_value - std_value)
concentration_range = (mean_value - std_value, mean_value + std_value)
if std_value < (max_value - min_value) / 6:
scatter = "low"
elif std_value < (max_value - min_value) / 3:
scatter = "moderate"
else:
scatter = "high"
if abs(mean_value - median_value) < 0.1 * std_value:
distribution = "symmetrical"
elif mean_value > median_value:
distribution = "right-skewed"
else:
distribution = "left-skewed"
fig, ax = plt.subplots()
ax.hist(cleaned_data, bins=30, edgecolor='black', alpha=0.7)
ax.axvline(mean_value, color='red', linestyle='--', label=f'Mean: {mean_value:.2f}')
ax.axvline(median_value, color='green', linestyle='-', label=f'Median: {median_value:.2f}')
ax.axvline(std_upper, color='blue', linestyle=':', label=f'+1 Std: {std_upper:.2f}')
ax.axvline(std_lower, color='blue', linestyle=':', label=f'-1 Std: {std_lower:.2f}')
ax.set_title(f"Histogram of {variable}")
ax.legend(title=f'Std-Deviation: {std_value:.2f}')
if apply_log_scale:
ax.set_yscale('log')
st.pyplot(fig)
context = (
f"Here is an analysis of the distribution of the variable '{variable}':\n"
f"- Mean: {mean_value:.2f}\n"
f"- Median: {median_value:.2f}\n"
f"- Standard deviation: {std_value:.2f}\n"
f"- Minimum: {min_value:.2f}\n"
f"- Maximum: {max_value:.2f}\n\n"
f"The distribution of the data shows a {distribution} distribution.\n"
f"The small difference between mean and median indicates a {distribution} distribution.\n"
f"A strong concentration of data points is observed between {concentration_range[0]:.2f} and {concentration_range[1]:.2f}.\n"
f"The scatter of the data is described as {scatter}, indicating a relatively tight distribution around the mean.\n\n"
f"Please analyze this distribution in the histogram, paying particular attention to symmetry, scatter, and potential deviations.\n"
f"Avoid calling the distribution normal unless there are explicit indications.\n"
f"Use only the names of the variables {variable} in the analysis!"
)
response = query_llm_via_cli(context)
st.write(f"**Histogram Interpretation:** {response}")
箱型图函数
“plot_boxplot()” 函数为用户选择的变量创建箱线图。基于变量,从 DataFrame 中计算统计关键数字,以便在图表中显示数据分布,并使用 LLM 进行集中趋势和离散度分析。除了均值、中位数和标准差之外,与直方图一样,还计算了下四分位数 “q1”、上四分位数 “q3”、四分位距 “iqr”(Q3 — Q1)以及基于四分位距(1.5 * IQR)的下须“lower_whisker”和 “upper_whisker”,这些数据也会用于箱线图。
后者有助于识别异常值以及其他超出某个值的数据参数。箱线图是通过 Plotly 库 “fig = px.box(df, y=variable)” 创建的,最后在应用程序中显示 “st.plotly_chart(fig)”。此图类型也可以使用对数尺度 [4]。图表的样式如下所示:
ASCVIT V1 箱线图(plotly),显示 critic_score 和 LLM 解读(作者提供的图片)
与直方图类似,也为箱线图创建了一个上下文,并将其传递给 LLM。统计关键数字以及有关潜在异常值的信息(即那些超出须值的数据)都会被传输。发送给 LLM 的文本已格式化,以便在这些指标上执行分析。
def plot_boxplot(df, variable, apply_log_scale):
mean_value = df[variable].mean()
median_value = df[variable].median()
std_value = df[variable].std()
q1 = df[variable].quantile(0.25)
q3 = df[variable].quantile(0.75)
iqr = q3 - q1
lower_whisker = max(df[variable].min(), q1 - 1.5 * iqr)
upper_whisker = min(df[variable].max(), q3 + 1.5 * iqr)
fig = px.box(df, y=variable)
fig.update_layout(title=f"Boxplot of {variable}")
if apply_log_scale:
fig.update_yaxes(type="log")
st.plotly_chart(fig)
context = (
f"Here is an analysis of the distribution of the variable '{variable}' based on a boxplot:\n"
f"- Mean: {mean_value:.2f}\n"
f"- Median: {median_value:.2f}\n"
f"- Standard deviation: {std_value:.2f}\n"
f"- Lower quartile (Q1): {q1:.2f}\n"
f"- Upper quartile (Q3): {q3:.2f}\n"
f"- Interquartile range (IQR): {iqr:.2f}\n"
f"- Potential outliers outside values from {lower_whisker:.2f} to {upper_whisker:.2f}.\n"
f"Please analyze this distribution and identify patterns or outliers.\n"
f"Use only the names of the variables {variable} in the analysis!"
)
response = query_llm_via_cli(context)
st.write(f"**Boxplot Interpretation:** {response}")
PAIRPLOT 函数
“plot_pairplot()” 函数根据用户选择的变量创建配对图。如果选择的变量少于两个,则会显示错误信息。会显示所有可能的变量组合的散点图,并绘制线性回归线,以显示变量之间的关系。为了使其生效,使用 “calculate_regression_stats” 函数计算所有可能的变量对的回归统计数据。所选变量 “selected_vars” 中的 NaN 值会被移除。
在这两个变量之间执行线性回归。这里,“var1” 是自变量 x,“var2” 是因变量 y。计算斜率和 R2 值 “r_squared”。结果以元组列表(var1, var2, slope, r_squared)的形式返回。如果选择了三个变量 [“A”, “B”, “C”],则函数会计算对(A, B)、(A, C)、(B, A)、(B, C)等的回归统计 [5]。
def calculate_regression_stats(df, selected_vars):
regression_results = []
for var1 in selected_vars:
for var2 in selected_vars:
if var1 != var2:
non_nan_data = df[[var1, var2]].dropna()
X = non_nan_data[[var1]].values.reshape(-1, 1)
y = non_nan_data[var2].values
if len(X) > 0 and len(y) > 0:
model = LinearRegression()
model.fit(X, y)
r_squared = model.score(X, y)
slope = model.coef_[0]
regression_results.append((var1, var2, slope, r_squared))
return regression_results
def plot_pairplot(df, selected_vars):
if len(selected_vars) > 1:
st.write("**Pairplot with regression lines:**")
pairplot_fig = sns.pairplot(df[selected_vars], kind='reg', diag_kind='kde',
plot_kws={'line_kws': {'color': 'red'}, 'scatter_kws': {'color': 'blue'}})
st.pyplot(pairplot_fig.fig)
corr_matrix = df[selected_vars].corr()
regression_stats = calculate_regression_stats(df, selected_vars)
correlation_list = "\n".join(
[f"The correlation between {var1} and {var2} is {corr_matrix.at[var1, var2]:.2f}."
for var1 in corr_matrix.columns for var2 in corr_matrix.columns if var1 != var2]
)
regression_list = "\n".join(
[f"The regression line for {var1} and {var2} has a slope of {slope:.2f} and an R² of {r_squared:.2f}."
for var1, var2, slope, r_squared in regression_stats]
)
context = (
f"Here are the correlation and regression analyses between the selected variables:\n"
f"{correlation_list}\n\n"
f"{regression_list}\n\n"
f"Please analyze these relationships in detail based solely on the numerical values (correlation and regression lines).\n"
f"Use only the names of the variables {selected_vars} in the analysis!"
)
response = query_llm_via_cli(context)
st.write(f"**Pairplot Interpretation:** {response}")
else:
st.error("At least two variables must be selected for a pairplot.")
“plot_pairplot()” 函数在对角线上使用 KDE(核密度估计)来显示每个单独变量的分布。与之前的函数一样,也为 LLM 创建了一个上下文进行分析。对于这种类型的图表,LLM 会接收来自相关性和回归分析的数据。文本已格式化,以便生成有关变量之间关系的详细解释。
ASCVIT V1 配对图(pyplot),展示 critic_score、na_sales、pal_sales 和 LLM 解释(作者提供的图像)
相关矩阵函数
“plot_correlation_matrix” 函数用于根据用户选择的变量创建相关矩阵 “if len(selected_vars) > 1”。如果只选择了一个变量,将显示错误消息。可视化以热图形式展示。矩阵单元格的颜色表示相关性的强度和方向。显著的相关性会自动发送到 LLM 进行进一步分析 “if var1 != var2 and abs(corr_matrix.at[var1, var2]) >= 0.5”。
选定变量之间的线性相关性以相关系数(值在 -1 和 +1 之间)“corr_matrix = df[selected_vars].cor()” 的形式展示。若值为 0,表示没有线性相关性。接近 -1 的值表示强烈的负相关,而接近 +1 的值表示强烈的正相关。变量对及其相关值会保存在 “high_correlations” [4] 中。
ASCVIT V1 相关矩阵(pyplot),包含所有变量及 LLM 解释(作者提供的图像)
为 LLM 创建了一个上下文。现有的显著相关性被分类为文本描述 “correlation_list”。若相关性较强(无论是正相关还是负相关),其值大于 0.7。如果值介于 0.5 和 0.7 之间,则表示中等相关性,而如果值仅略高于 0.5,则表示相关性较弱。如果未发现显著相关性,则会显示相应的消息。
def plot_correlation_matrix(df, selected_vars):
if len(selected_vars) > 1:
corr_matrix = df[selected_vars].corr()
fig, ax = plt.subplots()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', ax=ax)
ax.set_title("Correlation Matrix")
st.pyplot(fig)
high_correlations = []
for var1 in corr_matrix.columns:
for var2 in corr_matrix.columns:
if var1 != var2 and abs(corr_matrix.at[var1, var2]) >= 0.5:
if (var2, var1) not in [(v1, v2) for v1, v2, _ in high_correlations]:
high_correlations.append((var1, var2, corr_matrix.at[var1, var2]))
if high_correlations:
correlation_list = "\n".join([f"- {var1} and {var2} have a correlation value of {value:.2f}, "
f"indicating a {'strong' if abs(value) > 0.7 else 'moderate' if abs(value) > 0.5 else 'weak'} correlation."
for var1, var2, value in high_correlations])
context = (
f"Here is an analysis of the significant correlations between the selected variables in the correlation matrix:\n"
f"{correlation_list}\n\n"
f"Please analyze the correlations solely based on their strength and significance.\n"
f"Use only the names of the variables {selected_vars} in the analysis!"
f"Focus in detail on the statistical relationship and patterns."
)
response = query_llm_via_cli(context)
st.write(f"**Model Response:** {response}")
else:
st.write("**No significant correlations were found.**")
else:
st.write("**The correlation matrix cannot be displayed because fewer than two variables were selected.**")
在以下统计程序中,LLM 记录的各项关键数据的解释不可用。然而,基于先前的程序,独立实施应该不成问题。现在让我们转向各种假设检验。
假设检验选择
在当前版本中,可以进行三种不同的检验(t 检验、方差分析(ANOVA)和卡方检验) “test_type = st.selectbox()”。根据选择的检验类型,会出现简要的说明,解释其用途。根据应用领域,这些描述可以扩展或移除。t 检验用于比较两组的均值。方差分析(ANOVA)用于比较多于两组的均值。卡方检验用于检验两个分类变量之间的独立性。根据选择的检验,执行相应的函数。
T 检验
如果用户选择了 t 检验,他们必须选择一个组变量(类别型)“group_col” 和一个数值变量(数值型)“value_col”。组变量定义了要比较的两组,数值变量比较这两组的均值。一旦选择完成,必须在文本框 “st.text_input()” 中输入两组的名称 “group1” 和 “group2”。这两组应该出现在所选的类别变量中。这里也提供了对数标度 “apply_log_scale”,它应用于数值变量。当进行检验时,提取组的数据并输出数据点数量(移除 NaN 值后)。然后显示 t 统计量和 p 值。
第一个值表示两组之间均值差异与数据分布的相对关系。是否存在显著的组间差异由 p 值指示。如果 p 值小于 0.05,则说明差异显著。为了直观地突出显示两组的分布,“filtered_df = df[df[group_col].isin([group1, group2])]”,创建了一个箱形图 “fig, ax = plt.subplots()”。这里使用了*“pyplot”,你也可以选择使用“plotly”* [6]。
ASCVIT V1 箱形图,按类型(动作/射击)和评论分数分类(图像来源:作者)
在此示例中,“genre” 被选为组变量,“critic_score” 被选为数值变量。动作(组 1)和射击(组 2)被定义为比较组。该函数还计算组内是否存在显著的离群值。离群值被定义为超出上四分位数 1.5 倍四分位距的数据点 “outliers_group1/2”。最后,找到的离群值会被显示出来,以确认 t 检验的有效性。如果偏差过大,必须相应考虑,以便更好地分类检验结果的可靠性和可解释性。
def t_test(df, numerical_columns, categorical_columns):
group_col = st.selectbox("Choose the group variable:", categorical_columns)
value_col = st.selectbox("Choose the value variable:", numerical_columns)
group1 = st.text_input("Name of group 1:")
group2 = st.text_input("Name of group 2:")
apply_log_scale = st.checkbox("Apply logarithmic scaling?", value=False)
if st.button("Perform t-Test"):
group1_data = df[df[group_col] == group1][value_col]
group2_data = df[df[group_col] == group2][value_col]
initial_count_group1 = len(group1_data)
initial_count_group2 = len(group2_data)
group1_data = group1_data.dropna()
group2_data = group2_data.dropna()
remaining_count_group1 = len(group1_data)
remaining_count_group2 = len(group2_data)
st.write(f"**Group 1 ({group1}):** Total number of data points: {initial_count_group1}, without NaN: {remaining_count_group1}")
st.write(f"**Group 2 ({group2}):** Total number of data points: {initial_count_group2}, without NaN: {remaining_count_group2}")
if apply_log_scale:
group1_data = np.log1p(group1_data)
group2_data = np.log1p(group2_data)
if not group1_data.empty and not group2_data.empty:
t_stat, p_value = stats.ttest_ind(group1_data, group2_data)
st.markdown(f"**t-Statistic:** {t_stat}")
st.markdown(f"**p-Value:** {p_value}")
filtered_df = df[df[group_col].isin([group1, group2])]
fig, ax = plt.subplots()
sns.boxplot(x=filtered_df[group_col], y=filtered_df[value_col], ax=ax, palette="Set2")
ax.set_title(f"Boxplot for {group1} vs. {group2}")
if apply_log_scale:
ax.set_yscale('log')
st.pyplot(fig)
outliers_group1 = group1_data[group1_data > group1_data.quantile(0.75) + 1.5 * (group1_data.quantile(0.75) - group1_data.quantile(0.25))]
outliers_group2 = group2_data[group2_data > group2_data.quantile(0.75) + 1.5 * (group2_data.quantile(0.75) - group2_data.quantile(0.25))]
st.write("**Outlier Analysis:**")
if not outliers_group1.empty:
st.write(f"In group 1 ({group1}) there are {len(outliers_group1)} outliers.")
else:
st.write(f"In group 1 ({group1}) there are no significant outliers.")
if not outliers_group2.empty:
st.write(f"In group 2 ({group2}) there are {len(outliers_group2)} outliers.")
else:
st.write(f"In group 2 ({group2}) there are no significant outliers.")
else:
st.error("One or both groups contain no data after removing NaN values.")
ANOVA 检验
“anova_test()” 函数集成了执行 ANOVA 检验的选项。该检验用于检查多个组的均值是否存在显著差异。数据首先被清洗 “df_clean”。如果 ANOVA 检验显著,还会进行 Tukey 的 HSD 检验(诚实显著差异)。首先,再次定义一个组变量和一个数值变量。如果某个组的数据点少于 2 个,它将被排除 “valid_groups = group_sizes[group_sizes >= 2].index”。
如果调整后剩余的组少于两个,则会显示错误信息,且不执行该测试。ANOVA 测试计算 F 值和 p 值。F 值衡量组间的变异性与组内变异性的比值。p 值则指示组间均值差异是否显著。如果 p 值小于 0.05,则至少有一个组存在显著差异。为了可视化结果,使用 “pyplot” 创建箱型图 [7]。
ASCVIT V1 箱型图与控制台和评分(图像来源:作者)
如果 ANOVA 测试结果显著,则进行 Tukey 测试,以具体检验各组之间的差异。因此,ANOVA 测试并不显示哪些组之间存在差异。会创建一个图表,显示各组之间的配对均值差异及其置信区间 “st.pyplot(tukey.plot_simultaneous())”。
ASCVIT V1 Tukey 测试结果(图像来源:作者)
在图表下方,结果以表格形式显示,“st.dataframe(tukey_results_df, height=400)”。该表包含两组数据、均值差异 “meandiff”、调整后的 p 值 “p-adj”、置信区间以及是否可以拒绝原假设 “reject”(True = 显著,False = 不显著)。以下是置信区间的简要示例:对于 3DS 和 GBA 控制台,区间位于 -0.9319 和 -0.0061 之间,因此完全低于零。均值差异是显著的。
关键数字可以用于通过 LLM 解读结果。还可以选择将数据作为 .csv 文件下载,以便进一步进行统计分析(例如回归分析)[7]。
def anova_test(df, numerical_columns, categorical_columns):
group_col = st.selectbox("Choose the group variable:", categorical_columns)
value_col = st.selectbox("Choose the value variable:", numerical_columns)
if st.button("Perform ANOVA"):
df_clean = df[[group_col, value_col]].dropna()
group_sizes = df_clean.groupby(group_col).size()
valid_groups = group_sizes[group_sizes >= 2].index
df_filtered = df_clean[df_clean[group_col].isin(valid_groups)]
if len(valid_groups) < 2:
st.error("After removing small groups, there are not enough groups left for the ANOVA test.")
else:
grouped_data = [group[value_col].values for name, group in df_filtered.groupby(group_col)]
try:
anova_result = stats.f_oneway(*grouped_data)
st.markdown(f"**F-Value:** {anova_result.statistic}")
st.markdown(f"**p-Value:** {anova_result.pvalue}")
fig, ax = plt.subplots(figsize=(10, 6))
sns.boxplot(x=group_col, y=value_col, data=df_filtered, ax=ax)
plt.xticks(rotation=90)
st.pyplot(fig)
if anova_result.pvalue < 0.05:
st.write("The ANOVA test is significant. Tukey's HSD test will be performed.")
try:
tukey = pairwise_tukeyhsd(endog=df_filtered[value_col], groups=df_filtered[group_col], alpha=0.05)
st.pyplot(tukey.plot_simultaneous())
tukey_results_df = pd.DataFrame(data=tukey.summary().data[1:], columns=tukey.summary().data[0])
st.write("Results of the Tukey HSD test:")
st.dataframe(tukey_results_df, height=400)
csv = tukey_results_df.to_csv(index=False)
st.download_button(label="Download Tukey HSD results as CSV", data=csv, file_name='tukey_hsd_results.csv', mime='text/csv')
except Exception as e:
st.error(f"An error occurred during Tukey's HSD test: {str(e)}")
except ValueError as e:
st.error(f"An error occurred: {str(e)}.")
卡方检验
“chi_square_test()” 函数检查两个分类变量之间是否存在统计学显著关系。由于只能使用分类变量,因此不需要激活对数缩放选项。具体来说,它检查类别中观测频率是否相互独立,或者是否存在相关性。用户选择两个现有的分类变量。NaN 值会被移除,并且每个变量仅选择前 10 个最频繁的类别,以保持分析的可管理性,“value_counts().nlargest(10).index”。
创建了一个交叉表 “contingency_table”,它使用热图显示两个选定变量中类别组合的频率。如果交叉表无效(数据过少或仅有一个类别),则不执行该测试 [8]。
ASCVIT V1 带有类型和控制台的热图(图像来源:作者)
测试计算各种值。卡方值*“chi2”确定观察频率与预期频率之间差异的程度。高值表明差异很大。与其他分析一样,p 值“p”显示差异是否显著。还指示了测试的自由度“dof”以及预期频率“expected”*。
def chi_square_test(df, categorical_columns):
cat_var1 = st.selectbox("Choose the first group variable:", categorical_columns)
cat_var2 = st.selectbox("Choose the second group variable:", categorical_columns)
if st.button("Perform Chi-square test"):
df_clean = df[[cat_var1, cat_var2]].dropna()
top_cat_var1 = df_clean[cat_var1].value_counts().nlargest(10).index
top_cat_var2 = df_clean[cat_var2].value_counts().nlargest(10).index
df_filtered = df_clean[df_clean[cat_var1].isin(top_cat_var1) & df_clean[cat_var2].isin(top_cat_var2)]
try:
contingency_table = pd.crosstab(df_filtered[cat_var1], df_filtered[cat_var2])
if contingency_table.empty or contingency_table.shape[0] < 2 or contingency_table.shape[1] < 2:
st.error("The contingency table is invalid. Check the variables.")
else:
chi2, p, dof, expected = stats.chi2_contingency(contingency_table)
st.markdown(f"**Chi-square:** {chi2}")
st.markdown(f"**p-Value:** {p}")
st.write("**Heatmap of the contingency table:**")
fig, ax = plt.subplots(figsize=(12, 10)) # Larger display
sns.heatmap(contingency_table, annot=False, cmap="YlGnBu", ax=ax)
ax.set_title(f"Heatmap of the contingency table: {cat_var1} vs. {cat_var2} top 10")
plt.xticks(rotation=90)
st.pyplot(fig)
except ValueError as e:
st.error(f"An error occurred: {str(e)}.")
回归分析选择
可用回归分析(线性回归、逻辑回归和多元回归)的选择方式与选择各种假设检验相似。选择分析方法后,将显示简短的说明,并调用相应的函数。
线性回归分析
在*“linear_regression()”函数的开始,创建一个由上传数据集中所有可用数值型变量构成的相关矩阵“corr_matrix = df[numerical_columns].corr()”*。该矩阵旨在帮助用户理解变量之间的关系,以便识别适合回归分析的变量和不适合的变量(多重共线性)。
最后,选择因变量和一个或多个自变量。数据被清理后,为所有选择的自变量创建线性回归模型*“model = LinearRegression()”*。回归系数和截距被指定。在总体模型运行完成后,为每个自变量创建单独的线性回归模型,并通过散点图表示[9]。
ASCVIT V1 线性回归 pal_sales、na_sales 和 total_sales(图像由作者提供)
显示的回归系数表示当相应的自变量变化一个单位时,因变量的变化程度。假设所有其他变量保持不变。当所有自变量为零时,因变量所取的值由截距指示。
def linear_regression(df, numerical_columns):
st.write("**Correlation matrix of numerical variables:**")
corr_matrix = df[numerical_columns].corr()
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', ax=ax)
st.pyplot(fig)
dependent_var = st.selectbox("Choose the dependent variable:", numerical_columns)
independent_vars = st.multiselect("Choose the independent variables:", numerical_columns)
if independent_vars:
if st.button("Perform regression"):
X = df[independent_vars].dropna()
y = df[dependent_var].loc[X.index]
y = y.dropna()
X = X.loc[y.index]
if y.isnull().values.any():
st.error("The dependent variable still contains missing values. Please clean the data.")
else:
model = LinearRegression()
model.fit(X, y)
st.markdown("**Regression coefficients:**")
for var, coef in zip(independent_vars, model.coef_):
st.write(f"- {var}: {coef}")
st.write(f"**Intercept:** {model.intercept_}")
for var in independent_vars:
X_single_var = X[[var]] # Use only the current independent variable
model_single = LinearRegression()
model_single.fit(X_single_var, y)
fig, ax = plt.subplots()
ax.scatter(X[var], y, edgecolor='none', facecolors='blue', s=5, label='Data points')
ax.plot(X[var], model_single.predict(X_single_var), color='red', label='Regression line')
ax.set_xlabel(var)
ax.set_ylabel(dependent_var)
ax.set_title(f"{dependent_var} vs {var}")
ax.legend()
st.pyplot(fig)
逻辑回归分析
与其他功能一样,用户在开始时选择因变量和自变量。在此分析方法中,因变量必须是二元的(0/1)。为了演示该功能,我创建了一些与迄今为止使用的数据集无关的数据。或者,你也可以手动调整变量的值,只要类别数目不太多。如果选择了错误的变量,将显示相应的错误信息。
如果所有内容都正确定义,则执行逻辑回归,模型使用自变量来建模目标变量的概率。具体而言,这是指事件发生的概率。每个自变量都有相应的系数,并且逻辑函数会被可视化。这展示了当自变量变化时,目标结果(1 而非 0)的概率如何变化[10]。
ASCVIT V1 逻辑回归演示用途的虚构值(图片来源:作者)
在散点图中,红线代表目标结果的预测概率,即结果 1 发生的概率。自变量发生变化。“logistic_regression()” 函数非常适用于二分类问题,在该问题中,您希望根据多个因素预测事件的发生。
def logistic_regression(df, numerical_columns):
dependent_var = st.selectbox("Choose the dependent variable (binary):", numerical_columns)
independent_vars = st.multiselect("Choose the independent variables:", numerical_columns)
if independent_vars:
if st.button("Perform logistic regression"):
X = df[independent_vars].dropna()
y = df[dependent_var].loc[X.index].dropna()
X = X.loc[y.index]
unique_values = y.unique()
if len(unique_values) != 2:
st.error("The dependent variable must be binary (e.g., 0 and 1).")
else:
model = LogisticRegression()
model.fit(X, y)
st.write("**Logistic regression coefficients:**")
for var, coef in zip(independent_vars, model.coef_[0]):
st.write(f"- {var}: {coef}")
st.write(f"**Intercept:** {model.intercept_[0]}")
for var in independent_vars:
fig, ax = plt.subplots()
ax.scatter(X[var], y, label='Data points')
x_range = np.linspace(X[var].min(), X[var].max(), 300).reshape(-1, 1)
X_copy = pd.DataFrame(np.tile(X.mean().values, (300, 1)), columns=X.columns)
X_copy[var] = x_range.flatten() # Vary the current variable var
y_prob = model.predict_proba(X_copy)[:, 1]
ax.plot(x_range, y_prob, color='red', label='Logistic function')
ax.set_xlabel(var)
ax.set_ylabel(f'Probability ({dependent_var})')
ax.set_title(f'Logistic regression: {dependent_var} vs {var}')
ax.legend()
st.pyplot(fig)
多元回归分析
在多元回归分析中,用户必须选择多个因变量和一个或多个自变量。分析将检视因变量如何受到自变量的影响。选择变量后,NaN 值将被再次删除,必要时会显示错误信息。模型输出所有因变量的回归系数和截距。
为所有自变量和因变量的组合创建带回归线的散点图。这个功能使得可以同时分析多个目标变量,并且建立它们与多个预测因子之间的关系[11]。
ASCVIT V1 多元回归(plotly)示例(图片来源:作者)
def multivariate_regression(df, numerical_columns):
dependent_vars = st.multiselect("**Choose the dependent variables (multiple):**", numerical_columns)
independent_vars = st.multiselect("**Choose the independent variables:**", numerical_columns)
if dependent_vars and independent_vars:
if st.button("Perform multivariate regression"):
X = df[independent_vars].dropna()
Y = df[dependent_vars].loc[X.index].dropna()
X = X.loc[Y.index]
if X.shape[1] != len(independent_vars) or Y.shape[1] != len(dependent_vars):
st.error("The number of independent or dependent variables does not match.")
return
model = LinearRegression()
model.fit(X, Y)
st.write("**Multivariate regression coefficients:**")
for i, dep_var in enumerate(dependent_vars):
st.write(f"\nFor the dependent variable: **{dep_var}**")
st.write(f"Intercept: {model.intercept_[i]}")
for var, coef in zip(independent_vars, model.coef_[i]):
st.write(f"- {var}: {coef}")
for dep_var in dependent_vars:
for var in independent_vars:
fig, ax = plt.subplots()
ax.scatter(X[var], Y[dep_var], label='Data points')
x_range = np.linspace(X[var].min(), X[var].max(), 300).reshape(-1, 1)
X_copy = pd.DataFrame(np.tile(X.mean().values, (300, 1)), columns=X.columns)
X_copy[var] = x_range.flatten()
y_pred = model.predict(X_copy)
ax.plot(x_range, y_pred[:, dependent_vars.index(dep_var)], color='red', label='Regression line')
ax.set_xlabel(var)
ax.set_ylabel(dep_var)
ax.set_title(f'Multivariate regression: {dep_var} vs {var}')
ax.legend()
st.plotly_chart(fig)
时间序列分析
该分析方法进行的是时间上的分析。为此,将给定的时间序列按年分组,并计算并显示值的年均值。该分析需要一个时间变量;如果使用的数据集不包含该变量,则无法进行分析。在我选择的数据集中,包含了变量 “release_date”,它记录了每个游戏的发布日期。
所选时间变量被转换为日期格式 “df[time_var]”。如果数据点无效,则会将其转换为 NaN 值并删除 “df = df.dropna(subset=[time_var])”。然后,数据按年分组 “df[‘year’] = df[time_var].dt.year”,并计算指定值变量“value_var”的年均值 “yearly_avg”。计算值变量的最小和最大年均值以及所有数据点的总体均值 “overall_avg”。接着,以折线图的形式显示每年的值变量年均值。总体均值集成在水平线上。为了提高可读性,值会交替显示在数据点的上下方[12]。
ASCVIT V1 时间序列分析与年份和 critic_score(图片来自作者)
重要的统计关键指标显示在图表下方,可以像描述性分析一样使用 LLM 轻松解释。具体来说,显示了标准差、方差以及值变量和年份的最小值和最大值。*“perform_time_series_analysis()”*函数适用于分析数据序列中的时间趋势。这可以对时间的变异性进行初步分析。
def perform_time_series_analysis(df, time_var, value_var):
df[time_var] = pd.to_datetime(df[time_var], errors='coerce')
df = df.dropna(subset=[time_var])
if df.empty:
st.error("**Error:** The time variable has an incorrect format.")
else:
df['year'] = df[time_var].dt.year
yearly_avg = df.groupby('year')[value_var].mean().reset_index()
y_min = yearly_avg[value_var].min()
y_max = yearly_avg[value_var].max()
y_range = y_max - y_min
y_buffer = y_range * 0.05
overall_avg = df[value_var].mean()
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(yearly_avg['year'], yearly_avg[value_var], marker='o', label='Yearly average')
ax.axhline(overall_avg, color='red', linestyle='--', label=f'Overall average: {overall_avg:.2f}')
ax.set_title(f'Average {value_var} per year')
ax.set_xlabel('Year')
ax.set_ylabel(f'Average {value_var}')
ax.set_ylim(y_min - y_buffer, y_max + y_buffer)
ax.text(yearly_avg['year'].max() - (yearly_avg['year'].max() - yearly_avg['year'].min()) * 0.05,
overall_avg + y_buffer,
f'{overall_avg:.2f}', color='red', ha='right', va='center')
for i in range(len(yearly_avg)):
if i % 2 == 0:
ax.text(yearly_avg['year'][i], yearly_avg[value_var][i] + y_buffer/2,
f'{yearly_avg[value_var][i]:.2f}', color='blue', ha='center', va='bottom')
else:
ax.text(yearly_avg['year'][i], yearly_avg[value_var][i] - y_buffer/2,
f'{yearly_avg[value_var][i]:.2f}', color='blue', ha='center', va='top')
plt.xticks(rotation=45)
ax.legend()
st.pyplot(fig)
st.write(f"**Standard deviation:** {df[value_var].std():.2f}")
st.write(f"**Variance:** {df[value_var].var():.2f}")
st.write(f"**Minimum {value_var}:** {y_min:.2f} in year {yearly_avg.loc[yearly_avg[value_var].idxmin(), 'year']}")
st.write(f"**Maximum {value_var}:** {y_max:.2f} in year {yearly_avg.loc[yearly_avg[value_var].idxmax(), 'year']}")
聚类方法选择
与假设检验和回归分析类似,在聚类方法领域也有多种选项可供选择。选择函数的结构与其他方法相似。选择一种方法并执行相应的函数,同时也会显示该方法的简要说明。根据不同的方法,必须定义簇的数量。对于 k-Means 和层次聚类,可以定义最多 10 个簇。对于 DBSCAN,则需要查询半径*“eps”和每个簇的最小点数“min_samples”*。每种方法必须选择至少两个数值变量。
k-Means 聚类
k-Means 算法将数据分为*“n_clusters”个簇。数据点的分组方式是使得簇内数据点之间的距离最小化。簇的数量由用户确定。根据该数量,算法计算出每个数据点属于哪个簇。结果会发送到“visualize_clusters()”*函数进行可视化[13]。
def perform_kmeans(X, n_clusters):
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
X['Cluster'] = kmeans.fit_predict(X)
visualize_clusters(X, 'k-Means Clustering')
ASCVIT V1 k-Means 聚类与 PCA 降维(图片来自作者)
层次聚类
在这里创建了一个簇的层次结构,可以使用聚合或分割方法。该函数使用的是聚合聚类方法,其中每个数据点最初被视为一个独立的簇,然后依次合并。簇的数量由用户确定,算法根据数量进行数据划分。与 k-Means 相同的函数用于可视化*“visualize_clusters(X, ‘Hierarchical Clustering’)”* [14]。
def perform_hierarchical_clustering(X, n_clusters):
hierarchical_clustering = AgglomerativeClustering(n_clusters=n_clusters)
X['Cluster'] = hierarchical_clustering.fit_predict(X)
visualize_clusters(X, 'Hierarchical Clustering')
ASCVIT V1 层次聚类与 PCA 降维(图片来自作者)
DBSCAN 聚类
通过这种方法,数据点根据其周围环境的密度进行分组。该方法非常适合检测异常值(噪声)并发现任何形状的簇。在这里,用户不指定簇的数量,而是指定两个点之间的最大距离*“eps”,超过该距离就认为它们是邻居。同时,还定义了簇中出现的最小点数“min_samples”。可视化也通过“visualize_clusters()”*函数生成[15]。
def perform_dbscan(X, eps, min_samples):
dbscan = DBSCAN(eps=eps, min_samples=min_samples)
X['Cluster'] = dbscan.fit_predict(X)
visualize_clusters(X, 'DBSCAN Clustering')
ASCVIT V1 DBSCAN 聚类与 PCA 降维(图片来自作者)
聚类可视化
三种不同聚类方法的结果通过*“visualize_clusters”函数进行可视化,采用主成分分析(PCA)。数据的维度通过 PCA 降到两个分量“n_components”,以便能够显示聚类结果。检查数据点和变量“num_samples”*是否足够;如果不足,则会显示错误信息。聚类结果通过散点图进行可视化,图中显示了前两个 PCA 分量中的数据点。
聚类结果以不同颜色显示*“cmap=‘tab10’”。在图表中,轴标签“ax.set_x/ylabel”和图例“legend_labels”已做调整,以便更好地解读。数据点的大小“s”以及透明度“alpha”也进行了调整,以提高可见性。在 DBSCAN 中,离群点会被自动分配到聚类-1。聚类的每个变量的平均值以表格形式显示在可视化图形下方“st.dataframe(cluster_means)”*。
def visualize_clusters(X, title):
num_samples, num_features = X.shape
n_components = min(num_samples, num_features, 2)
if n_components < 2:
st.error("Not enough data points or variables to perform PCA.")
return
pca = PCA(n_components=n_components)
try:
X_pca = pca.fit_transform(X.drop(columns=['Cluster']))
fig, ax = plt.subplots(figsize=(10, 6))
scatter = ax.scatter(X_pca[:, 0], X_pca[:, 1], c=X['Cluster'], cmap='tab10', s=25, alpha=0.4)
ax.set_title(title)
ax.set_xlabel(f'PCA 1' if n_components >= 1 else '')
ax.set_ylabel(f'PCA 2' if n_components == 2 else '')
cluster_counts = X['Cluster'].value_counts()
legend_labels = [f"Cluster {int(cluster)} ({count} points)" for cluster, count in cluster_counts.items()]
legend1 = ax.legend(handles=scatter.legend_elements()[0], labels=legend_labels)
ax.add_artist(legend1)
st.pyplot(fig)
st.write(f"**Average values per cluster:**")
cluster_means = X.groupby('Cluster').mean()
st.dataframe(cluster_means)
except ValueError as e:
st.error(f"**Error:** Not enough variables were selected.")
与 LLM 的通信
在应用程序的第一个版本中,统计计算的输出仅在描述性区域进行分析。关键数字通过*“query_llm_via_cli”函数进行解释。具体来说,该函数用于通过命令行(CLI)与 LLM 进行通信。为此,使用 Python 模块“subprocess”通过命令行启动进程。LLM 通过命令[“ollama”, “run”, “llama3.1”]启动。输入存储在“stdin”中,输出存储在“stout”*中。
错误和警告被存储在*“stderr”中,虽然希望不会出现这些问题。输入通过“process.communicate”发送到模型。具体来说,创建的“context”被发送到函数与 LLM 进行通信。如果模型没有回应,包含超时机制“timeout=40”,它将在 40 秒后停止执行。根据所用系统的计算能力,通常模型应更早返回响应。模型的响应被清理并传递到“extract_relevant_answer”*,以提取相关信息[1]。
def query_llm_via_cli(input_text):
"""Sends the question and context to the LLM and receives a response"""
try:
process = subprocess.Popen(
["ollama", "run", "llama3.1"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8',
errors='ignore',
bufsize=1
)
stdout, stderr = process.communicate(input=f"{input_text}\n", timeout=40)
if process.returncode != 0:
return f"Error in the model request: {stderr.strip()}"
response = re.sub(r'\x1b\[.*?m', '', stdout)
return extract_relevant_answer(response)
except subprocess.TimeoutExpired:
process.kill()
return "Timeout for the model request"
except Exception as e:
return f"An unexpected error has occurred: {str(e)}"
def extract_relevant_answer(full_response):
response_lines = full_response.splitlines()
if response_lines:
return "\n".join(response_lines).strip()
return "No answer received"
应用程序的主函数
应用程序的结构由*“main()”函数定义。标题通过“st.title()”设置,侧边栏用于上传 CSV 或 Excel 格式的数据集“uploaded_file”。上传文件后,应用程序会分析文件并提取数值和类别变量。在这里和许多其他情况下,Streamlit 使用“session_state”*存储与分析方法选择相关的某些参数。
变量*“numerical_columns”和“categorical_columns”*将在上传新数据集后更新。一旦数据可用,用户可以从多种分析方法中选择。选择方法后,会显示该方法,并在相应的变量定义后进行操作。主功能控制应用程序的互动统计分析。
自定义选项
如前所述,由于代码的模块化结构,该应用程序可以扩展以包括其他分析方法。使用 LLM 解读统计关键数据的功能也可以转移到其他方法。当前使用的是 Meta 的 Llama3.1 (8B),但也可以使用 Ollama 的另一款 LLM(例如 Mistral)。此时,*“query_llm_via_cli”*函数中的命令必须进行相应调整。
根据可用的计算资源,也可以使用更多参数的模型。图表的设计可以进一步优化,传输的上下文也可以加以改进,以提升 LLM 的输出效果。或者,你也可以创建一个新的模型文件,调整 LLM 的某些参数(例如参数),从而改善数据的解读。
ASCVIT V1 PYTHON 脚本 [GITHUB]
应用程序的代码可以从以下GitHub 仓库下载。应用程序可以在相应目录中通过以下命令启动:
Streamlit run app.py
结论
在本文中,我展示了如何使用 Streamlit 创建一个应用程序,利用多种方法分析数据集。我还展示了如何将 LLM 集成到该应用程序中,从而带来实际的附加值。数据不仅会自动可视化并输出统计参数,还会进行分类。该应用程序具有广泛的发展潜力。我在倒数第二部分列出了一些建议。希望你在使用和自定义应用程序时玩得开心。
你最多可以拍手 50 次!
[1] Pietrusky, S. (2024 年 8 月 21 日). 如何在不使用专有模型的情况下与 PDF 文件交互:CLI, Streamlit, Ollama. Towards Data Science. URL
[2] Maven Analytics. (2024 年 6 月 10 日). 数据游乐场,视频游戏销售. URL
[3] Hastie, T., Tibshirani, R., & Friedman, J. (2009). 统计学习的元素:数据挖掘、推断与预测(第 2 版)。斯坦福大学。URL
[4] Bruce, P., Bruce, A., & Gedeck, P. (2021). 数据科学家的实用统计学:50+个 R 和 Python 中的核心概念(第 2 版)。O’Reilly。
[5] VanderPlas J. (2017). Python 数据科学手册:处理数据的必备工具. O’Reilly。[URL]
[6] Fahrmeir, L., Künstler, R., Pigeot, I., & Tutz, G. (2016). 统计学:数据分析之路(第 8 版)。Springer.
[7] Montgomery, D. C. (2012). 实验设计与分析(第 8 版)。Wiley. URL
[8] Moore, D. S., McCabe, G. P., Craig, B. A., & Duckworth, W. M. (2021). 统计学实践导论(第 10 版)。W. H. Freeman.
[9] Montgomery, D. C., Peck, E. A., & Vining, G. G. (2012). 线性回归分析导论(第 5 版)。Wiley. URL
[10] Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). 应用逻辑回归(第 3 版)。Wiley.
[11] Johnson, R. A., & Wichern, D. W. (2007). 应用多元统计分析(第 6 版)。Pearson. URL
[12] Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). 时间序列分析:预测与控制(第 5 版)。Wiley. URL
[13] Witten, I. H., & Frank, E. (2005). 数据挖掘:实用的机器学习工具与技术(第 2 版)。Morgan Kaufmann. URL
[14] Everitt, B. S., Landau, S., Leese, M., & Stahl, D. (2011). 聚类分析(第 5 版)。Wiley. URL
[15] Aggarwal, C. C., & Reddy, C. K. (2014). 数据聚类:算法与应用。CRC Press URL
仅为缩略图(图片来源:作者)
不要问人工智能能为你做什么 — 问问你能与人工智能一起实现什么
https://medium.com/@fneves?source=post_page---byline--36814f622849--------------------------------https://towardsdatascience.com/?source=post_page---byline--36814f622849-------------------------------- Fábio Neves
·发布于Towards Data Science ·9 分钟阅读·2024 年 8 月 8 日
–
图片来自BoliviaInteligente,发布于Unsplash
新的前沿
在过去的一年半里,我一直在告诉我认识的每个人有关人工智能的潜力,特别是大型语言模型(LLM)。是时候让每个人,无论他们的技术背景如何,都学习 LLM 的基础知识,并了解如何高效地使用它们。
在 1960 年代,我们有了登月计划。今天,我们拥有广阔而未被探索的人工智能领域。这一次,不是去插旗或者留下脚印,而是关于拓展人类潜力。
我真心认为,在这个新时代,我们每个人都是开拓者。
挑战不仅仅是跟上新设备的步伐,而是要变得擅长于与人工智能沟通。
每个人的旅程
忘掉那些借口,比如“我不会编程”或者“太复杂了”。
竞技场是平等的,只要稍加努力,任何人都能从人工智能中受益。
只需每周花一小时自己进行测试,并弄清楚如何使用这些工具,我敢打赌,你很可能会感到有必要改进你与这些“东西”沟通的方式,以便它们能给你提供更好的结果!
作为数据科学家个人贡献者,如何请求反馈
接收清晰而有用的反馈。摒弃笼统的问题。这里有超过 60 个示例问题供你使用。
https://medium.com/@joparga3?source=post_page---byline--4ffcfa86ec41--------------------------------https://towardsdatascience.com/?source=post_page---byline--4ffcfa86ec41-------------------------------- Jose Parreño
·发表于Towards Data Science ·14 分钟阅读·2024 年 9 月 18 日
–
图片由Marsha Reid提供,来源于Unsplash
请求反馈可能会让人感到困难,甚至令人畏惧。有很多因素可能影响你如何请求反馈:公司文化、个人恐惧、缺乏参与的经理、过去的反馈无效等等……
尽管这些情况可能是事实,但它们不应该阻止你请求反馈。作为一名带领团队的人,我必须定期提供大量反馈,而且每次绩效评估时也需要提供反馈。在之前的一篇文章中,我描述了如何使用 SBIN 框架提供反馈。我希望依赖这个框架,为你提供一组模板/指导问题,帮助你更有针对性地获得反馈,并从中得到更高质量的回应。
PS 1: 虽然这篇博客的标题是面向个人贡献者的,但数据科学经理也许会发现其中的内容对他们传递给团队非常有价值。
PS 2: 本文的灵感来源于与 Stefano Franco的合作。作为一名非常周到的团队负责人,他通过开发标准化团队工具帮助他人。
有限区域内的傅里叶级数的各种形式
选择在边界处表现良好的那个
https://sebastiengilbert.medium.com/?source=post_page---byline--8c93904df6ae--------------------------------https://towardsdatascience.com/?source=post_page---byline--8c93904df6ae-------------------------------- Sébastien Gilbert
·发表于 Towards Data Science ·阅读时间:8 分钟·2024 年 4 月 22 日
–
如果你查阅傅里叶分析的历史,你会发现让·巴普蒂斯特·约瑟夫·傅里叶在研究热流问题时,正式化了这套以他名字命名的级数。
傅里叶级数将周期信号表示为正弦波的和,这些正弦波的频率是基本频率的整数倍。
我们直观地知道,导热介质中的热点会向四面八方传播热量,直到温度均匀分布为止。在这个现象中,无论在空间还是时间上,都没有可见的振荡行为。那么为什么要引入一系列正弦波呢?
初始温度分布、控制微分方程和边界条件决定了一维导热介质(如一根薄金属棒)问题中温度函数 u(x, t)的演变。结果显示,初始温度分布的空间频率分量会随着时间的推移被一个衰减的指数函数所抑制,且其指数因子增长速率与空间频率的平方成正比。换句话说,初始温度分布中的高频部分衰减速度远快于低频部分,这也解释了温度分布的平滑现象。
在这个故事中,我们将回顾有限区间上定义的傅里叶级数的基础知识。我们将问题构造为,使得得到的傅里叶级数在区间的边界处具有一些理想的性质。当我们将傅里叶级数应用于解决涉及具有边界约束的微分方程问题时,这种方法将带来好处。
傅里叶级数:表示周期函数的工具
傅里叶级数可以逼近周期函数。假设 g(x)是一个周期为 2L 的周期函数。
为什么是周期 2L?
我们关注的是定义在有限区间[0, L]上的函数。我们可以构造一个周期为 2L 的周期函数 g(x),其周期函数 g(x)的定义域为[0, L],并通过在函数两端加上适当的填充,以获得理想的性质。稍后我们会回到这一点。
假设傅里叶级数存在,我们可以将 g(x)写成:
举个例子,我们考虑以下周期函数 g(x),其周期为 2L = 0.6:
图 1:周期函数 g(x)。图片由作者提供。
通过应用方程(2)、(3)、(4)并使用辛普森数值积分,可以得到 a₀、aₙ和 bₙ的以下值:
这些值,即傅里叶系数,使我们能够通过方程(1)构建 g(x)的近似值。我们在求和中包含的项数越多,近似值就越精确。图 2 展示了通过方程(1)中不同项数的求和得到的几种近似。
图 2:通过傅里叶级数中的不同项数重构 g(x)。图片由作者提供。
我们已经可以提出一些观察结果:
-
信号中的有限不连续性是可以容忍的,但它们会在重构的近似中产生波动。我们称这些不连续点附近的振荡现象为吉布斯现象。
-
傅里叶级数是一个无限项的和,但我们可以截断求和,并仍然得到原始函数的合理近似。
-
原始信号可能是离散点的样本。傅里叶级数可以在 x 轴的任何位置插值该函数。
定义在有限区间上的函数
在工程问题中,我们经常遇到定义在有限区间上的函数。例如,在导热介质的一维温度分布中,温度函数定义在区间[0, L]上,其中 L 是薄金属棒的长度。那么,在这种情况下,如何使用傅里叶级数呢?
为了解答这个问题,我们首先需要认识到,任何在范围[0, L]内与目标函数 f(x)一致的周期函数 g(x),都是 f(x)的傅里叶级数表示的有效候选。毕竟,我们不关心傅里叶级数在[0, L]范围之外的行为。
f(x)的天真周期复制
构建 g(x)的最直接方法是将 f(x)在区间[-L, 0]内复制,如图 3 所示:
图 3:f(x) 在[0, 0.3]范围内定义,并在范围[-0.3, 0]内复制,构建周期为 0.6 的周期函数 g(x)。图片来源:作者。
对 f(x)的天真周期复制进行傅里叶积分,得到方程(5)到(7):
通过将(5)、(6)、(7)代入方程(1)中的 f(x)(参见图 3),我们得到了图 4 所示的傅里叶级数重构:
图 4:图 3 中的 f(x)(原始信号)和傅里叶级数,显示为信号重构。图片来源:作者。
傅里叶级数与原始信号非常接近,除了在范围边界处,重构会出现振荡和跳跃。由于我们明确构造了一个周期为 L 的周期信号,傅里叶级数将 x=0 和 x=L 处的过渡解释为有限的间断点。
傅里叶级数允许有限的间断性,但吉布斯现象会在间断点周围恶化重构效果。
对于许多工程应用来说,这是一个问题。例如,在薄金属棒的热传导问题中,金属棒两端(即边界条件)发生的情况是问题描述的一个内在部分。我们可以假设有一根孤立的金属棒,这意味着两端的温度梯度必须为 0。或者,我们可以假设在 x=0 和 x=L 处有任意的设定温度。在这些常见场景中,我们不能使用天真周期复制 f(x)的方法,因为吉布斯现象会在范围的两端破坏信号。
偶数半范围扩展
我们可以将 f(x)复制为图 5 中的形式,也可以在范围[-L, 0]内使用 f(x)的翻转版本:
图 5:g(x) = f(-x) 在范围[-L, 0]内。图片来源:作者。
这种方法消除了 x=0 和 x=L 处的间断性。f(x)的偶数半范围扩展的傅里叶积分得到方程(8)到(10):
图 6 展示了 f(x)的傅里叶级数重构:
图 6:原始信号及其通过偶数半范围扩展的重构。图片来源:作者。
偶数半范围展开的一个特性是,由于 g(x)是偶函数,所有的 bₙ系数(参见方程(10))为 0,因此它的傅里叶级数仅由余弦项组成。因此,傅里叶级数的导数在 x=0 和 x=L 处为零。你可以通过对方程(1)关于 x 进行求导,且将所有 bₙ项设置为 0 来验证这一点。
这是我们在某些情况下所需要的,例如金属杆被隔离,没有热量泄漏到端部。
奇数半范围展开
如果我们改为创建一个奇函数会怎么样呢?这可以通过将 f(x)的旋转版本粘贴到区间[-L, 0]中来实现,如图 7 所示:
图 7:g(x) = -f(-x)在区间[-L, 0]。图片由作者提供。
f(x)的奇数半范围展开的傅里叶积分得到方程(11)到(13):
图 8 显示了 f(x)的傅里叶级数重构:
图 8:原始信号及其通过奇数半范围展开的重构。图片由作者提供。
由于 g(x)是奇函数,傅里叶级数仅由正弦项组成。因此,傅里叶级数在 x=0 和 x=L 处为零。这个特性可以在模拟振动吉他弦的形状时加以利用。吉他弦在 x=0 和 x=L 处的高度被限制为 0,因此我们自然会使用奇数半展开来模拟初始条件。
图片由Rio Lecatompessy提供,来源于Unsplash
偶数四分之一范围展开
我们还可以更加创新,设计一个周期为 4L 的周期性函数。如果我们希望在 x=0 处的导数为 0,并且在 x=L 处的值和导数都平滑过渡,可以在[L, 2L]区间附加 f(x)的旋转副本并使该函数为偶函数。图 9 展示了一个例子:
图 9:g(x) = 2f(L) - f(2L+x)在区间[-2L, -L];f(-x)在区间[-L, 0];f(x)在区间[0, L];2f(L)-f(2L-x)在区间[L, 2L]。图片由作者提供。
f(x)的偶数四分之一范围展开的傅里叶积分得到方程(14)到(16):
图 10 显示了 f(x)的傅里叶级数重构:
图 10:原始信号和通过偶数四分之一范围展开的傅里叶级数重构。图片由作者提供。
尽管从图中无法看出,傅里叶级数的导数在 x=0 处为 0,并且在 x=L 处与原始信号相同。
奇数四分之一范围展开
我们考虑的最后一个情况是,当我们希望 x=0 处的值为 0,x=L 处的导数为 0 时。我们通过在[L, 2L]范围内附加 f(x)的翻转版本来构建 g(x),并使该函数成为奇函数。
图 11:g(x) = -f(x+2L)在范围[-2L, L]内;-f(-x)在范围[-L, 0]内;f(x)在范围[0, L]内;f(2L-x)在范围[L, 2L]内。图片由作者提供。
f(x)的奇数四分之一范围展开的傅里叶积分得到方程(17)到(19):
图 12 显示了 f(x)的傅里叶级数重建:
图 12:原始信号与傅里叶级数重建,采用奇数四分之一范围展开。图片由作者提供。
我们可以看到,重建在 x=0 时通过 0。即使原始信号的导数不是零,x=L 处的导数为零。
结论
我们考虑了为定义在有限区间[0, L]上的信号 f(x)找到合适的傅里叶级数展开的问题。傅里叶级数适用于周期性函数,因此我们必须构建一个与 f(x)在定义域上匹配的周期性函数。我们观察到定义周期性函数 g(x)的四种方法。每种方法都能确保在范围边界处具有特定的属性:
-
偶数半范围展开:傅里叶级数在 x=0 和 x=L 处的导数为 0。
-
奇数半范围展开:傅里叶级数在 x=0 和 x=L 处的值为 0。
-
偶数四分之一范围展开:傅里叶级数在 x=0 处的导数为 0,并且在 x=L 处具有平滑的值和导数。
-
奇数四分之一范围展开:傅里叶级数在 x=0 处的值为 0,x=L 处的导数为 0。
在未来的故事中,我们将研究热量如何在细长的金属棒中传递。解决方案涉及将初始温度分布转换为傅里叶级数。我们将观察到,傅里叶级数展开的选择自然由边界条件决定(例如,金属棒在 x=0 处是隔离的,在 x=L 处保持固定温度)。我们在这篇文章中创建的那些看似任意的周期性函数,将突然变得有意义!
参考文献
(R1) 《高级工程数学》,Erwin Kreyszig,John Wiley & Sons,1988

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)