<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2024-09-27T17:16:45+00:00</updated><id>/feed.xml</id><title type="html">CAIYONGJI’S BLOG</title><subtitle>Let&apos;s make progress!</subtitle><author><name>caiyongji</name><email>i@caiyongji.com</email></author><entry><title type="html">深度！程序员生涯的垃圾时间（上）</title><link href="/2024/09/15/programmers-garbage-time-1.html" rel="alternate" type="text/html" title="深度！程序员生涯的垃圾时间（上）" /><published>2024-09-15T00:00:00+00:00</published><updated>2024-09-15T00:00:00+00:00</updated><id>/2024/09/15/programmers-garbage-time-1</id><content type="html" xml:base="/2024/09/15/programmers-garbage-time-1.html"><![CDATA[<h1 id="1">1</h1>
<p>很多程序员对互联网行业中广泛讨论的“35岁危机”表示不满，似乎所有的程序员都有着35岁的职业保质期。然而，随着AI技术的兴起，这场翻天覆地的技术革命正以更加残酷且直接的方式渗透到各行各业。程序员的核心价值正在被自动化和智能工具所取代。程序员不再面临传统意义上的35岁年龄危机，而是面临着职业生涯的终结危机。</p>

<p>AI技术迅速崛起，其迭代速度快到了以周为单位，几乎所有的大模型公司都在AI编程上取得了重大突破。程序员正面临着深刻的转型和被淘汰的风险。但由于AI技术取代程序员的过渡期尚未完全结束，许多程序员仍然从事着那些即将被取代的工作。我愿意把这段时间称为“程序员的垃圾时间”。</p>

<p>垃圾时间（Garbage time）是体育赛事中的术语，指一场比赛中双方分差过大，胜负已定。此时，比赛剩余的时间不再对最终结果产生决定性影响，剩下的时间就被称为垃圾时间。将这个词用在浩浩荡荡的技术革命、汹涌向前的历史车轮上，再合适不过。时代的必然，是个人无法违背的规律。</p>

<h1 id="2">2</h1>
<p>要想理解程序员被AI取代的深层逻辑，我们就不得不说一下AI的原理。</p>

<p>AI之所以能够表现出智能，背后是以大型语言模型（LLM）作为核心支持。它的训练逻辑是基于海量的语言数据，利用每秒可执行万亿次浮点运算的GPU集群（以A100为例，其双精度浮点运算能力为19.5 TFLOPS），通过高效的算法调整数万亿的参数来训练语言模型。我们可以将模型简单粗暴地理解为数据加上参数结构。虽然这样说很简单，但训练模型的成本相当高。以GPT-4为例，训练模型需要数万张每张价值一万美元的A100显卡，训练一次需要上百天，光每天的电费就高达数万美元。不是所有的智能模型都需要如此大的投入，而是如此大规模的投入才能训练出超级智能。</p>

<p>为什么模型可以表现出智能？智能的本质是什么呢？</p>

<p>科学界普遍认为，大模型的涌现能力塑造了AI的智能。涌现（emergence）是指一个大实体由许多相互作用的小实体组成，而这个大实体却能表现出任何组成它的小实体都不具备的特性。随着ChatGPT的流行，大家更加关注大型语言模型的涌现能力。大模型的涌现更多地指，随着模型规模的变大，模型在某一刻突然表现出以前没有的能力，也就是智能。</p>

<p>大模型还有另一个令人惊讶的特性：随着规模的变化，它的准确度也呈幂律上升，这就是规模法则（scaling law）。模型的规模越大，它的表现能力提升得越快。换句话说，随着加大数据量和计算量的投入，模型的智能会呈现出指数级的增长。</p>

<p>现如今，AI大模型正在以一种人类第二大脑的形式渗透到各个领域。尤其是最近OpenAI发布的新模型，使我们的第二大脑不仅是知识的存储和提取工具，更具备了深层次的思考能力。在编程领域，它的表现尤为出色。程序开发天然适合AI的应用场景，因为程序是没有二义性的。程序开发是高度结构化的，代码中的每一个命令、每一个语法逻辑都有着严格的规则。人类的语言表达是存在歧义的，表面意思和深层含义可能不同。但编程语言则不然，它没有任何歧义，只有0和1的非黑即白。</p>

<h1 id="3">3</h1>
<p>这种AI编程取代程序员的过程与新能源取代传统燃油车的进程非常相似。随着新能源技术的发展，产业链的成熟，规模效应使得边际成本越来越低，新能源的竞争优势也越来越大。但它并不是一下子取代所有的燃油车，甚至燃油车的市场根本就不会完全消失。燃油车市场会逐渐开始分化，可被取代的民用汽车市场逐渐被新能源汽车代替，而燃油车则开始走向高端市场，逐渐面向特定群体，比如汽车爱好者和收藏家。你可以在很多超级跑车上见到手动挡，这就是一种侧面印证。</p>

<p>编程领域也是如此，它同样会在AI编程的影响下逐渐分化。传统的工程化编程工作在这个阶段逐渐失去意义，变得越来越机械化和工具化。程序员投入的精力和时间，与AI带来的生产力提升相比，使他们感觉自己的劳动价值被稀释。因此，处理常规开发任务、运维、前后端开发、简单业务逻辑编码的工程化程序员，其职业生涯正被AI工具所威胁。而那些少数的精英型程序员则被重用，他们具备深厚的理论基础和算法能力，工作更具创造性和前沿性，已超越了传统工程师的范畴，更像是一名科学家。这种理学思维和工程思维的核心区别，体现在专业上就是工科和理科的区别。这注定了未来程序员的工作，或者说程序科学家的工作，只有极少数人能够胜任。</p>

<p>麻省、哈佛、斯坦福，清华、北大、中科院，如今在AI领域的研究者，都有着极高的学术背景。他们与AI的结合可谓以一当十，以一敌百。他们创造的价值有多巨大，就有多少“平庸”的价值被取代。</p>

<h1 id="4">4</h1>
<p>然而，任何变革总是充满着危机与机遇。当我们看不清未来时，不妨回过头看看过去。</p>

<p>我们从技术和经济的角度来回顾历史上的一些故事。</p>

<p>首先，从技术的角度来看。</p>

<p>2016年4月，AlphaGo战胜了世界围棋冠军李世石。自此之后，在下围棋这件事上，人类就再也没赢过。如果我们想了解ChatGPT对人类的影响，不妨看看AlphaGo对围棋界产生了哪些影响。</p>

<p>如今，几乎所有职业围棋选手都依赖围棋AI来提升自己的棋艺。比如在开局阶段，许多被传统认为是“不能走”的棋路，AI却会大胆选择。经过多次攻防后，AI会在另一个地方回应这些棋路，展现出人意料的深远布局。职业棋手们直到这时才恍然大悟：原来如此！</p>

<p>有人形容，AI时代就像远远驶来的火车。我们远远地就看到它来势汹汹，但当它真正到来时，却只是一瞬间与我们擦肩而过。然后，我们只能眼睁睁地看着它离我们越来越远，再也无法追上。</p>

<p>19世纪时，电力仅限于上流社会使用。当有人提议将电力普及到千家万户时，议会上出现了反对的声音。有人警告道：“如果每家每户都安装电插头，那其杀伤力将难以估量，简直就像现代化的武器！如果一只小猫不小心碰到电插头，不就立刻被电死了吗？如果哥哥叫弟弟去摸一摸插头，岂不是瞬间没命？如果我们在整个伦敦，甚至全英国普及电力，岂不是等于给所有人，包括坏人和精神病患者都发了一把枪？这实在是太可怕了！””</p>

<p>因此，这项决议当时没有通过。</p>

<p>然而，站在今天的角度回看，电力为整个人类社会带来了巨大的价值，几乎所有人都从中获益。诚然，触电事故的确时有发生，但即使如此，我们也不会因此停止使用电力。我们需要做的，是学习如何正确、安全地使用电。</p>

<h1 id="5">5</h1>
<p>我们再从资本的角度来看。</p>

<p>我们不得不承认，资本是推动技术快速发展的核心力量。资本的大量投入，使得AI成为当下最热门的领域。各种初创公司、研究项目、创新产品都得到了空前的支持。虽然这必然会导致AI市场的泡沫化，但这种过度推动正是为了刺激创新，筛选出具有竞争力的公司和产品。疯狂砸钱，激活市场，正是资本朴实无华的行事手段。最终，一定会有几家公司脱颖而出，形成寡头格局。这些公司都是经过充分竞争而产生的，而谁最终胜出并不重要。</p>

<p>这像不像是当初互联网泡沫时代的重演？</p>

<p>2000年左右，互联网同样经历了泡沫化，也同样经历了金融危机。但新兴事物的崛起，必然伴随着混乱和动荡。各个公司摸着石头过河，最终摸索出成功的商业模式，塑造了今天的互联网格局。而当今的科技巨头，恰恰都是那个互联网泡沫年代产生的。百度，2000年创办；腾讯，1998年创办；阿里巴巴，1999年创办；谷歌，1998年创办；Facebook，2004年创办；亚马逊，1994年创办；Netflix，1997年创办。这些公司都是在互联网泡沫时期产生的，并在那段混乱中脱颖而出。</p>

<p>我们现在面对的这场AI技术革命，同样伴随着经济的衰退，但这绝对不是一个时代的衰落，而是一个崭新时代的开始。AI时代的独角兽，正在孕育当中。</p>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="AI" /><category term="ChatGPT" /><category term="程序员的垃圾时间" /><category term="OpenAI" /><category term="GPT" /><summary type="html"><![CDATA[1 很多程序员对互联网行业中广泛讨论的“35岁危机”表示不满，似乎所有的程序员都有着35岁的职业保质期。然而，随着AI技术的兴起，这场翻天覆地的技术革命正以更加残酷且直接的方式渗透到各行各业。程序员的核心价值正在被自动化和智能工具所取代。程序员不再面临传统意义上的35岁年龄危机，而是面临着职业生涯的终结危机。 AI技术迅速崛起，其迭代速度快到了以周为单位，几乎所有的大模型公司都在AI编程上取得了重大突破。程序员正面临着深刻的转型和被淘汰的风险。但由于AI技术取代程序员的过渡期尚未完全结束，许多程序员仍然从事着那些即将被取代的工作。我愿意把这段时间称为“程序员的垃圾时间”。 垃圾时间（Garbage time）是体育赛事中的术语，指一场比赛中双方分差过大，胜负已定。此时，比赛剩余的时间不再对最终结果产生决定性影响，剩下的时间就被称为垃圾时间。将这个词用在浩浩荡荡的技术革命、汹涌向前的历史车轮上，再合适不过。时代的必然，是个人无法违背的规律。 2 要想理解程序员被AI取代的深层逻辑，我们就不得不说一下AI的原理。 AI之所以能够表现出智能，背后是以大型语言模型（LLM）作为核心支持。它的训练逻辑是基于海量的语言数据，利用每秒可执行万亿次浮点运算的GPU集群（以A100为例，其双精度浮点运算能力为19.5 TFLOPS），通过高效的算法调整数万亿的参数来训练语言模型。我们可以将模型简单粗暴地理解为数据加上参数结构。虽然这样说很简单，但训练模型的成本相当高。以GPT-4为例，训练模型需要数万张每张价值一万美元的A100显卡，训练一次需要上百天，光每天的电费就高达数万美元。不是所有的智能模型都需要如此大的投入，而是如此大规模的投入才能训练出超级智能。 为什么模型可以表现出智能？智能的本质是什么呢？ 科学界普遍认为，大模型的涌现能力塑造了AI的智能。涌现（emergence）是指一个大实体由许多相互作用的小实体组成，而这个大实体却能表现出任何组成它的小实体都不具备的特性。随着ChatGPT的流行，大家更加关注大型语言模型的涌现能力。大模型的涌现更多地指，随着模型规模的变大，模型在某一刻突然表现出以前没有的能力，也就是智能。 大模型还有另一个令人惊讶的特性：随着规模的变化，它的准确度也呈幂律上升，这就是规模法则（scaling law）。模型的规模越大，它的表现能力提升得越快。换句话说，随着加大数据量和计算量的投入，模型的智能会呈现出指数级的增长。 现如今，AI大模型正在以一种人类第二大脑的形式渗透到各个领域。尤其是最近OpenAI发布的新模型，使我们的第二大脑不仅是知识的存储和提取工具，更具备了深层次的思考能力。在编程领域，它的表现尤为出色。程序开发天然适合AI的应用场景，因为程序是没有二义性的。程序开发是高度结构化的，代码中的每一个命令、每一个语法逻辑都有着严格的规则。人类的语言表达是存在歧义的，表面意思和深层含义可能不同。但编程语言则不然，它没有任何歧义，只有0和1的非黑即白。 3 这种AI编程取代程序员的过程与新能源取代传统燃油车的进程非常相似。随着新能源技术的发展，产业链的成熟，规模效应使得边际成本越来越低，新能源的竞争优势也越来越大。但它并不是一下子取代所有的燃油车，甚至燃油车的市场根本就不会完全消失。燃油车市场会逐渐开始分化，可被取代的民用汽车市场逐渐被新能源汽车代替，而燃油车则开始走向高端市场，逐渐面向特定群体，比如汽车爱好者和收藏家。你可以在很多超级跑车上见到手动挡，这就是一种侧面印证。 编程领域也是如此，它同样会在AI编程的影响下逐渐分化。传统的工程化编程工作在这个阶段逐渐失去意义，变得越来越机械化和工具化。程序员投入的精力和时间，与AI带来的生产力提升相比，使他们感觉自己的劳动价值被稀释。因此，处理常规开发任务、运维、前后端开发、简单业务逻辑编码的工程化程序员，其职业生涯正被AI工具所威胁。而那些少数的精英型程序员则被重用，他们具备深厚的理论基础和算法能力，工作更具创造性和前沿性，已超越了传统工程师的范畴，更像是一名科学家。这种理学思维和工程思维的核心区别，体现在专业上就是工科和理科的区别。这注定了未来程序员的工作，或者说程序科学家的工作，只有极少数人能够胜任。 麻省、哈佛、斯坦福，清华、北大、中科院，如今在AI领域的研究者，都有着极高的学术背景。他们与AI的结合可谓以一当十，以一敌百。他们创造的价值有多巨大，就有多少“平庸”的价值被取代。 4 然而，任何变革总是充满着危机与机遇。当我们看不清未来时，不妨回过头看看过去。 我们从技术和经济的角度来回顾历史上的一些故事。 首先，从技术的角度来看。 2016年4月，AlphaGo战胜了世界围棋冠军李世石。自此之后，在下围棋这件事上，人类就再也没赢过。如果我们想了解ChatGPT对人类的影响，不妨看看AlphaGo对围棋界产生了哪些影响。 如今，几乎所有职业围棋选手都依赖围棋AI来提升自己的棋艺。比如在开局阶段，许多被传统认为是“不能走”的棋路，AI却会大胆选择。经过多次攻防后，AI会在另一个地方回应这些棋路，展现出人意料的深远布局。职业棋手们直到这时才恍然大悟：原来如此！ 有人形容，AI时代就像远远驶来的火车。我们远远地就看到它来势汹汹，但当它真正到来时，却只是一瞬间与我们擦肩而过。然后，我们只能眼睁睁地看着它离我们越来越远，再也无法追上。 19世纪时，电力仅限于上流社会使用。当有人提议将电力普及到千家万户时，议会上出现了反对的声音。有人警告道：“如果每家每户都安装电插头，那其杀伤力将难以估量，简直就像现代化的武器！如果一只小猫不小心碰到电插头，不就立刻被电死了吗？如果哥哥叫弟弟去摸一摸插头，岂不是瞬间没命？如果我们在整个伦敦，甚至全英国普及电力，岂不是等于给所有人，包括坏人和精神病患者都发了一把枪？这实在是太可怕了！”” 因此，这项决议当时没有通过。 然而，站在今天的角度回看，电力为整个人类社会带来了巨大的价值，几乎所有人都从中获益。诚然，触电事故的确时有发生，但即使如此，我们也不会因此停止使用电力。我们需要做的，是学习如何正确、安全地使用电。 5 我们再从资本的角度来看。 我们不得不承认，资本是推动技术快速发展的核心力量。资本的大量投入，使得AI成为当下最热门的领域。各种初创公司、研究项目、创新产品都得到了空前的支持。虽然这必然会导致AI市场的泡沫化，但这种过度推动正是为了刺激创新，筛选出具有竞争力的公司和产品。疯狂砸钱，激活市场，正是资本朴实无华的行事手段。最终，一定会有几家公司脱颖而出，形成寡头格局。这些公司都是经过充分竞争而产生的，而谁最终胜出并不重要。 这像不像是当初互联网泡沫时代的重演？ 2000年左右，互联网同样经历了泡沫化，也同样经历了金融危机。但新兴事物的崛起，必然伴随着混乱和动荡。各个公司摸着石头过河，最终摸索出成功的商业模式，塑造了今天的互联网格局。而当今的科技巨头，恰恰都是那个互联网泡沫年代产生的。百度，2000年创办；腾讯，1998年创办；阿里巴巴，1999年创办；谷歌，1998年创办；Facebook，2004年创办；亚马逊，1994年创办；Netflix，1997年创办。这些公司都是在互联网泡沫时期产生的，并在那段混乱中脱颖而出。 我们现在面对的这场AI技术革命，同样伴随着经济的衰退，但这绝对不是一个时代的衰落，而是一个崭新时代的开始。AI时代的独角兽，正在孕育当中。]]></summary></entry><entry><title type="html">深度！程序员生涯的垃圾时间（下）</title><link href="/2024/09/15/programmers-garbage-time-2.html" rel="alternate" type="text/html" title="深度！程序员生涯的垃圾时间（下）" /><published>2024-09-15T00:00:00+00:00</published><updated>2024-09-15T00:00:00+00:00</updated><id>/2024/09/15/programmers-garbage-time-2</id><content type="html" xml:base="/2024/09/15/programmers-garbage-time-2.html"><![CDATA[<h1 id="6">6</h1>
<p>程序员正处于这场技术革命的风暴中心，面临着被取代的命运。然而，这场技术革命的过渡期，也是程序员们的黄金转型期。因为程序员是距离这个时代变革最近的一群人。程序员的技术背景、编程能力、逻辑思维，都和AI技术天生契合。那些可以持续学习、快速适应并且创新的人，将能够在AI主导的未来中占据优势。</p>

<p>可以肯定的是，未来人们和AI的关系会越来越紧密。AI的诞生使得世界的工作效率进入了一个更加高速的时代。换句话说，各种工作的过程耗时会极大地缩短，我们可以更快速地拿到结果，省去人工的中间过程。绝大部分的工作会变得以结果为导向。</p>

<p>以编程为例，在AI时代下，世界上的程序必然会大量涌现，但与此同时，程序员的数量却在急剧减少。AI使编程的过程极大地简化，但编程的结果—程序本身在全球范围内仍有巨大的需求。</p>

<p>即使在大公司纷纷裁员的背景下，这依然是程序员的机会！</p>

<p>AI无疑对公司的组织架构产生了革命性的影响。现在，大公司的层级结构臃肿，人员构成复杂，但这种组织架构已经足够成熟。底层员工的分工合作，使得价值在向上传递的过程中不断增值。但随着AI参与到劳动生产中，不仅基层工作的过程大幅缩短，高管的管理手段也有所改进。无论在策略层面还是执行层面，高级管理者的能力都被AI这个放大器所增强。那么，大公司的架构扁平化就成了必然。</p>

<p>大公司原本的体量优势，在AI时代反而变成了劣势。在大公司努力转型的阶段，很难避免陷入创新者的窘境。而小公司、小团队反而有了更多的创新优势。</p>

<h1 id="7">7</h1>
<p>AI时代刚刚开始，程序员目前在职场上的“垃圾时间”，也可以是创业的准备期。程序员职业生涯所积累的经验和直觉，与AI天然契合。AI工具在程序员手中可以发挥巨大的价值。如果与AI密切合作，实现成百上千倍的效率提升，那么由一两个人组成的小团队对抗大公司的某个部门，完全是可能的。毕竟，小公司从来不是与整个大公司竞争，而是与大公司某个部门的一群特定的人竞争。</p>

<p>程序员的逻辑思维强，擅长将任务工程化，制定解决方案，有自动化和效率提升意识，懂得产品迭代的概念，熟悉数据库和数据结构，并且有开放的学习心态。更重要的是，他们具备最容易被忽略的编码能力。这些都是AI时代创业者所需要的素质。</p>

<p>AI+编程、AI+写作、AI+电商、AI+教育、AI+艺术、AI+广告、AI+社交等领域，都是程序员可以尝试的创业方向。</p>

<p>AI在版权、专利方面的影响，以及在跨语种信息获取和交流上的进步，让中国的创业者在全球范围内发现机会。我强烈建议大家将目光放到全球，而不是止步于中国，从国际市场中寻找机会。AI特别擅长基层工作，这迫使我们必须站在更高的视角看待问题。我们向AI发送指令，更像是管理者对待自己的员工，我们则抽身出来，从更高的维度思考问题。</p>

<p>记住，你创业所对抗的也只是大公司的一小部分人，他们真的不见得比你优秀。</p>

<h1 id="8">8</h1>
<p>当然，不是所有的程序员都适合创业。</p>

<p>都说劝人创业，天打雷劈。创业可能有巨大的回报，但也伴随着巨大的风险。我想很多人是无法接受这种情景，自己点一份外卖放桌子上，想起它来吃的时候，它已经馊了。相比之下，996的工作简直是福报。所以，如果你选择珍惜眼前的安稳生活，我赞扬你是真正的聪明人，有大智慧。</p>

<p>无论你是选择转型，还是继续在小公司工作，我依然有一些建议，希望可以帮到你。</p>

<p>第一，靠近AI。</p>

<p>虽然我们看不清未来AI的世界是怎样的，但自AI诞生的那一刻起，我们就无法摆脱它了。与其对抗它的影响，不如让它赋予我们力量。而且，任何对AI技巧的掌握，在未来世界一定是非常容易迁移的技能，掌握它的性价比是非常高的。</p>

<p>第二，远离劳动密集型产业。</p>

<p>人越多，人就越廉价。是的，这句话有着多层次的含义。我们应该选择人均资源丰富的行业，去人均资源丰富的地方，哪怕是农村。人的生存只需要阳光、空气、水和食物。</p>

<p>第三，向内求。</p>

<p>向内求不是逃避，而是趋吉避凶的智慧。我们降低预期，就可以解决大部分的痛苦，保持自己的情绪稳定是为了积蓄力量，保留体力，面对未来。生存是当前经济周期下的重中之重，赚确定性高的钱，同样是一种优秀的品格。</p>

<p>第四，健康教育。</p>

<p>现在大学的知识更新速度和实际的技术变革速度相比，产生了严重的滞后。几年前还大火的计算机专业，目前来看已经出现了就业困难的情况。技术变革是以月甚至周为单位快速迭代，跨越4年的周期去预测未来的行业热度显然是不现实的。但我们在子女的教育重点上，可以从学术转移到孩子的身心健康上。未来，强健的体魄，完整的人格是更具竞争力的。</p>

<p>除了健康，学习英语、法语、日语、德语等语言可能会有更高的价值。未来，人与人的交流可能是更核心的竞争力，跨语言文化的思考方式会让孩子在全球范围内拥有更多的机会。这个观点的细节暂且不表。</p>

<p>另外，分享我自己的心得：人比钱重要。这几年我们经历过的几件大事，让我们反思。疫情让你思考健康的意义，房子让你思考财富的意义，裁员让你思考工作的意义。你一定有所心得。</p>

<h1 id="9">9</h1>
<p>个人力量无法对抗时代的必然，但在更高的维度上可以。</p>

<p>在《三体》中，人类想象过无数种对抗外星文明的方式，太空战舰、核武器。但三体人压根没想过和人类比拼力量。他们向地球发射二向箔，从维度上对地球进行降维打击。他们压根不和我们在同一个维度上竞争。</p>

<p>AI时代也是如此，普通人的命运已经不在自己掌控的维度了。</p>

<p>在出租车领域，如果允许无人出租车与人类司机竞争，那就产生了社会结构性的不平等。虽然无人出租看似解放了劳动力，但它们的核心受益者并不是AI，而是拥有这项AI技术的人。无论出租车司机付出多少努力，在开车这个维度上，AI能做到的都是人类无法企及的。这种局势，如果不引入更高维度的外力，是无解的。</p>

<p>这些硅基生命（无人出租车）行驶的马路，是碳基生命（人类）依法纳税建造的。它们侵占着社会资源，增加了交通的维护成本，却无需承担纳税义务。这对普通人来说是不公平的。因此，我个人建议引入“AI纳税人”概念，让AI承担纳税义务。社会进步的本质应该是让技术的红利为全社会服务，而不是让AI加速资源向少数人的流动。</p>

<p>在编程领域，如果允许AI和程序员竞争，那么可以肯定，编程不只停留在现在的serverless，还会向codeless、humanless发展，最终程序员都变成了homeless（玩笑）。</p>

<p>当然，在更高的维度上，我想决策者们正在试着寻找一个平衡点。在瞬息万变的时代洪流中，高维度的参数调整作用于低维世界，需要一定的时间，让子弹飞一会儿。</p>

<h1 id="10">10</h1>
<p>AI影响下的未来世界尚未可知。 在机器学习、深度学习兴起的时候，大家一致认为创意、美术、设计等工作是很难被AI取代的。然而，随着AI的成熟，人们发现AI也可以胜任这些工作。AI的推动下，编程进入了程序写程序的高效循环，程序员的职业生涯步入了“垃圾时间”。不过，虽然这段时期是程序员生涯的终结期，但也是新的职业生涯的准备期。我们利用这段时间为下一次起跑积蓄力量。</p>

<p>我们很难说清未来的AI世界是怎样的，但可以肯定，这个世界正飞速变化。我们保持开放的心态，积极地面对这个世界，终有一天会从迷雾中走出来。</p>

<p>如果AI可以让我们从繁忙的工作中抽身出来，我们是否可以用更多的时间来思考我们人生的追求、生命的意义？</p>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="AI" /><category term="ChatGPT" /><category term="程序员的垃圾时间" /><category term="OpenAI" /><category term="GPT" /><summary type="html"><![CDATA[6 程序员正处于这场技术革命的风暴中心，面临着被取代的命运。然而，这场技术革命的过渡期，也是程序员们的黄金转型期。因为程序员是距离这个时代变革最近的一群人。程序员的技术背景、编程能力、逻辑思维，都和AI技术天生契合。那些可以持续学习、快速适应并且创新的人，将能够在AI主导的未来中占据优势。 可以肯定的是，未来人们和AI的关系会越来越紧密。AI的诞生使得世界的工作效率进入了一个更加高速的时代。换句话说，各种工作的过程耗时会极大地缩短，我们可以更快速地拿到结果，省去人工的中间过程。绝大部分的工作会变得以结果为导向。 以编程为例，在AI时代下，世界上的程序必然会大量涌现，但与此同时，程序员的数量却在急剧减少。AI使编程的过程极大地简化，但编程的结果—程序本身在全球范围内仍有巨大的需求。 即使在大公司纷纷裁员的背景下，这依然是程序员的机会！ AI无疑对公司的组织架构产生了革命性的影响。现在，大公司的层级结构臃肿，人员构成复杂，但这种组织架构已经足够成熟。底层员工的分工合作，使得价值在向上传递的过程中不断增值。但随着AI参与到劳动生产中，不仅基层工作的过程大幅缩短，高管的管理手段也有所改进。无论在策略层面还是执行层面，高级管理者的能力都被AI这个放大器所增强。那么，大公司的架构扁平化就成了必然。 大公司原本的体量优势，在AI时代反而变成了劣势。在大公司努力转型的阶段，很难避免陷入创新者的窘境。而小公司、小团队反而有了更多的创新优势。 7 AI时代刚刚开始，程序员目前在职场上的“垃圾时间”，也可以是创业的准备期。程序员职业生涯所积累的经验和直觉，与AI天然契合。AI工具在程序员手中可以发挥巨大的价值。如果与AI密切合作，实现成百上千倍的效率提升，那么由一两个人组成的小团队对抗大公司的某个部门，完全是可能的。毕竟，小公司从来不是与整个大公司竞争，而是与大公司某个部门的一群特定的人竞争。 程序员的逻辑思维强，擅长将任务工程化，制定解决方案，有自动化和效率提升意识，懂得产品迭代的概念，熟悉数据库和数据结构，并且有开放的学习心态。更重要的是，他们具备最容易被忽略的编码能力。这些都是AI时代创业者所需要的素质。 AI+编程、AI+写作、AI+电商、AI+教育、AI+艺术、AI+广告、AI+社交等领域，都是程序员可以尝试的创业方向。 AI在版权、专利方面的影响，以及在跨语种信息获取和交流上的进步，让中国的创业者在全球范围内发现机会。我强烈建议大家将目光放到全球，而不是止步于中国，从国际市场中寻找机会。AI特别擅长基层工作，这迫使我们必须站在更高的视角看待问题。我们向AI发送指令，更像是管理者对待自己的员工，我们则抽身出来，从更高的维度思考问题。 记住，你创业所对抗的也只是大公司的一小部分人，他们真的不见得比你优秀。 8 当然，不是所有的程序员都适合创业。 都说劝人创业，天打雷劈。创业可能有巨大的回报，但也伴随着巨大的风险。我想很多人是无法接受这种情景，自己点一份外卖放桌子上，想起它来吃的时候，它已经馊了。相比之下，996的工作简直是福报。所以，如果你选择珍惜眼前的安稳生活，我赞扬你是真正的聪明人，有大智慧。 无论你是选择转型，还是继续在小公司工作，我依然有一些建议，希望可以帮到你。 第一，靠近AI。 虽然我们看不清未来AI的世界是怎样的，但自AI诞生的那一刻起，我们就无法摆脱它了。与其对抗它的影响，不如让它赋予我们力量。而且，任何对AI技巧的掌握，在未来世界一定是非常容易迁移的技能，掌握它的性价比是非常高的。 第二，远离劳动密集型产业。 人越多，人就越廉价。是的，这句话有着多层次的含义。我们应该选择人均资源丰富的行业，去人均资源丰富的地方，哪怕是农村。人的生存只需要阳光、空气、水和食物。 第三，向内求。 向内求不是逃避，而是趋吉避凶的智慧。我们降低预期，就可以解决大部分的痛苦，保持自己的情绪稳定是为了积蓄力量，保留体力，面对未来。生存是当前经济周期下的重中之重，赚确定性高的钱，同样是一种优秀的品格。 第四，健康教育。 现在大学的知识更新速度和实际的技术变革速度相比，产生了严重的滞后。几年前还大火的计算机专业，目前来看已经出现了就业困难的情况。技术变革是以月甚至周为单位快速迭代，跨越4年的周期去预测未来的行业热度显然是不现实的。但我们在子女的教育重点上，可以从学术转移到孩子的身心健康上。未来，强健的体魄，完整的人格是更具竞争力的。 除了健康，学习英语、法语、日语、德语等语言可能会有更高的价值。未来，人与人的交流可能是更核心的竞争力，跨语言文化的思考方式会让孩子在全球范围内拥有更多的机会。这个观点的细节暂且不表。 另外，分享我自己的心得：人比钱重要。这几年我们经历过的几件大事，让我们反思。疫情让你思考健康的意义，房子让你思考财富的意义，裁员让你思考工作的意义。你一定有所心得。 9 个人力量无法对抗时代的必然，但在更高的维度上可以。 在《三体》中，人类想象过无数种对抗外星文明的方式，太空战舰、核武器。但三体人压根没想过和人类比拼力量。他们向地球发射二向箔，从维度上对地球进行降维打击。他们压根不和我们在同一个维度上竞争。 AI时代也是如此，普通人的命运已经不在自己掌控的维度了。 在出租车领域，如果允许无人出租车与人类司机竞争，那就产生了社会结构性的不平等。虽然无人出租看似解放了劳动力，但它们的核心受益者并不是AI，而是拥有这项AI技术的人。无论出租车司机付出多少努力，在开车这个维度上，AI能做到的都是人类无法企及的。这种局势，如果不引入更高维度的外力，是无解的。 这些硅基生命（无人出租车）行驶的马路，是碳基生命（人类）依法纳税建造的。它们侵占着社会资源，增加了交通的维护成本，却无需承担纳税义务。这对普通人来说是不公平的。因此，我个人建议引入“AI纳税人”概念，让AI承担纳税义务。社会进步的本质应该是让技术的红利为全社会服务，而不是让AI加速资源向少数人的流动。 在编程领域，如果允许AI和程序员竞争，那么可以肯定，编程不只停留在现在的serverless，还会向codeless、humanless发展，最终程序员都变成了homeless（玩笑）。 当然，在更高的维度上，我想决策者们正在试着寻找一个平衡点。在瞬息万变的时代洪流中，高维度的参数调整作用于低维世界，需要一定的时间，让子弹飞一会儿。 10 AI影响下的未来世界尚未可知。 在机器学习、深度学习兴起的时候，大家一致认为创意、美术、设计等工作是很难被AI取代的。然而，随着AI的成熟，人们发现AI也可以胜任这些工作。AI的推动下，编程进入了程序写程序的高效循环，程序员的职业生涯步入了“垃圾时间”。不过，虽然这段时期是程序员生涯的终结期，但也是新的职业生涯的准备期。我们利用这段时间为下一次起跑积蓄力量。 我们很难说清未来的AI世界是怎样的，但可以肯定，这个世界正飞速变化。我们保持开放的心态，积极地面对这个世界，终有一天会从迷雾中走出来。 如果AI可以让我们从繁忙的工作中抽身出来，我们是否可以用更多的时间来思考我们人生的追求、生命的意义？]]></summary></entry><entry><title type="html">GPT最佳实践：五分钟打造你自己的GPT</title><link href="/2023/11/10/GPTs-generate-your-own-gpt-in-5-mins.html" rel="alternate" type="text/html" title="GPT最佳实践：五分钟打造你自己的GPT" /><published>2023-11-10T00:00:00+00:00</published><updated>2023-11-10T00:00:00+00:00</updated><id>/2023/11/10/GPTs-generate-your-own-gpt-in-5-mins</id><content type="html" xml:base="/2023/11/10/GPTs-generate-your-own-gpt-in-5-mins.html"><![CDATA[<p>前几天OpenAI的My GPTs栏目还是灰色的，就在今天已经开放使用了。有幸第一时间体验了一把生成自己的GPT，效果着实惊艳！！！我打造的GPT模型我会放到文章末尾，大家感兴趣也可以自己体验一下。
<img src="/assets/images/20231110/image.png" alt="Alt text" /></p>

<h1 id="打造自己的gpt模型">打造自己的GPT模型</h1>
<p>点击Create a GPT，可以进入到下面这个界面，左侧是一个GPT Builder的对话框，右边是你随时更改GPT配置后的预览。
<img src="/assets/images/20231110/image-1.png" alt="Alt text" /></p>

<p>点进去Configure配置，可以看到具体的头像、名称、描述、说明、对话引导、知识库、可选择的模型能力（是否打开联网、Dall·E图像生成、代码解释器）以及Actions这个是模型调用API的能力。
<img src="/assets/images/20231110/img5.png" alt="Alt text" /></p>

<p>我上传了我所有的mardown文章内容，然后告诉模型，我要一个博客写作GPT帮我写技术文章。</p>
<h1 id="gpt-builder">GPT builder</h1>
<p>然后，我让GPT Builder给我一些建议，他给我罗列了一些，他告诉我可以针对我的需求加入合适的用户交互，要突出技术专长，要经常更新（做不到），可以加入我自己的头像，最重要的是，他说他可以fine-tuning模型。这点我非常惊讶，因为fine-tuning是真正的让GPT背后的模型适配你的数据，也就是我创造的GPT需求，它需要根据数据反向传播影响模型参数的，而fine-tuning的成本也是不便宜的。<br />
我试了试，它真的根据我的需求调整了模型。
<img src="/assets/images/20231110/image-2.png" alt="Alt text" /></p>

<h1 id="发布">发布</h1>
<p>发布时可以选择公开发布，它提示你公开的GPT模型可能会出现在未来GPT商店里，足以看出openAI对整个模型生态的野心。</p>

<p><img src="/assets/images/20231110/image-3.png" alt="Alt text" /></p>
<h1 id="实践">实践</h1>
<p>我让他根据我以往的写作风格写一篇技术文章，它选择了<a href="https://blog.caiyongji.com/2023/11/10/gpt-sample.html">《深入理解Python异步编程：从原理到实践》</a>我已经放到了我的个人博客上，大家可以自己看看写的怎么样。<br />
甚至，我让他把文章改成markdown格式，并提供一个下载链接，它也做！到！了！
<img src="/assets/images/20231110/image-4.png" alt="Alt text" /></p>

<h1 id="caibloggpt">CaiBlogGPT</h1>
<p>总的来说，这意味着老板们想要啥可以自己打造了，哪有什么技术壁垒。我的理解是，谁有数据，谁就有模型能力，技术层面，已经是傻瓜式了。 机器学习已经毫无意义，打造自己的knowledge base（知识库）吧。那么谁有整合这些数据的能力呢？这个赢家通吃，强者恒强的世界呀！<br />
这就是我生成自己的GPT的体验。大家可以试试我用5分钟打造的gpt： <a href="https://chat.openai.com/g/g-ARKi8yoKs-caibloggpt">https://chat.openai.com/g/g-ARKi8yoKs-caibloggpt</a>。</p>

<p>我从来只原创，也不水文章（咳咳），所以几年没更新。我早已财务自由（并没有），下次再见。</p>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="GPT" /><category term="ChatGPT" /><category term="OpenAI" /><summary type="html"><![CDATA[前几天OpenAI的My GPTs栏目还是灰色的，就在今天已经开放使用了。有幸第一时间体验了一把生成自己的GPT，效果着实惊艳！！！我打造的GPT模型我会放到文章末尾，大家感兴趣也可以自己体验一下。 打造自己的GPT模型 点击Create a GPT，可以进入到下面这个界面，左侧是一个GPT Builder的对话框，右边是你随时更改GPT配置后的预览。 点进去Configure配置，可以看到具体的头像、名称、描述、说明、对话引导、知识库、可选择的模型能力（是否打开联网、Dall·E图像生成、代码解释器）以及Actions这个是模型调用API的能力。 我上传了我所有的mardown文章内容，然后告诉模型，我要一个博客写作GPT帮我写技术文章。 GPT builder 然后，我让GPT Builder给我一些建议，他给我罗列了一些，他告诉我可以针对我的需求加入合适的用户交互，要突出技术专长，要经常更新（做不到），可以加入我自己的头像，最重要的是，他说他可以fine-tuning模型。这点我非常惊讶，因为fine-tuning是真正的让GPT背后的模型适配你的数据，也就是我创造的GPT需求，它需要根据数据反向传播影响模型参数的，而fine-tuning的成本也是不便宜的。 我试了试，它真的根据我的需求调整了模型。 发布 发布时可以选择公开发布，它提示你公开的GPT模型可能会出现在未来GPT商店里，足以看出openAI对整个模型生态的野心。 实践 我让他根据我以往的写作风格写一篇技术文章，它选择了《深入理解Python异步编程：从原理到实践》我已经放到了我的个人博客上，大家可以自己看看写的怎么样。 甚至，我让他把文章改成markdown格式，并提供一个下载链接，它也做！到！了！ CaiBlogGPT 总的来说，这意味着老板们想要啥可以自己打造了，哪有什么技术壁垒。我的理解是，谁有数据，谁就有模型能力，技术层面，已经是傻瓜式了。 机器学习已经毫无意义，打造自己的knowledge base（知识库）吧。那么谁有整合这些数据的能力呢？这个赢家通吃，强者恒强的世界呀！ 这就是我生成自己的GPT的体验。大家可以试试我用5分钟打造的gpt： https://chat.openai.com/g/g-ARKi8yoKs-caibloggpt。 我从来只原创，也不水文章（咳咳），所以几年没更新。我早已财务自由（并没有），下次再见。]]></summary></entry><entry><title type="html">(Sample)深入理解Python异步编程：从原理到实践</title><link href="/2023/11/10/gpt-sample.html" rel="alternate" type="text/html" title="(Sample)深入理解Python异步编程：从原理到实践" /><published>2023-11-10T00:00:00+00:00</published><updated>2023-11-10T00:00:00+00:00</updated><id>/2023/11/10/gpt-sample</id><content type="html" xml:base="/2023/11/10/gpt-sample.html"><![CDATA[<h1 id="深入理解python异步编程从原理到实践">深入理解Python异步编程：从原理到实践</h1>

<p>在当今快速发展的技术世界里，Python异步编程已经成为了一个热门话题。随着应用程序和服务越来越依赖于网络通信和I/O操作，有效地管理这些操作变得尤为重要。本文将深入探索Python中的异步编程，从基本原理到实际应用，让你全面了解这一强大工具。</p>

<h2 id="一异步编程的基本原理">一、异步编程的基本原理</h2>

<p>异步编程是一种编程范式，它允许程序在等待一个长时间运行的任务（如I/O操作）完成时继续执行其他任务。这与传统的同步编程形成对比，后者在执行长时间运行的任务时会阻塞程序的其余部分。</p>

<p>在Python中，异步编程主要依赖于<code class="language-plaintext highlighter-rouge">asyncio</code>库。<code class="language-plaintext highlighter-rouge">asyncio</code>是Python用于编写并发代码的库，它使用<code class="language-plaintext highlighter-rouge">async</code>和<code class="language-plaintext highlighter-rouge">await</code>语法进行异步编程。使用<code class="language-plaintext highlighter-rouge">asyncio</code>，你可以编写单线程并发代码来执行多个任务，这些任务可以在等待I/O操作或长时间运行的任务完成时被挂起。</p>

<h2 id="二异步编程的优势">二、异步编程的优势</h2>

<p>异步编程的主要优势在于其高效的资源利用。在传统的同步应用中，程序在执行例如网络请求或磁盘读写操作时会被阻塞，从而导致CPU时间的浪费。而在异步应用中，当一个任务被阻塞时，程序可以切换到其他任务，从而使CPU始终保持忙碌状态，提高了程序的整体效率。</p>

<h2 id="三python中的异步编程实践">三、Python中的异步编程实践</h2>

<p>要开始使用Python进行异步编程，首先需要理解<code class="language-plaintext highlighter-rouge">async</code>和<code class="language-plaintext highlighter-rouge">await</code>关键字的用法。<code class="language-plaintext highlighter-rouge">async</code>定义了一个异步函数，而<code class="language-plaintext highlighter-rouge">await</code>用于挂起异步函数的执行，直到相关的操作完成。</p>

<h3 id="示例异步http请求">示例：异步HTTP请求</h3>

<p>以下是一个使用<code class="language-plaintext highlighter-rouge">asyncio</code>和<code class="language-plaintext highlighter-rouge">aiohttp</code>库进行异步HTTP请求的简单示例：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">asyncio</span>
<span class="kn">import</span> <span class="n">aiohttp</span>

<span class="k">async</span> <span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">url</span><span class="p">):</span>
    <span class="k">async</span> <span class="k">with</span> <span class="n">session</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
        <span class="k">return</span> <span class="k">await</span> <span class="n">response</span><span class="p">.</span><span class="nf">text</span><span class="p">()</span>

<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="k">async</span> <span class="k">with</span> <span class="n">aiohttp</span><span class="p">.</span><span class="nc">ClientSession</span><span class="p">()</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
        <span class="n">html</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="sh">'</span><span class="s">http://python.org</span><span class="sh">'</span><span class="p">)</span>
        <span class="nf">print</span><span class="p">(</span><span class="n">html</span><span class="p">)</span>

<span class="n">asyncio</span><span class="p">.</span><span class="nf">run</span><span class="p">(</span><span class="nf">main</span><span class="p">())</span>
</code></pre></div></div>

<p>在这个示例中，<code class="language-plaintext highlighter-rouge">fetch</code>函数是一个异步函数，它获取一个网页的内容并返回。<code class="language-plaintext highlighter-rouge">main</code>函数则创建一个<code class="language-plaintext highlighter-rouge">aiohttp</code>会话，并调用<code class="language-plaintext highlighter-rouge">fetch</code>函数。注意<code class="language-plaintext highlighter-rouge">fetch</code>和<code class="language-plaintext highlighter-rouge">main</code>函数前的<code class="language-plaintext highlighter-rouge">async</code>关键字，以及它们内部<code class="language-plaintext highlighter-rouge">await</code>语句的使用。</p>

<h2 id="四结论">四、结论</h2>

<p>异步编程是Python中一个强大而有用的工具，特别是在处理大量的I/O密集型任务时。通过有效利用程序等待时间，异步编程能显著提高应用程序的性能和响应能力。虽然它可能在一开始看起来有些复杂，但一旦掌握了异步编程的基本原理和实践，你就能写出更高效、更优化的Python代码。</p>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="GPT" /><category term="ChatGPT" /><category term="OpenAI" /><category term="Python" /><summary type="html"><![CDATA[深入理解Python异步编程：从原理到实践 在当今快速发展的技术世界里，Python异步编程已经成为了一个热门话题。随着应用程序和服务越来越依赖于网络通信和I/O操作，有效地管理这些操作变得尤为重要。本文将深入探索Python中的异步编程，从基本原理到实际应用，让你全面了解这一强大工具。 一、异步编程的基本原理 异步编程是一种编程范式，它允许程序在等待一个长时间运行的任务（如I/O操作）完成时继续执行其他任务。这与传统的同步编程形成对比，后者在执行长时间运行的任务时会阻塞程序的其余部分。 在Python中，异步编程主要依赖于asyncio库。asyncio是Python用于编写并发代码的库，它使用async和await语法进行异步编程。使用asyncio，你可以编写单线程并发代码来执行多个任务，这些任务可以在等待I/O操作或长时间运行的任务完成时被挂起。 二、异步编程的优势 异步编程的主要优势在于其高效的资源利用。在传统的同步应用中，程序在执行例如网络请求或磁盘读写操作时会被阻塞，从而导致CPU时间的浪费。而在异步应用中，当一个任务被阻塞时，程序可以切换到其他任务，从而使CPU始终保持忙碌状态，提高了程序的整体效率。 三、Python中的异步编程实践 要开始使用Python进行异步编程，首先需要理解async和await关键字的用法。async定义了一个异步函数，而await用于挂起异步函数的执行，直到相关的操作完成。 示例：异步HTTP请求 以下是一个使用asyncio和aiohttp库进行异步HTTP请求的简单示例： import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'http://python.org') print(html) asyncio.run(main()) 在这个示例中，fetch函数是一个异步函数，它获取一个网页的内容并返回。main函数则创建一个aiohttp会话，并调用fetch函数。注意fetch和main函数前的async关键字，以及它们内部await语句的使用。 四、结论 异步编程是Python中一个强大而有用的工具，特别是在处理大量的I/O密集型任务时。通过有效利用程序等待时间，异步编程能显著提高应用程序的性能和响应能力。虽然它可能在一开始看起来有些复杂，但一旦掌握了异步编程的基本原理和实践，你就能写出更高效、更优化的Python代码。]]></summary></entry><entry><title type="html">如何对抗信息茧房？</title><link href="/2021/07/29/how-to-confront-info-cocoon.html" rel="alternate" type="text/html" title="如何对抗信息茧房？" /><published>2021-07-29T00:00:00+00:00</published><updated>2021-07-29T00:00:00+00:00</updated><id>/2021/07/29/how-to-confront-info-cocoon</id><content type="html" xml:base="/2021/07/29/how-to-confront-info-cocoon.html"><![CDATA[<p><em>首先声明：本文表达观点，提供一种思考问题的角度，并非严谨的论述论证。为了直击问题本质，高效陈述观点，行文过程中出现的不严谨之处皆是作者表述方式问题，与观点本身无关。无论作者表述多么拙劣，都希望读者可以考虑观点的合理行，对其进行深度的思考。所有“另当别论的个例”皆另当别论，不在本文简洁表述的范围内。</em></p>

<p>人们对信息的需求并非全方位的，大家只注意自己选择的东西和使自己愉悦的领域，久而久之，会将自身桎梏于蚕茧一般的“茧房”中，这就是信息茧房(Information Cocoons)。</p>

<h2 id="一算法驯化">一、算法驯化</h2>

<p>你看到什么你就是什么？<br />
不！<br />
资本想玩皇帝的新装这套，又是道德绑架，又是洞穿人性的。<br />
根据熵增定律，任何系统的混乱程度都在不断增大。这里的熵就是指混乱度，就是说，啥事都是学坏容易，学好难。如果不加约束，互联网上的每个人都是往低俗、劣质发展的。<br />
我从来都不会高估人性，当然我对人性也有相当的自信。简单与性感，质朴与高调，逻辑与搞笑，节俭与时髦，枯燥与新奇，等待和现在就要……   当人们需要在两者之间做出选择时，大部分人会选择后者。与其投入、等待，在许久之后获得回报和立刻获得愉悦之间，人们更愿意选择容易而非困难，这是人性。<br />
当人们沉浸在推荐算法提供的短期的高度满意的环境中，人们很难感知到自身的信息受限。这时，如果只给你提供有限的选择（比如上滑下滑），那么茧房就形成了。这就是为什么你搭上了某类信息的边，并稍微表现出一点兴趣，你就会陷入到某类信息的漩涡中，直到你成为某个消费品类的客户。</p>

<h2 id="二利益驱动">二、利益驱动</h2>

<p>信息茧房里的人最终会沉迷于那些有趣的、低成本的、使人满足的低俗的娱乐内容中。人们就像是含着奶嘴的巨婴一样，又有生产力，又遵纪守法，又节约资源，又有消费能力，除了费一点电以外，人们消耗的资源降低了。<br />
可是对个人而言，它没有好处。看似什么都直到，只是“没用的知识增加了”。看似见识过人间百态，可又不那么真实，像是表演。看似每天都有收获，可总感觉很空虚。看似了解了世界的大，却连卧室都没走出半步……</p>

<h2 id="三拓展渠道">三、拓展渠道</h2>

<p>摆脱信息茧房的重要手段是，增加自主性。不要推荐，自己主动搜索。你要知道，现在互联网环境的信噪比是越来越低的，有效信息夹杂在大量的垃圾信息中。随着众多论坛、社区向下沉市场扩大，形成了劣币驱逐良币的趋势。懂得人不说话，不懂的人声音大。<br />
因此，我们获取信息的渠道不能只靠网络。<br />
大家可以通过书籍、现实朋友、展会、论坛、峰会等渠道获取信息。没事买一些杂书看一看，自身有能力学一门新的语言又会打开一个不同的新世界。同一个世界，不同的文化竟然讲述着不同的故事。</p>

<h2 id="四总结">四、总结</h2>

<p>对抗信息茧房的手段：<br />
    1. 拓展信息获取渠道，避免让互联网成为你唯一获取信息的渠道。
    2. 增加获取信息的随机性，比如多买些杂书看。</p>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="蔡永吉" /><category term="程序员" /><summary type="html"><![CDATA[首先声明：本文表达观点，提供一种思考问题的角度，并非严谨的论述论证。为了直击问题本质，高效陈述观点，行文过程中出现的不严谨之处皆是作者表述方式问题，与观点本身无关。无论作者表述多么拙劣，都希望读者可以考虑观点的合理行，对其进行深度的思考。所有“另当别论的个例”皆另当别论，不在本文简洁表述的范围内。 人们对信息的需求并非全方位的，大家只注意自己选择的东西和使自己愉悦的领域，久而久之，会将自身桎梏于蚕茧一般的“茧房”中，这就是信息茧房(Information Cocoons)。 一、算法驯化 你看到什么你就是什么？ 不！ 资本想玩皇帝的新装这套，又是道德绑架，又是洞穿人性的。 根据熵增定律，任何系统的混乱程度都在不断增大。这里的熵就是指混乱度，就是说，啥事都是学坏容易，学好难。如果不加约束，互联网上的每个人都是往低俗、劣质发展的。 我从来都不会高估人性，当然我对人性也有相当的自信。简单与性感，质朴与高调，逻辑与搞笑，节俭与时髦，枯燥与新奇，等待和现在就要…… 当人们需要在两者之间做出选择时，大部分人会选择后者。与其投入、等待，在许久之后获得回报和立刻获得愉悦之间，人们更愿意选择容易而非困难，这是人性。 当人们沉浸在推荐算法提供的短期的高度满意的环境中，人们很难感知到自身的信息受限。这时，如果只给你提供有限的选择（比如上滑下滑），那么茧房就形成了。这就是为什么你搭上了某类信息的边，并稍微表现出一点兴趣，你就会陷入到某类信息的漩涡中，直到你成为某个消费品类的客户。 二、利益驱动 信息茧房里的人最终会沉迷于那些有趣的、低成本的、使人满足的低俗的娱乐内容中。人们就像是含着奶嘴的巨婴一样，又有生产力，又遵纪守法，又节约资源，又有消费能力，除了费一点电以外，人们消耗的资源降低了。 可是对个人而言，它没有好处。看似什么都直到，只是“没用的知识增加了”。看似见识过人间百态，可又不那么真实，像是表演。看似每天都有收获，可总感觉很空虚。看似了解了世界的大，却连卧室都没走出半步…… 三、拓展渠道 摆脱信息茧房的重要手段是，增加自主性。不要推荐，自己主动搜索。你要知道，现在互联网环境的信噪比是越来越低的，有效信息夹杂在大量的垃圾信息中。随着众多论坛、社区向下沉市场扩大，形成了劣币驱逐良币的趋势。懂得人不说话，不懂的人声音大。 因此，我们获取信息的渠道不能只靠网络。 大家可以通过书籍、现实朋友、展会、论坛、峰会等渠道获取信息。没事买一些杂书看一看，自身有能力学一门新的语言又会打开一个不同的新世界。同一个世界，不同的文化竟然讲述着不同的故事。 四、总结 对抗信息茧房的手段： 1. 拓展信息获取渠道，避免让互联网成为你唯一获取信息的渠道。 2. 增加获取信息的随机性，比如多买些杂书看。]]></summary></entry><entry><title type="html">机器学习(六)：通俗易懂无监督学习K-Means聚类算法及代码实践</title><link href="/2021/03/20/machine-learning-6.html" rel="alternate" type="text/html" title="机器学习(六)：通俗易懂无监督学习K-Means聚类算法及代码实践" /><published>2021-03-20T00:00:00+00:00</published><updated>2021-03-20T00:00:00+00:00</updated><id>/2021/03/20/machine-learning-6</id><content type="html" xml:base="/2021/03/20/machine-learning-6.html"><![CDATA[<blockquote>
  <p>K-Means是一种无监督学习方法，用于将无标签的数据集进行聚类。其中K指集群的数量，Means表示寻找集群中心点的手段。</p>
</blockquote>

<h1 id="一-无监督学习-k-means">一、 无监督学习 K-Means</h1>

<p>贴标签是需要花钱的。<br />
所以人们研究处理无标签数据集的方法。（笔者狭隘了）<br />
面对无标签的数据集，我们期望从数据中找出一定的规律。一种最简单也最快速的聚类算法应运而生—K-Means。<br />
它的核心思想很简单：物以类聚。</p>

<p><strong>用直白的话简单解释它的算法执行过程如下：</strong></p>
<ol>
  <li>随便选择K个中心点（大哥）。</li>
  <li>把距离它足够近的数据（小弟）吸纳为成员，聚成K个集群（组织）。</li>
  <li>各集群（组织）内部重新选择中心点（大哥），选择标准是按照距离取<strong>均值</strong>作为中心点（大哥）。</li>
  <li>重复2、3步骤直到收敛（组织成员相对稳定）。</li>
</ol>

<p>这就是<del>黑涩会形成</del>聚类的过程。</p>

<h1 id="二-k-means代码实践">二、 K-Means代码实践</h1>

<h2 id="21-鸢尾花数据集">2.1 鸢尾花数据集</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="n">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>

<span class="c1"># 大家不用在意这个域名
</span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nf">read_csv</span><span class="p">(</span><span class="sh">'</span><span class="s">https://blog.caiyongji.com/assets/iris.csv</span><span class="sh">'</span><span class="p">)</span>
<span class="n">sns</span><span class="p">.</span><span class="nf">scatterplot</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="sh">'</span><span class="s">petal_length</span><span class="sh">'</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="sh">'</span><span class="s">petal_width</span><span class="sh">'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">df</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="sh">'</span><span class="s">species</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>我们得到带标签的数据如下：</p>

<p><img src="/assets/images/20210320/1.png" alt="image" /></p>

<h2 id="22-k-means训练数据">2.2 K-Means训练数据</h2>

<p>我们移除数据标签，仅使用花瓣长、宽作为数据输入，并使用无监督学习方法K-Means进行训练。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">X</span> <span class="o">=</span> <span class="n">df</span><span class="p">[[</span><span class="sh">'</span><span class="s">petal_length</span><span class="sh">'</span><span class="p">,</span><span class="sh">'</span><span class="s">petal_width</span><span class="sh">'</span><span class="p">]].</span><span class="nf">to_numpy</span><span class="p">()</span> 

<span class="kn">from</span> <span class="n">sklearn.cluster</span> <span class="kn">import</span> <span class="n">KMeans</span>
<span class="n">k</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">kmeans</span> <span class="o">=</span> <span class="nc">KMeans</span><span class="p">(</span><span class="n">n_clusters</span><span class="o">=</span><span class="n">k</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">kmeans</span><span class="p">.</span><span class="nf">fit_predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">plot</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">y_pred</span><span class="o">==</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="n">y_pred</span><span class="o">==</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="sh">"</span><span class="s">ro</span><span class="sh">"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sh">"</span><span class="s">group 1</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">plot</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">y_pred</span><span class="o">==</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="n">y_pred</span><span class="o">==</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="sh">"</span><span class="s">bo</span><span class="sh">"</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="sh">"</span><span class="s">group 0</span><span class="sh">"</span><span class="p">)</span>
<span class="c1"># plt.legend(loc=2)
</span><span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
</code></pre></div></div>

<p>得到分类数据如下，我们并不知道下方数据类别分别代表什么意义。</p>

<p><img src="/assets/images/20210320/2.png" alt="image" /></p>

<p>我们将K分别取1-6的值，可得到如下图所示分类结果：</p>

<p><img src="/assets/images/20210320/3.png" alt="image" /></p>

<p>那么K值的选择有什么意义呢？我们如何选择？</p>

<h1 id="三k的选择">三、K的选择</h1>

<h2 id="31-惯性指标inertia">3.1 惯性指标（inertia）</h2>

<p>K-Means的惯性计算方式是，<strong>每个样本与最接近的集群中心点的均方距离的总和</strong>。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kmeans_per_k</span> <span class="o">=</span> <span class="p">[</span><span class="nc">KMeans</span><span class="p">(</span><span class="n">n_clusters</span><span class="o">=</span><span class="n">k</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">).</span><span class="nf">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">)]</span>

<span class="n">inertias</span> <span class="o">=</span> <span class="p">[</span><span class="n">model</span><span class="p">.</span><span class="n">inertia_</span> <span class="k">for</span> <span class="n">model</span> <span class="ow">in</span> <span class="n">kmeans_per_k</span><span class="p">]</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mf">3.5</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">plot</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="n">inertias</span><span class="p">,</span> <span class="sh">"</span><span class="s">bo-</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">xlabel</span><span class="p">(</span><span class="sh">"</span><span class="s">$k$</span><span class="sh">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">ylabel</span><span class="p">(</span><span class="sh">"</span><span class="s">Inertia</span><span class="sh">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">annotate</span><span class="p">(</span><span class="sh">'</span><span class="s">Elbow</span><span class="sh">'</span><span class="p">,</span>
             <span class="n">xy</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">inertias</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span>
             <span class="n">xytext</span><span class="o">=</span><span class="p">(</span><span class="mf">0.55</span><span class="p">,</span> <span class="mf">0.55</span><span class="p">),</span>
             <span class="n">textcoords</span><span class="o">=</span><span class="sh">'</span><span class="s">figure fraction</span><span class="sh">'</span><span class="p">,</span>
             <span class="n">fontsize</span><span class="o">=</span><span class="mi">16</span><span class="p">,</span>
             <span class="n">arrowprops</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">facecolor</span><span class="o">=</span><span class="sh">'</span><span class="s">black</span><span class="sh">'</span><span class="p">,</span> <span class="n">shrink</span><span class="o">=</span><span class="mf">0.1</span><span class="p">)</span>
            <span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">axis</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mf">8.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1300</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="/assets/images/20210320/4.png" alt="image" /></p>

<p>以上代码中<code class="language-plaintext highlighter-rouge">model.inertia_</code>即K-Means方法中的惯性指标。<br />
一般地，惯性越小模型越好，但伴随K值的增大，惯性下降的速度变的很慢，因此我们选择“肘部”的K值，作为最优的K值选择。</p>

<h2 id="32-轮廓系数指标silhouette">3.2 轮廓系数指标（silhouette）</h2>

<p>K-Means的轮廓系数计算方式是，<strong>与集群内其他样本的平均距离记为a，与外部集群样本的平均距离记为b，轮廓系数(b-a)/max(a,b)</strong>。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">sklearn.metrics</span> <span class="kn">import</span> <span class="n">silhouette_score</span>
<span class="n">silhouette_scores</span> <span class="o">=</span> <span class="p">[</span><span class="nf">silhouette_score</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">model</span><span class="p">.</span><span class="n">labels_</span><span class="p">)</span>
                     <span class="k">for</span> <span class="n">model</span> <span class="ow">in</span> <span class="n">kmeans_per_k</span><span class="p">[</span><span class="mi">1</span><span class="p">:]]</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">plot</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="n">silhouette_scores</span><span class="p">,</span> <span class="sh">"</span><span class="s">bo-</span><span class="sh">"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">xlabel</span><span class="p">(</span><span class="sh">"</span><span class="s">$k$</span><span class="sh">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">ylabel</span><span class="p">(</span><span class="sh">"</span><span class="s">Silhouette score</span><span class="sh">"</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">14</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">axis</span><span class="p">([</span><span class="mf">1.8</span><span class="p">,</span> <span class="mf">8.5</span><span class="p">,</span> <span class="mf">0.55</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="/assets/images/20210320/5.png" alt="image" /></p>

<p>以上代码中<code class="language-plaintext highlighter-rouge">silhouette_score</code>方法可取得K-Means的轮廓系数值。<br />
一般地，轮廓系数指标越大越好，我们可以看到当K为2、3时均可取得不错的聚类效果。</p>

<h1 id="四自动选择k值拓展">四、自动选择K值（拓展）</h1>

<h2 id="41-简单理解贝叶斯定理">4.1 简单理解贝叶斯定理</h2>

<p>白话解释贝叶斯：<strong>当有新的证据出现时，不确定的事情更加确信了。</strong> 这里的“确信”是指对不确定的事情的信心程度。</p>

<p>公式(可忽略)：</p>

\[P(A|B) = \frac{P(A)P(B|A)}{P(B)}\]

<table>
  <tbody>
    <tr>
      <td>其中，P(A) 表示事件A发生的概率，P(A</td>
      <td>B)表示事件B发生时事件A发生的概率。上面的公式中B就是所谓的证据。这里要注意的是，P(B)的出现让P(A</td>
      <td>B)变的更确定了，并不是说概率变高了或者变低了。概率的高或者低都是一种确定。它是一种信心程度的体现。</td>
    </tr>
  </tbody>
</table>

<h2 id="42-贝叶斯高斯混合模型">4.2 贝叶斯高斯混合模型</h2>

<p>我们使用<code class="language-plaintext highlighter-rouge">BayesianGaussianMixture</code>方法，而无需指定明确的K值。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">sklearn.mixture</span> <span class="kn">import</span> <span class="n">BayesianGaussianMixture</span>
<span class="n">bgm</span> <span class="o">=</span> <span class="nc">BayesianGaussianMixture</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">n_init</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">bgm</span><span class="p">.</span><span class="nf">fit_predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">np</span><span class="p">.</span><span class="nf">round</span><span class="p">(</span><span class="n">bgm</span><span class="p">.</span><span class="n">weights_</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</code></pre></div></div>
<p>输出：  <code class="language-plaintext highlighter-rouge">array([0.4 , 0.33, 0.27, 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ])</code></p>

<p>以上代码的执行逻辑是，初始化10个集群，不断调整有关集群数贝叶斯先验知识，来将不必要的集群权重设为0（或接近0），来确定最终K值。</p>

<h1 id="五总结系列完结">五、总结（系列完结）</h1>

<h2 id="51-机器学习系列完结">5.1 机器学习系列完结</h2>

<p><strong>我相信</strong>，截至到目前，大家对机器学习已经有了一个基本的认识。最重要的是，大家亲手实践了机器学习的代码。无论你对机器学习有多么模糊的认识，都能近距离的接触到机器学习，<strong>这一点很重要</strong>。</p>

<p>当初，我发现市面上大部分的教程都对数学有<strong>强依赖</strong>，让很多人敬而远之。我觉得，无论顶尖的科学研究还是普罗大众的教育科普都有其不可替代的巨大价值。流于表面的广泛未必没有其意义，因此我选择了<strong>舍弃严谨，贴近通俗</strong>。</p>

<p>当然，想要深耕于AI领域，数学是充分且必要的条件。如果付得起时间和机会成本，请认真且努力，绝不会辜负你。</p>

<h2 id="52-深度学习系列开始">5.2 深度学习系列开始</h2>

<p>深度学习是一台结构复杂的机器，但它的操作却相对简单。<strong>甚至</strong>，会给你比传统机器学习算法更简单的感受。<br />
我们拭目以待！感谢大家！</p>

<p>往期文章：</p>

<ul>
  <li><a href="https://mp.weixin.qq.com/s/rW59lwwTPdqCPTMDoBbjIQ">机器学习(五)：通俗易懂决策树与随机森林及代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/QqXNgfyZVwZ-Aze6XTbvng">机器学习(四)：通俗理解支持向量机SVM及代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/cEbGM0_Lrt8elfubxSF9jg">机器学习(三)：理解逻辑回归及二分类、多分类代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/_bHi-XH5ZXI4jDUzwH3xpQ">机器学习(二)：理解线性回归与梯度下降并做简单预测</a></li>
  <li><a href="https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q">机器学习(一)：5分钟理解机器学习并上手实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/5brLPnUP6sYvc-_JO7IzkA">前置机器学习（五）：30分钟掌握常用Matplotlib用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/LlLkkBfI-4s3qdVaiv7EdQ">前置机器学习（四）：一文掌握Pandas用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/U8dV8ENzzSx_VwBDdJdr_w">前置机器学习（三）：30分钟掌握常用NumPy用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/PCGThwI-YD7_hHxO35V8xw">前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/BLxyqK3CGV9yd92yGEs4XQ">前置机器学习（一）：数学符号及希腊字母</a></li>
</ul>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="机器学习" /><category term="无监督学习" /><category term="K-Means" /><category term="KMeans" /><category term="聚类算法" /><summary type="html"><![CDATA[K-Means是一种无监督学习方法，用于将无标签的数据集进行聚类。其中K指集群的数量，Means表示寻找集群中心点的手段。 一、 无监督学习 K-Means 贴标签是需要花钱的。 所以人们研究处理无标签数据集的方法。（笔者狭隘了） 面对无标签的数据集，我们期望从数据中找出一定的规律。一种最简单也最快速的聚类算法应运而生—K-Means。 它的核心思想很简单：物以类聚。 用直白的话简单解释它的算法执行过程如下： 随便选择K个中心点（大哥）。 把距离它足够近的数据（小弟）吸纳为成员，聚成K个集群（组织）。 各集群（组织）内部重新选择中心点（大哥），选择标准是按照距离取均值作为中心点（大哥）。 重复2、3步骤直到收敛（组织成员相对稳定）。 这就是黑涩会形成聚类的过程。 二、 K-Means代码实践 2.1 鸢尾花数据集 import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt # 大家不用在意这个域名 df = pd.read_csv('https://blog.caiyongji.com/assets/iris.csv') sns.scatterplot(x='petal_length',y='petal_width',data=df,hue='species') 我们得到带标签的数据如下： 2.2 K-Means训练数据 我们移除数据标签，仅使用花瓣长、宽作为数据输入，并使用无监督学习方法K-Means进行训练。 X = df[['petal_length','petal_width']].to_numpy() from sklearn.cluster import KMeans k = 2 kmeans = KMeans(n_clusters=k, random_state=42) y_pred = kmeans.fit_predict(X) plt.plot(X[y_pred==1, 0], X[y_pred==1, 1], "ro", label="group 1") plt.plot(X[y_pred==0, 0], X[y_pred==0, 1], "bo", label="group 0") # plt.legend(loc=2) plt.show() 得到分类数据如下，我们并不知道下方数据类别分别代表什么意义。 我们将K分别取1-6的值，可得到如下图所示分类结果： 那么K值的选择有什么意义呢？我们如何选择？ 三、K的选择 3.1 惯性指标（inertia） K-Means的惯性计算方式是，每个样本与最接近的集群中心点的均方距离的总和。 kmeans_per_k = [KMeans(n_clusters=k, random_state=42).fit(X) for k in range(1, 10)] inertias = [model.inertia_ for model in kmeans_per_k] plt.figure(figsize=(8, 3.5)) plt.plot(range(1, 10), inertias, "bo-") plt.xlabel("$k$", fontsize=14) plt.ylabel("Inertia", fontsize=14) plt.annotate('Elbow', xy=(2, inertias[2]), xytext=(0.55, 0.55), textcoords='figure fraction', fontsize=16, arrowprops=dict(facecolor='black', shrink=0.1) ) plt.axis([1, 8.5, 0, 1300]) plt.show() 以上代码中model.inertia_即K-Means方法中的惯性指标。 一般地，惯性越小模型越好，但伴随K值的增大，惯性下降的速度变的很慢，因此我们选择“肘部”的K值，作为最优的K值选择。 3.2 轮廓系数指标（silhouette） K-Means的轮廓系数计算方式是，与集群内其他样本的平均距离记为a，与外部集群样本的平均距离记为b，轮廓系数(b-a)/max(a,b)。 from sklearn.metrics import silhouette_score silhouette_scores = [silhouette_score(X, model.labels_) for model in kmeans_per_k[1:]] plt.figure(figsize=(8, 3)) plt.plot(range(2, 10), silhouette_scores, "bo-") plt.xlabel("$k$", fontsize=14) plt.ylabel("Silhouette score", fontsize=14) plt.axis([1.8, 8.5, 0.55, 0.8]) plt.show() 以上代码中silhouette_score方法可取得K-Means的轮廓系数值。 一般地，轮廓系数指标越大越好，我们可以看到当K为2、3时均可取得不错的聚类效果。 四、自动选择K值（拓展） 4.1 简单理解贝叶斯定理 白话解释贝叶斯：当有新的证据出现时，不确定的事情更加确信了。 这里的“确信”是指对不确定的事情的信心程度。 公式(可忽略)： \[P(A|B) = \frac{P(A)P(B|A)}{P(B)}\] 其中，P(A) 表示事件A发生的概率，P(A B)表示事件B发生时事件A发生的概率。上面的公式中B就是所谓的证据。这里要注意的是，P(B)的出现让P(A B)变的更确定了，并不是说概率变高了或者变低了。概率的高或者低都是一种确定。它是一种信心程度的体现。 4.2 贝叶斯高斯混合模型 我们使用BayesianGaussianMixture方法，而无需指定明确的K值。 from sklearn.mixture import BayesianGaussianMixture bgm = BayesianGaussianMixture(n_components=10, n_init=10, random_state=42) y_pred = bgm.fit_predict(X) np.round(bgm.weights_, 2) 输出： array([0.4 , 0.33, 0.27, 0. , 0. , 0. , 0. , 0. , 0. , 0. ]) 以上代码的执行逻辑是，初始化10个集群，不断调整有关集群数贝叶斯先验知识，来将不必要的集群权重设为0（或接近0），来确定最终K值。 五、总结（系列完结） 5.1 机器学习系列完结 我相信，截至到目前，大家对机器学习已经有了一个基本的认识。最重要的是，大家亲手实践了机器学习的代码。无论你对机器学习有多么模糊的认识，都能近距离的接触到机器学习，这一点很重要。 当初，我发现市面上大部分的教程都对数学有强依赖，让很多人敬而远之。我觉得，无论顶尖的科学研究还是普罗大众的教育科普都有其不可替代的巨大价值。流于表面的广泛未必没有其意义，因此我选择了舍弃严谨，贴近通俗。 当然，想要深耕于AI领域，数学是充分且必要的条件。如果付得起时间和机会成本，请认真且努力，绝不会辜负你。 5.2 深度学习系列开始 深度学习是一台结构复杂的机器，但它的操作却相对简单。甚至，会给你比传统机器学习算法更简单的感受。 我们拭目以待！感谢大家！ 往期文章： 机器学习(五)：通俗易懂决策树与随机森林及代码实践 机器学习(四)：通俗理解支持向量机SVM及代码实践 机器学习(三)：理解逻辑回归及二分类、多分类代码实践 机器学习(二)：理解线性回归与梯度下降并做简单预测 机器学习(一)：5分钟理解机器学习并上手实践 前置机器学习（五）：30分钟掌握常用Matplotlib用法 前置机器学习（四）：一文掌握Pandas用法 前置机器学习（三）：30分钟掌握常用NumPy用法 前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法 前置机器学习（一）：数学符号及希腊字母]]></summary></entry><entry><title type="html">机器学习(五)：通俗易懂决策树与随机森林及代码实践</title><link href="/2021/02/25/machine-learning-5.html" rel="alternate" type="text/html" title="机器学习(五)：通俗易懂决策树与随机森林及代码实践" /><published>2021-02-25T00:00:00+00:00</published><updated>2021-02-25T00:00:00+00:00</updated><id>/2021/02/25/machine-learning-5</id><content type="html" xml:base="/2021/02/25/machine-learning-5.html"><![CDATA[<p>与SVM一样，决策树是通用的机器学习算法。随机森林，顾名思义，将决策树分类器集成到一起就形成了更强大的机器学习算法。它们都是很基础但很强大的机器学习工具，虽然我们现在有更先进的算法工具来训练模型，但决策树与随机森林因其简单灵活依然广受喜爱，建议大家学习。</p>

<h1 id="一决策树">一、决策树</h1>
<h2 id="11-什么是决策树">1.1 什么是决策树</h2>

<p>我们可以把决策树想象成IF/ELSE判别式深度嵌套的二叉树形结构。以我们在<a href="https://mp.weixin.qq.com/s/cEbGM0_Lrt8elfubxSF9jg">《机器学习(三)：理解逻辑回归及二分类、多分类代码实践》</a>所举的鸢尾花数据集为例。</p>

<p>我们曾用<code class="language-plaintext highlighter-rouge">seaborn</code>绘制花瓣长度和宽度特征对应鸢尾花种类的散点图，如下：</p>

<p><img src="/assets/images/20210225/1.png" alt="image" /></p>

<p>当花瓣长度小于2.45则为山鸢尾(setosa)，剩下的我们判断花瓣宽度小于1.75则为变色鸢尾(versicolor)剩下的为维吉尼亚鸢尾(virginica)。那么我用导图画一下这种判别式的树形结构如下：</p>

<p><img src="/assets/images/20210225/2.png" alt="image" /></p>

<p>因此，当我们面对任意鸢尾花的样本，我们只需要<strong>从根节点到叶子节点遍历决策树</strong>，就可以得到鸢尾花的分类结论。</p>

<p>这就是决策树。</p>

<h2 id="12-决策树代码实践">1.2 决策树代码实践</h2>

<p>我们导入数据集（大家不用在意这个域名），并训练模型：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">from</span> <span class="n">sklearn.tree</span> <span class="kn">import</span> <span class="n">DecisionTreeClassifier</span>

<span class="c1">#引入数据集
</span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nf">read_csv</span><span class="p">(</span><span class="sh">'</span><span class="s">https://blog.caiyongji.com/assets/iris.csv</span><span class="sh">'</span><span class="p">)</span>

<span class="c1">#决策树模型
</span><span class="n">X</span> <span class="o">=</span> <span class="n">df</span><span class="p">[[</span><span class="sh">'</span><span class="s">petal_length</span><span class="sh">'</span><span class="p">,</span><span class="sh">'</span><span class="s">petal_width</span><span class="sh">'</span><span class="p">]].</span><span class="nf">to_numpy</span><span class="p">()</span> 
<span class="n">y</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">species</span><span class="sh">'</span><span class="p">]</span>
<span class="n">tree_clf</span> <span class="o">=</span> <span class="nc">DecisionTreeClassifier</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">tree_clf</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
</code></pre></div></div>

<p>我们来可视化决策树：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="n">sklearn.tree</span> <span class="kn">import</span> <span class="n">plot_tree</span>
<span class="n">plt</span><span class="p">.</span><span class="nf">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span>
<span class="nf">plot_tree</span><span class="p">(</span><span class="n">tree_clf</span><span class="p">,</span><span class="n">filled</span><span class="o">=</span><span class="bp">True</span><span class="p">);</span>
</code></pre></div></div>

<p><img src="/assets/images/20210225/3.png" alt="image" /></p>

<p>如上图，我们可以看到根节点总实例数为150时，由<code class="language-plaintext highlighter-rouge">value = [50, 50, 50]</code>可知，实际样本分类为50个山鸢尾花实例、50个变色鸢尾花实例、50个维吉尼亚鸢尾花实例。我们再看最末尾右侧的叶子节点（紫色），由<code class="language-plaintext highlighter-rouge">value = [0, 1, 45]</code>可知，实际样本分类为0个山鸢尾花实例、1个变色鸢尾花实例、45个维吉尼亚鸢尾花实例。</p>

<p>那么gini = 0.043是什么意思呢？</p>

<h2 id="13-基尼不纯度">1.3 基尼不纯度</h2>

<p>显然我们进行分类时，每一个类别实际混入其他类的数量越少分类就越<strong>纯粹</strong>，这种纯度我们通过如下公式表示：</p>

\[G_i = 1 - \sum_{k=1}^{n}{p^2_{i,k}}\]

<p>我们计算维吉尼亚鸢尾花节点（紫色）的gini系数<code class="language-plaintext highlighter-rouge">1-((0/46)**2 + (1/46)**2 + (45/46)**2) = 0.04253308128544431 ≈0.043</code> 。</p>

<p>我们使用基尼(gini)不纯度来衡量决策树的好坏。那么我们通过最小化基尼不纯度min(gini)来求解X[0],X[1]（即，花瓣长度宽度特征）边界的过程就决策树模型的训练过程。</p>

<h1 id="二随机森林">二、随机森林</h1>
<h2 id="21-大数定理与随机森林">2.1 大数定理与随机森林</h2>

<p>其实随机森林很简单，我们把决策树随机组合在一起就是随机森林，它比单个的决策树更有效。</p>

<p>凭什么？</p>

<p>假设我们有一枚不均匀的硬币，投掷它有51%的概率为正面，49%的概率为背面，那么当投掷1000次时，“大多数为正面”这件事的概率为75%。投掷10000次时，“大多数为正面”这件事的概率为97%。这就是大数定理，它体现的是群体智慧。<em>质量不够，数量来凑</em>。由此可知，当前寻找最佳模型的方法不止是技巧的比拼，也同样是算力的比拼。</p>

<h2 id="22-随机森林代码实践">2.2 随机森林代码实践</h2>

<h3 id="221-引入新的数据集">2.2.1. 引入新的数据集</h3>

<p>添加引用：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="n">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="n">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="n">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
</code></pre></div></div>

<p>导入数据集（大家不用在意这个域名）：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nf">read_csv</span><span class="p">(</span><span class="sh">"</span><span class="s">https://blog.caiyongji.com/assets/penguins_size.csv</span><span class="sh">"</span><span class="p">)</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="nf">dropna</span><span class="p">()</span>
<span class="n">df</span><span class="p">.</span><span class="nf">head</span><span class="p">()</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th style="text-align: left">species</th>
      <th style="text-align: left">island</th>
      <th style="text-align: right">culmen_length_mm</th>
      <th style="text-align: right">culmen_depth_mm</th>
      <th style="text-align: right">flipper_length_mm</th>
      <th style="text-align: right">body_mass_g</th>
      <th style="text-align: left">sex</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Adelie</td>
      <td style="text-align: left">Torgersen</td>
      <td style="text-align: right">39.1</td>
      <td style="text-align: right">18.7</td>
      <td style="text-align: right">181</td>
      <td style="text-align: right">3750</td>
      <td style="text-align: left">MALE</td>
    </tr>
    <tr>
      <td style="text-align: left">Adelie</td>
      <td style="text-align: left">Torgersen</td>
      <td style="text-align: right">39.5</td>
      <td style="text-align: right">17.4</td>
      <td style="text-align: right">186</td>
      <td style="text-align: right">3800</td>
      <td style="text-align: left">FEMALE</td>
    </tr>
    <tr>
      <td style="text-align: left">Adelie</td>
      <td style="text-align: left">Torgersen</td>
      <td style="text-align: right">40.3</td>
      <td style="text-align: right">18</td>
      <td style="text-align: right">195</td>
      <td style="text-align: right">3250</td>
      <td style="text-align: left">FEMALE</td>
    </tr>
    <tr>
      <td style="text-align: left">Adelie</td>
      <td style="text-align: left">Torgersen</td>
      <td style="text-align: right">36.7</td>
      <td style="text-align: right">19.3</td>
      <td style="text-align: right">193</td>
      <td style="text-align: right">3450</td>
      <td style="text-align: left">FEMALE</td>
    </tr>
    <tr>
      <td style="text-align: left">Adelie</td>
      <td style="text-align: left">Torgersen</td>
      <td style="text-align: right">39.3</td>
      <td style="text-align: right">20.6</td>
      <td style="text-align: right">190</td>
      <td style="text-align: right">3650</td>
      <td style="text-align: left">MALE</td>
    </tr>
  </tbody>
</table>

<p>企鹅数据集包含特征和标签如下：</p>

<ul>
  <li><strong>特征</strong>：所在岛屿island、鸟喙长度culmen_length_mm、鸟喙深度culmen_depth_mm、脚蹼长度flipper_length_mm、体重(g)、性别</li>
  <li><strong>标签</strong>：物种species：Chinstrap, Adélie, or Gentoo</li>
</ul>

<h3 id="222-观察数据">2.2.2 观察数据</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sns</span><span class="p">.</span><span class="nf">pairplot</span><span class="p">(</span><span class="n">df</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="sh">'</span><span class="s">species</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>我们通过pairplot方法绘制特征两两之间的对应关系。</p>

<p><img src="/assets/images/20210225/4.png" alt="image" /></p>

<h3 id="223-预处理">2.2.3 预处理</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">X</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="nf">get_dummies</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="nf">drop</span><span class="p">(</span><span class="sh">'</span><span class="s">species</span><span class="sh">'</span><span class="p">,</span><span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span><span class="n">drop_first</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="sh">'</span><span class="s">species</span><span class="sh">'</span><span class="p">]</span>
<span class="n">X</span><span class="p">.</span><span class="nf">head</span><span class="p">()</span>
</code></pre></div></div>

<p>注意，<code class="language-plaintext highlighter-rouge">get_dummies</code>方法将字符串属性的列转换成了数字属性的多个列。如，岛屿island和性别sex分别转换成了island_Dream、island_Torgersen和sex_FEMALE、sex_MALE。这是一种独热编码的关系，比如sex_FEMALE与sex_MALE属性独立，在空间内没有向量关系。</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">culmen_length_mm</th>
      <th style="text-align: right">culmen_depth_mm</th>
      <th style="text-align: right">flipper_length_mm</th>
      <th style="text-align: right">body_mass_g</th>
      <th style="text-align: right">island_Dream</th>
      <th style="text-align: right">island_Torgersen</th>
      <th style="text-align: right">sex_FEMALE</th>
      <th style="text-align: right">sex_MALE</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">39.1</td>
      <td style="text-align: right">18.7</td>
      <td style="text-align: right">181</td>
      <td style="text-align: right">3750</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">39.5</td>
      <td style="text-align: right">17.4</td>
      <td style="text-align: right">186</td>
      <td style="text-align: right">3800</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">40.3</td>
      <td style="text-align: right">18</td>
      <td style="text-align: right">195</td>
      <td style="text-align: right">3250</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">36.7</td>
      <td style="text-align: right">19.3</td>
      <td style="text-align: right">193</td>
      <td style="text-align: right">3450</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">39.3</td>
      <td style="text-align: right">20.6</td>
      <td style="text-align: right">190</td>
      <td style="text-align: right">3650</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">0</td>
      <td style="text-align: right">1</td>
    </tr>
  </tbody>
</table>

<h3 id="224-训练数据">2.2.4 训练数据</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#训练
</span><span class="kn">from</span> <span class="n">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>
<span class="kn">from</span> <span class="n">sklearn.ensemble</span> <span class="kn">import</span> <span class="n">RandomForestClassifier</span>
<span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">y_test</span> <span class="o">=</span> <span class="nf">train_test_split</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">test_size</span><span class="o">=</span><span class="mf">0.3</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">101</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="nc">RandomForestClassifier</span><span class="p">(</span><span class="n">n_estimators</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span><span class="n">max_features</span><span class="o">=</span><span class="sh">'</span><span class="s">auto</span><span class="sh">'</span><span class="p">,</span><span class="n">random_state</span><span class="o">=</span><span class="mi">101</span><span class="p">)</span>
<span class="n">model</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span><span class="n">y_train</span><span class="p">)</span>

<span class="c1">#预测
</span><span class="kn">from</span> <span class="n">sklearn.metrics</span> <span class="kn">import</span> <span class="n">accuracy_score</span>
<span class="n">preds</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="nf">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
<span class="nf">accuracy_score</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span><span class="n">preds</span><span class="p">)</span>
</code></pre></div></div>

<p>使用随机森林分类器<code class="language-plaintext highlighter-rouge">RandomForestClassifier</code>训练，得到模型精度为97%。</p>

<h3 id="225-网格搜索与adaboost提升法拓展">2.2.5 网格搜索与AdaBoost提升法（拓展）</h3>

<p>我们使用<code class="language-plaintext highlighter-rouge">AdaBoostClassifier</code>分类器集成数个决策树分类器<code class="language-plaintext highlighter-rouge">DecisionTreeClassifier</code>进行分类。并使用网格搜索方法<code class="language-plaintext highlighter-rouge">GridSearchCV</code>来寻找最优参数。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">GridSearchCV</span>
<span class="kn">from</span> <span class="n">sklearn.ensemble</span> <span class="kn">import</span> <span class="n">AdaBoostClassifier</span>

<span class="n">ada_clf</span> <span class="o">=</span> <span class="nc">AdaBoostClassifier</span><span class="p">(</span><span class="nc">DecisionTreeClassifier</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">101</span><span class="p">)</span>
<span class="n">ada_clf</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">param_grid</span> <span class="o">=</span> <span class="p">{</span><span class="sh">'</span><span class="s">n_estimators</span><span class="sh">'</span><span class="p">:[</span><span class="mi">10</span><span class="p">,</span><span class="mi">15</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">25</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">35</span><span class="p">,</span><span class="mi">40</span><span class="p">],</span> <span class="sh">'</span><span class="s">learning_rate</span><span class="sh">'</span><span class="p">:[</span><span class="mf">0.01</span><span class="p">,</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">0.5</span><span class="p">,</span><span class="mi">1</span><span class="p">],</span> <span class="sh">'</span><span class="s">algorithm</span><span class="sh">'</span><span class="p">:[</span><span class="sh">'</span><span class="s">SAMME</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">SAMME.R</span><span class="sh">'</span><span class="p">]}</span>
<span class="n">grid</span> <span class="o">=</span> <span class="nc">GridSearchCV</span><span class="p">(</span><span class="n">ada_clf</span><span class="p">,</span><span class="n">param_grid</span><span class="p">)</span>
<span class="n">grid</span><span class="p">.</span><span class="nf">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span><span class="n">y_train</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">grid.best_params_ = </span><span class="sh">"</span><span class="p">,</span><span class="n">grid</span><span class="p">.</span><span class="n">best_params_</span><span class="p">,</span><span class="sh">"</span><span class="s">, grid.best_score_ =</span><span class="sh">"</span> <span class="p">,</span><span class="n">grid</span><span class="p">.</span><span class="n">best_score_</span><span class="p">)</span>
</code></pre></div></div>

<p>这是一种集成学习技术，输出如下：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grid.best_params_ =  {'algorithm': 'SAMME', 'learning_rate': 1, 'n_estimators': 20} , grid.best_score_ = 0.9914893617021276
</code></pre></div></div>

<h1 id="总结">总结</h1>

<p>二叉树是决策树的核心逻辑，随机森林是大数定理的应用实现。这种基本思想即使不用数学公式也可以很容易的解释清楚，这也是我做这个系列课程（文章）的主要风格特点。我认为，数学是对现实世界的解释，但现实世界并不能被数学<strong>完全解释</strong>。像谷歌AI主管Laurence Moroney所说：</p>

<blockquote>
  <p>很多人害怕数学，害怕大量的深度的微积分知识。其实我们可以实现编码而不考虑数学，我们可以使用TensorFlow中高(层)级的API，来解决问题，如自然语言处理，图像分类，计算机视觉序列模型等而无需理解深刻的数学。就像你使用JAVA却不一定非要掌握它是如何编译的。未来，AI只是每个开发者技术栈(toolbox)中的一部分，就像HTML, CSS, JAVA。</p>
</blockquote>

<p>希望那一天可以早点到来吧……</p>

<p>往期文章：</p>

<ul>
  <li><a href="https://mp.weixin.qq.com/s/QqXNgfyZVwZ-Aze6XTbvng">机器学习(四)：通俗理解支持向量机SVM及代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/cEbGM0_Lrt8elfubxSF9jg">机器学习(三)：理解逻辑回归及二分类、多分类代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/_bHi-XH5ZXI4jDUzwH3xpQ">机器学习(二)：理解线性回归与梯度下降并做简单预测</a></li>
  <li><a href="https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q">机器学习(一)：5分钟理解机器学习并上手实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/5brLPnUP6sYvc-_JO7IzkA">前置机器学习（五）：30分钟掌握常用Matplotlib用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/LlLkkBfI-4s3qdVaiv7EdQ">前置机器学习（四）：一文掌握Pandas用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/U8dV8ENzzSx_VwBDdJdr_w">前置机器学习（三）：30分钟掌握常用NumPy用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/PCGThwI-YD7_hHxO35V8xw">前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/BLxyqK3CGV9yd92yGEs4XQ">前置机器学习（一）：数学符号及希腊字母</a></li>
</ul>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="机器学习" /><category term="决策树" /><category term="随机森林" /><summary type="html"><![CDATA[与SVM一样，决策树是通用的机器学习算法。随机森林，顾名思义，将决策树分类器集成到一起就形成了更强大的机器学习算法。它们都是很基础但很强大的机器学习工具，虽然我们现在有更先进的算法工具来训练模型，但决策树与随机森林因其简单灵活依然广受喜爱，建议大家学习。 一、决策树 1.1 什么是决策树 我们可以把决策树想象成IF/ELSE判别式深度嵌套的二叉树形结构。以我们在《机器学习(三)：理解逻辑回归及二分类、多分类代码实践》所举的鸢尾花数据集为例。 我们曾用seaborn绘制花瓣长度和宽度特征对应鸢尾花种类的散点图，如下： 当花瓣长度小于2.45则为山鸢尾(setosa)，剩下的我们判断花瓣宽度小于1.75则为变色鸢尾(versicolor)剩下的为维吉尼亚鸢尾(virginica)。那么我用导图画一下这种判别式的树形结构如下： 因此，当我们面对任意鸢尾花的样本，我们只需要从根节点到叶子节点遍历决策树，就可以得到鸢尾花的分类结论。 这就是决策树。 1.2 决策树代码实践 我们导入数据集（大家不用在意这个域名），并训练模型： import numpy as np import pandas as pd from sklearn.tree import DecisionTreeClassifier #引入数据集 df = pd.read_csv('https://blog.caiyongji.com/assets/iris.csv') #决策树模型 X = df[['petal_length','petal_width']].to_numpy() y = df['species'] tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42) tree_clf.fit(X, y) 我们来可视化决策树： import matplotlib.pyplot as plt from sklearn.tree import plot_tree plt.figure(figsize=(12,8)) plot_tree(tree_clf,filled=True); 如上图，我们可以看到根节点总实例数为150时，由value = [50, 50, 50]可知，实际样本分类为50个山鸢尾花实例、50个变色鸢尾花实例、50个维吉尼亚鸢尾花实例。我们再看最末尾右侧的叶子节点（紫色），由value = [0, 1, 45]可知，实际样本分类为0个山鸢尾花实例、1个变色鸢尾花实例、45个维吉尼亚鸢尾花实例。 那么gini = 0.043是什么意思呢？ 1.3 基尼不纯度 显然我们进行分类时，每一个类别实际混入其他类的数量越少分类就越纯粹，这种纯度我们通过如下公式表示： \[G_i = 1 - \sum_{k=1}^{n}{p^2_{i,k}}\] 我们计算维吉尼亚鸢尾花节点（紫色）的gini系数1-((0/46)**2 + (1/46)**2 + (45/46)**2) = 0.04253308128544431 ≈0.043 。 我们使用基尼(gini)不纯度来衡量决策树的好坏。那么我们通过最小化基尼不纯度min(gini)来求解X[0],X[1]（即，花瓣长度宽度特征）边界的过程就决策树模型的训练过程。 二、随机森林 2.1 大数定理与随机森林 其实随机森林很简单，我们把决策树随机组合在一起就是随机森林，它比单个的决策树更有效。 凭什么？ 假设我们有一枚不均匀的硬币，投掷它有51%的概率为正面，49%的概率为背面，那么当投掷1000次时，“大多数为正面”这件事的概率为75%。投掷10000次时，“大多数为正面”这件事的概率为97%。这就是大数定理，它体现的是群体智慧。质量不够，数量来凑。由此可知，当前寻找最佳模型的方法不止是技巧的比拼，也同样是算力的比拼。 2.2 随机森林代码实践 2.2.1. 引入新的数据集 添加引用： import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns 导入数据集（大家不用在意这个域名）： df = pd.read_csv("https://blog.caiyongji.com/assets/penguins_size.csv") df = df.dropna() df.head() species island culmen_length_mm culmen_depth_mm flipper_length_mm body_mass_g sex Adelie Torgersen 39.1 18.7 181 3750 MALE Adelie Torgersen 39.5 17.4 186 3800 FEMALE Adelie Torgersen 40.3 18 195 3250 FEMALE Adelie Torgersen 36.7 19.3 193 3450 FEMALE Adelie Torgersen 39.3 20.6 190 3650 MALE 企鹅数据集包含特征和标签如下： 特征：所在岛屿island、鸟喙长度culmen_length_mm、鸟喙深度culmen_depth_mm、脚蹼长度flipper_length_mm、体重(g)、性别 标签：物种species：Chinstrap, Adélie, or Gentoo 2.2.2 观察数据 sns.pairplot(df,hue='species') 我们通过pairplot方法绘制特征两两之间的对应关系。 2.2.3 预处理 X = pd.get_dummies(df.drop('species',axis=1),drop_first=True) y = df['species'] X.head() 注意，get_dummies方法将字符串属性的列转换成了数字属性的多个列。如，岛屿island和性别sex分别转换成了island_Dream、island_Torgersen和sex_FEMALE、sex_MALE。这是一种独热编码的关系，比如sex_FEMALE与sex_MALE属性独立，在空间内没有向量关系。 culmen_length_mm culmen_depth_mm flipper_length_mm body_mass_g island_Dream island_Torgersen sex_FEMALE sex_MALE 39.1 18.7 181 3750 0 1 0 1 39.5 17.4 186 3800 0 1 1 0 40.3 18 195 3250 0 1 1 0 36.7 19.3 193 3450 0 1 1 0 39.3 20.6 190 3650 0 1 0 1 2.2.4 训练数据 #训练 from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101) model = RandomForestClassifier(n_estimators=10,max_features='auto',random_state=101) model.fit(X_train,y_train) #预测 from sklearn.metrics import accuracy_score preds = model.predict(X_test) accuracy_score(y_test,preds) 使用随机森林分类器RandomForestClassifier训练，得到模型精度为97%。 2.2.5 网格搜索与AdaBoost提升法（拓展） 我们使用AdaBoostClassifier分类器集成数个决策树分类器DecisionTreeClassifier进行分类。并使用网格搜索方法GridSearchCV来寻找最优参数。 from sklearn.model_selection import GridSearchCV from sklearn.ensemble import AdaBoostClassifier ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), random_state=101) ada_clf.fit(X_train, y_train) param_grid = {'n_estimators':[10,15,20,25,30,35,40], 'learning_rate':[0.01,0.1,0.5,1], 'algorithm':['SAMME', 'SAMME.R']} grid = GridSearchCV(ada_clf,param_grid) grid.fit(X_train,y_train) print("grid.best_params_ = ",grid.best_params_,", grid.best_score_ =" ,grid.best_score_) 这是一种集成学习技术，输出如下： grid.best_params_ = {'algorithm': 'SAMME', 'learning_rate': 1, 'n_estimators': 20} , grid.best_score_ = 0.9914893617021276 总结 二叉树是决策树的核心逻辑，随机森林是大数定理的应用实现。这种基本思想即使不用数学公式也可以很容易的解释清楚，这也是我做这个系列课程（文章）的主要风格特点。我认为，数学是对现实世界的解释，但现实世界并不能被数学完全解释。像谷歌AI主管Laurence Moroney所说： 很多人害怕数学，害怕大量的深度的微积分知识。其实我们可以实现编码而不考虑数学，我们可以使用TensorFlow中高(层)级的API，来解决问题，如自然语言处理，图像分类，计算机视觉序列模型等而无需理解深刻的数学。就像你使用JAVA却不一定非要掌握它是如何编译的。未来，AI只是每个开发者技术栈(toolbox)中的一部分，就像HTML, CSS, JAVA。 希望那一天可以早点到来吧…… 往期文章： 机器学习(四)：通俗理解支持向量机SVM及代码实践 机器学习(三)：理解逻辑回归及二分类、多分类代码实践 机器学习(二)：理解线性回归与梯度下降并做简单预测 机器学习(一)：5分钟理解机器学习并上手实践 前置机器学习（五）：30分钟掌握常用Matplotlib用法 前置机器学习（四）：一文掌握Pandas用法 前置机器学习（三）：30分钟掌握常用NumPy用法 前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法 前置机器学习（一）：数学符号及希腊字母]]></summary></entry><entry><title type="html">机器学习(四)：通俗理解支持向量机SVM及代码实践</title><link href="/2021/02/15/machine-learning-4.html" rel="alternate" type="text/html" title="机器学习(四)：通俗理解支持向量机SVM及代码实践" /><published>2021-02-15T00:00:00+00:00</published><updated>2021-02-15T00:00:00+00:00</updated><id>/2021/02/15/machine-learning-4</id><content type="html" xml:base="/2021/02/15/machine-learning-4.html"><![CDATA[<p><a href="https://mp.weixin.qq.com/s/cEbGM0_Lrt8elfubxSF9jg">上一篇文章</a>我们介绍了使用逻辑回归来处理分类问题，本文我们讲一个更强大的分类模型。本文依旧侧重代码实践，你会发现我们解决问题的手段越来越丰富，问题处理起来越来越简单。</p>

<p>支持向量机(Support Vector Machine, SVM)是最受欢迎的机器学习模型之一。它特别适合处理中小型复杂数据集的分类任务。</p>

<h1 id="一什么是支持向量机">一、什么是支持向量机</h1>

<p>SMV在众多实例中寻找一个最优的决策边界，这个边界上的实例叫做支持向量，它们“支持”（支撑）分离开超平面，所以它叫支持向量机。</p>

<p>那么我们如何保证我们得到的决策边界是<strong>最优</strong>的呢？</p>

<p><img src="/assets/images/20210215/1.png" alt="image" /></p>

<p>如上图，三条黑色直线都可以完美分割数据集。由此可知，我们仅用单一直线可以得到无数个解。那么，其中怎样的直线是最优的呢？</p>

<p><img src="/assets/images/20210215/2.png" alt="image" /></p>

<p>如上图，我们计算直线到分割实例的距离，使得我们的直线与数据集的<strong>距离尽可能的远</strong>，那么我们就可以得到唯一的解。最大化上图虚线之间的距离就是我们的目标。而上图中重点圈出的实例就叫做支持向量。</p>

<p>这就是支持向量机。</p>

<h1 id="二从代码中映射理论">二、从代码中映射理论</h1>

<h2 id="21-导入数据集">2.1 导入数据集</h2>

<p>添加引用：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
</code></pre></div></div>

<p>导入数据集（大家不用在意这个域名）：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>df = pd.read_csv('https://blog.caiyongji.com/assets/mouse_viral_study.csv')
df.head()
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th style="text-align: right"> </th>
      <th style="text-align: right">Med_1_mL</th>
      <th style="text-align: right">Med_2_mL</th>
      <th style="text-align: right">Virus Present</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">0</td>
      <td style="text-align: right">6.50823</td>
      <td style="text-align: right">8.58253</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">1</td>
      <td style="text-align: right">4.12612</td>
      <td style="text-align: right">3.07346</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">2</td>
      <td style="text-align: right">6.42787</td>
      <td style="text-align: right">6.36976</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">3</td>
      <td style="text-align: right">3.67295</td>
      <td style="text-align: right">4.90522</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">4</td>
      <td style="text-align: right">1.58032</td>
      <td style="text-align: right">2.44056</td>
      <td style="text-align: right">1</td>
    </tr>
  </tbody>
</table>

<p>该数据集模拟了一项医学研究，对感染病毒的小白鼠使用不同剂量的两种药物，观察两周后小白鼠是否感染病毒。</p>

<ul>
  <li><strong>特征</strong>： 1. 药物Med_1_mL 药物Med_2_mL</li>
  <li><strong>标签</strong>：是否感染病毒（1感染/0不感染）</li>
</ul>

<h2 id="22-观察数据">2.2 观察数据</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.scatterplot(x='Med_1_mL',y='Med_2_mL',hue='Virus Present',data=df)
</code></pre></div></div>

<p>我们用seaborn绘制两种药物在不同剂量特征对应感染结果的散点图。</p>

<p><img src="/assets/images/20210215/3.png" alt="image" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.pairplot(df,hue='Virus Present')
</code></pre></div></div>

<p>我们通过pairplot方法绘制特征两两之间的对应关系。</p>

<p><img src="/assets/images/20210215/4.png" alt="image" /></p>

<p>我们可以做出大概的判断，当加大药物剂量可使小白鼠避免被感染。</p>

<h2 id="23-使用svm训练数据集">2.3 使用SVM训练数据集</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#SVC: Supprt Vector Classifier支持向量分类器
from sklearn.svm import SVC

#准备数据
y = df['Virus Present']
X = df.drop('Virus Present',axis=1) 

#定义模型
model = SVC(kernel='linear', C=1000)

#训练模型
model.fit(X, y)

# 绘制图像
# 定义绘制SVM边界方法
def plot_svm_boundary(model,X,y):
    
    X = X.values
    y = y.values
    
    # Scatter Plot
    plt.scatter(X[:, 0], X[:, 1], c=y, s=30,cmap='coolwarm')

    
    # plot the decision function
    ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # create grid to evaluate model
    xx = np.linspace(xlim[0], xlim[1], 30)
    yy = np.linspace(ylim[0], ylim[1], 30)
    YY, XX = np.meshgrid(yy, xx)
    xy = np.vstack([XX.ravel(), YY.ravel()]).T
    Z = model.decision_function(xy).reshape(XX.shape)

    # plot decision boundary and margins
    ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])
    # plot support vectors
    ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=100,
               linewidth=1, facecolors='none', edgecolors='k')
    plt.show()
plot_svm_boundary(model,X,y)
</code></pre></div></div>

<p><img src="/assets/images/20210215/5.png" alt="image" /></p>

<p>我们导入<code class="language-plaintext highlighter-rouge">sklearn</code>下的<code class="language-plaintext highlighter-rouge">SVC</code>(Supprt Vector Classifier)分类器，它是SVM的一种实现。</p>

<h2 id="24-svc参数c">2.4 SVC参数C</h2>
<p>SVC方法参数<code class="language-plaintext highlighter-rouge">C</code>代表L2正则化参数，正则化的强度与<code class="language-plaintext highlighter-rouge">C</code>的值城<strong>反比</strong>，即C值越大正则化强度越弱，其必须严格为正。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>model = SVC(kernel='linear', C=0.05)
model.fit(X, y)
plot_svm_boundary(model,X,y)
</code></pre></div></div>
<p>我们减少C的值，可以看到模型拟合数据的程度减弱。</p>

<p><img src="/assets/images/20210215/6.png" alt="image" /></p>

<h2 id="25-核技巧">2.5 核技巧</h2>
<p>SVC方法的<code class="language-plaintext highlighter-rouge">kernel</code>参数可取值<code class="language-plaintext highlighter-rouge">{'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'}</code>。像前文中所使用的那样，我们可以使<code class="language-plaintext highlighter-rouge">kernel='linear'</code>进行线性分类。那么如果我们像进行非线性分类呢？</p>

<h3 id="251-多项式内核">2.5.1 多项式内核</h3>
<p><strong>多项式内核</strong><code class="language-plaintext highlighter-rouge">kernel='poly'</code>的原理简单来说就是，<strong>用单一特征生成多特征来拟合曲线</strong>。比如我们拓展X到y的对应关系如下：</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right"> </th>
      <th style="text-align: right">X</th>
      <th style="text-align: right">X^2</th>
      <th style="text-align: right">X^3</th>
      <th style="text-align: right">y</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">0</td>
      <td style="text-align: right">6.50823</td>
      <td style="text-align: right">6.50823**2</td>
      <td style="text-align: right">6.50823**3</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">1</td>
      <td style="text-align: right">4.12612</td>
      <td style="text-align: right">4.12612**2</td>
      <td style="text-align: right">4.12612**3</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">2</td>
      <td style="text-align: right">6.42787</td>
      <td style="text-align: right">6.42787**2</td>
      <td style="text-align: right">6.42787**3</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">3</td>
      <td style="text-align: right">3.67295</td>
      <td style="text-align: right">3.67295**2</td>
      <td style="text-align: right">3.67295**3</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">4</td>
      <td style="text-align: right">1.58032</td>
      <td style="text-align: right">1.58032**2</td>
      <td style="text-align: right">1.58032**3</td>
      <td style="text-align: right">1</td>
    </tr>
  </tbody>
</table>

<p>这样我们就可以用曲线来拟合数据集。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>model = SVC(kernel='poly', C=0.05,degree=5)
model.fit(X, y)
plot_svm_boundary(model,X,y)
</code></pre></div></div>
<p>我们使用多项式内核，并通过<code class="language-plaintext highlighter-rouge">degree=5</code>设置多项式的<strong>最高次数</strong>为5。我们可以看出分割出现了一定的弧度。</p>

<p><img src="/assets/images/20210215/7.png" alt="image" /></p>

<h3 id="252-高斯rbf内核">2.5.2 高斯RBF内核</h3>
<p>SVC方法默认内核为高斯<code class="language-plaintext highlighter-rouge">RBF</code>，即Radial Basis Function（径向基函数）。这时我们需要引入<code class="language-plaintext highlighter-rouge">gamma</code>参数来控制钟形函数的形状。增加gamma值会使钟形曲线变得更窄，因此每个实例影响的范围变小，决策边界更不规则。减小gamma值会使钟形曲线变得更宽，因此每个实例的影响范围变大，决策边界更平坦。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>model = SVC(kernel='rbf', C=1,gamma=0.01)
model.fit(X, y)
plot_svm_boundary(model,X,y)
</code></pre></div></div>
<p><img src="/assets/images/20210215/8.png" alt="image" /></p>

<h2 id="26-调参技巧网格搜索">2.6 调参技巧：网格搜索</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from sklearn.model_selection import GridSearchCV
svm = SVC()
param_grid = {'C':[0.01,0.1,1],'kernel':['rbf','poly','linear','sigmoid'],'gamma':[0.01,0.1,1]}
grid = GridSearchCV(svm,param_grid)
grid.fit(X,y)
print("grid.best_params_ = ",grid.best_params_,", grid.best_score_ =" ,grid.best_score_)
</code></pre></div></div>
<p>我们可以通过<code class="language-plaintext highlighter-rouge">GridSearchCV</code>方法来遍历超参数的各种可能性来寻求最优超参数。这是通过算力碾压的方式暴力调参的手段。当然，在分析问题阶段，我们必须限定了各参数的可选范围才能应用此方法。</p>

<p>因为数据集太简单，我们在遍历第一种可能性时就已经得到100%的准确率了，输出如下：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grid.best_params_ =  {'C': 0.01, 'gamma': 0.01, 'kernel': 'rbf'} , grid.best_score_ = 1.0
</code></pre></div></div>

<h1 id="总结">总结</h1>

<p>当我们处理线性可分的数据集时，可以使用<code class="language-plaintext highlighter-rouge">SVC(kernel='linear')</code>方法来训练数据，当然我们也可以使用更快的方法<code class="language-plaintext highlighter-rouge">LinearSVC</code>来训练数据，特别是当训练集特别大或特征非常多的时候。<br />
当我们处理非线性SVM分类时，可以使用高斯RBF内核,多项式内核，sigmoid内核来进行非线性模型的的拟合。当然我们也可以通过GridSearchCV寻找最优参数。</p>

<p>往期文章：</p>

<ul>
  <li><a href="https://mp.weixin.qq.com/s/cEbGM0_Lrt8elfubxSF9jg">机器学习(三)：理解逻辑回归及二分类、多分类代码实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/_bHi-XH5ZXI4jDUzwH3xpQ">机器学习(二)：理解线性回归与梯度下降并做简单预测</a></li>
  <li><a href="https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q">机器学习(一)：5分钟理解机器学习并上手实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/5brLPnUP6sYvc-_JO7IzkA">前置机器学习（五）：30分钟掌握常用Matplotlib用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/LlLkkBfI-4s3qdVaiv7EdQ">前置机器学习（四）：一文掌握Pandas用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/U8dV8ENzzSx_VwBDdJdr_w">前置机器学习（三）：30分钟掌握常用NumPy用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/PCGThwI-YD7_hHxO35V8xw">前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/BLxyqK3CGV9yd92yGEs4XQ">前置机器学习（一）：数学符号及希腊字母</a></li>
</ul>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="机器学习" /><category term="支持向量机" /><category term="SVM" /><summary type="html"><![CDATA[上一篇文章我们介绍了使用逻辑回归来处理分类问题，本文我们讲一个更强大的分类模型。本文依旧侧重代码实践，你会发现我们解决问题的手段越来越丰富，问题处理起来越来越简单。 支持向量机(Support Vector Machine, SVM)是最受欢迎的机器学习模型之一。它特别适合处理中小型复杂数据集的分类任务。 一、什么是支持向量机 SMV在众多实例中寻找一个最优的决策边界，这个边界上的实例叫做支持向量，它们“支持”（支撑）分离开超平面，所以它叫支持向量机。 那么我们如何保证我们得到的决策边界是最优的呢？ 如上图，三条黑色直线都可以完美分割数据集。由此可知，我们仅用单一直线可以得到无数个解。那么，其中怎样的直线是最优的呢？ 如上图，我们计算直线到分割实例的距离，使得我们的直线与数据集的距离尽可能的远，那么我们就可以得到唯一的解。最大化上图虚线之间的距离就是我们的目标。而上图中重点圈出的实例就叫做支持向量。 这就是支持向量机。 二、从代码中映射理论 2.1 导入数据集 添加引用： import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt 导入数据集（大家不用在意这个域名）： df = pd.read_csv('https://blog.caiyongji.com/assets/mouse_viral_study.csv') df.head()   Med_1_mL Med_2_mL Virus Present 0 6.50823 8.58253 0 1 4.12612 3.07346 1 2 6.42787 6.36976 0 3 3.67295 4.90522 1 4 1.58032 2.44056 1 该数据集模拟了一项医学研究，对感染病毒的小白鼠使用不同剂量的两种药物，观察两周后小白鼠是否感染病毒。 特征： 1. 药物Med_1_mL 药物Med_2_mL 标签：是否感染病毒（1感染/0不感染） 2.2 观察数据 sns.scatterplot(x='Med_1_mL',y='Med_2_mL',hue='Virus Present',data=df) 我们用seaborn绘制两种药物在不同剂量特征对应感染结果的散点图。 sns.pairplot(df,hue='Virus Present') 我们通过pairplot方法绘制特征两两之间的对应关系。 我们可以做出大概的判断，当加大药物剂量可使小白鼠避免被感染。 2.3 使用SVM训练数据集 #SVC: Supprt Vector Classifier支持向量分类器 from sklearn.svm import SVC #准备数据 y = df['Virus Present'] X = df.drop('Virus Present',axis=1) #定义模型 model = SVC(kernel='linear', C=1000) #训练模型 model.fit(X, y) # 绘制图像 # 定义绘制SVM边界方法 def plot_svm_boundary(model,X,y): X = X.values y = y.values # Scatter Plot plt.scatter(X[:, 0], X[:, 1], c=y, s=30,cmap='coolwarm') # plot the decision function ax = plt.gca() xlim = ax.get_xlim() ylim = ax.get_ylim() # create grid to evaluate model xx = np.linspace(xlim[0], xlim[1], 30) yy = np.linspace(ylim[0], ylim[1], 30) YY, XX = np.meshgrid(yy, xx) xy = np.vstack([XX.ravel(), YY.ravel()]).T Z = model.decision_function(xy).reshape(XX.shape) # plot decision boundary and margins ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--']) # plot support vectors ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none', edgecolors='k') plt.show() plot_svm_boundary(model,X,y) 我们导入sklearn下的SVC(Supprt Vector Classifier)分类器，它是SVM的一种实现。 2.4 SVC参数C SVC方法参数C代表L2正则化参数，正则化的强度与C的值城反比，即C值越大正则化强度越弱，其必须严格为正。 model = SVC(kernel='linear', C=0.05) model.fit(X, y) plot_svm_boundary(model,X,y) 我们减少C的值，可以看到模型拟合数据的程度减弱。 2.5 核技巧 SVC方法的kernel参数可取值{'linear', 'poly', 'rbf', 'sigmoid', 'precomputed'}。像前文中所使用的那样，我们可以使kernel='linear'进行线性分类。那么如果我们像进行非线性分类呢？ 2.5.1 多项式内核 多项式内核kernel='poly'的原理简单来说就是，用单一特征生成多特征来拟合曲线。比如我们拓展X到y的对应关系如下：   X X^2 X^3 y 0 6.50823 6.50823**2 6.50823**3 0 1 4.12612 4.12612**2 4.12612**3 1 2 6.42787 6.42787**2 6.42787**3 0 3 3.67295 3.67295**2 3.67295**3 1 4 1.58032 1.58032**2 1.58032**3 1 这样我们就可以用曲线来拟合数据集。 model = SVC(kernel='poly', C=0.05,degree=5) model.fit(X, y) plot_svm_boundary(model,X,y) 我们使用多项式内核，并通过degree=5设置多项式的最高次数为5。我们可以看出分割出现了一定的弧度。 2.5.2 高斯RBF内核 SVC方法默认内核为高斯RBF，即Radial Basis Function（径向基函数）。这时我们需要引入gamma参数来控制钟形函数的形状。增加gamma值会使钟形曲线变得更窄，因此每个实例影响的范围变小，决策边界更不规则。减小gamma值会使钟形曲线变得更宽，因此每个实例的影响范围变大，决策边界更平坦。 model = SVC(kernel='rbf', C=1,gamma=0.01) model.fit(X, y) plot_svm_boundary(model,X,y) 2.6 调参技巧：网格搜索 from sklearn.model_selection import GridSearchCV svm = SVC() param_grid = {'C':[0.01,0.1,1],'kernel':['rbf','poly','linear','sigmoid'],'gamma':[0.01,0.1,1]} grid = GridSearchCV(svm,param_grid) grid.fit(X,y) print("grid.best_params_ = ",grid.best_params_,", grid.best_score_ =" ,grid.best_score_) 我们可以通过GridSearchCV方法来遍历超参数的各种可能性来寻求最优超参数。这是通过算力碾压的方式暴力调参的手段。当然，在分析问题阶段，我们必须限定了各参数的可选范围才能应用此方法。 因为数据集太简单，我们在遍历第一种可能性时就已经得到100%的准确率了，输出如下： grid.best_params_ = {'C': 0.01, 'gamma': 0.01, 'kernel': 'rbf'} , grid.best_score_ = 1.0 总结 当我们处理线性可分的数据集时，可以使用SVC(kernel='linear')方法来训练数据，当然我们也可以使用更快的方法LinearSVC来训练数据，特别是当训练集特别大或特征非常多的时候。 当我们处理非线性SVM分类时，可以使用高斯RBF内核,多项式内核，sigmoid内核来进行非线性模型的的拟合。当然我们也可以通过GridSearchCV寻找最优参数。 往期文章： 机器学习(三)：理解逻辑回归及二分类、多分类代码实践 机器学习(二)：理解线性回归与梯度下降并做简单预测 机器学习(一)：5分钟理解机器学习并上手实践 前置机器学习（五）：30分钟掌握常用Matplotlib用法 前置机器学习（四）：一文掌握Pandas用法 前置机器学习（三）：30分钟掌握常用NumPy用法 前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法 前置机器学习（一）：数学符号及希腊字母]]></summary></entry><entry><title type="html">机器学习(三)：理解逻辑回归及二分类、多分类代码实践</title><link href="/2021/02/01/machine-learning-3.html" rel="alternate" type="text/html" title="机器学习(三)：理解逻辑回归及二分类、多分类代码实践" /><published>2021-02-01T00:00:00+00:00</published><updated>2021-02-01T00:00:00+00:00</updated><id>/2021/02/01/machine-learning-3</id><content type="html" xml:base="/2021/02/01/machine-learning-3.html"><![CDATA[<p>本文是<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxMjU4NjI4MQ==&amp;action=getalbum&amp;album_id=1696710764742393857&amp;scene=173&amp;from_msgid=2247484303&amp;from_itemidx=1&amp;count=3#wechat_redirect">机器学习系列</a>的第三篇，算上<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxMjU4NjI4MQ==&amp;action=getalbum&amp;album_id=1627166768236412929&amp;scene=173&amp;from_msgid=2247484161&amp;from_itemidx=1&amp;count=3#wechat_redirect">前置机器学习系列</a>是第八篇。本文的概念相对简单，主要侧重于代码实践。<br />
<a href="https://mp.weixin.qq.com/s?__biz=MzUxMjU4NjI4MQ==&amp;mid=2247484303&amp;idx=1&amp;sn=3880ff2318ee5f005fbe07e308d1c714&amp;chksm=f96364c9ce14eddf2bb66703d249e6b62797a29e6fcbd69756ee3260352fe668860282830503&amp;scene=178&amp;cur_album_id=1696710764742393857#rd">上一篇文章</a>说到，我们可以用线性回归做预测，但显然现实生活中不止有预测的问题还有分类的问题。我们可以从预测值的类型上简单区分：<strong>连续变量的预测为回归，离散变量的预测为分类。</strong></p>

<h1 id="一逻辑回归二分类">一、逻辑回归：二分类</h1>

<h2 id="11-理解逻辑回归">1.1 理解逻辑回归</h2>
<p>我们把连续的预测值进行人工定义，边界的一边定义为1，另一边定义为0。这样我们就把回归问题转换成了分类问题。</p>

<p><img src="/assets/images/20210201/1.png" alt="image" /></p>

<p>如上图，我们把连续的变量分布<strong>压制</strong>在0-1的范围内，并以0.5作为我们分类决策的<strong>边界</strong>，大于0.5的概率则判别为1，小于0.5的概率则判别为0。</p>

<p><img src="/assets/images/20210201/2.png" alt="image" /></p>

<p>我们无法使用无穷大和负无穷大进行算术运算，我们通过逻辑回归函数（Sigmoid函数/S型函数/Logistic函数）可以讲数值计算限定在0-1之间。</p>

\[\sigma(x) = \frac{1}{1+e^{-x}}\]

<p>以上就是逻辑回归的简单解释。下面我们应用真实的数据案例来进行二分类代码实践。</p>

<h2 id="12-代码实践---导入数据集">1.2 代码实践 - 导入数据集</h2>

<p>添加引用：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
</code></pre></div></div>
<p>导入数据集（大家不用在意这个域名）：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>df = pd.read_csv('https://blog.caiyongji.com/assets/hearing_test.csv')
df.head()
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th style="text-align: right">age</th>
      <th style="text-align: right">physical_score</th>
      <th style="text-align: right">test_result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">33</td>
      <td style="text-align: right">40.7</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">50</td>
      <td style="text-align: right">37.2</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">52</td>
      <td style="text-align: right">24.7</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">56</td>
      <td style="text-align: right">31</td>
      <td style="text-align: right">0</td>
    </tr>
    <tr>
      <td style="text-align: right">35</td>
      <td style="text-align: right">42.9</td>
      <td style="text-align: right">1</td>
    </tr>
  </tbody>
</table>

<p>该数据集，对5000名参与者进行了一项实验，以研究年龄和身体健康对听力损失的影响，尤其是听高音的能力。此数据显示了研究结果对参与者进行了身体能力的评估和评分，然后必须进行音频测试（通过/不通过），以评估他们听到高频的能力。</p>

<ul>
  <li><strong>特征</strong>：1. 年龄 2. 健康得分</li>
  <li><strong>标签</strong>：（1通过/0不通过）</li>
</ul>

<h2 id="13-观察数据">1.3 观察数据</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.scatterplot(x='age',y='physical_score',data=df,hue='test_result')
</code></pre></div></div>
<p>我们用<code class="language-plaintext highlighter-rouge">seaborn</code>绘制年龄和健康得分特征对应测试结果的散点图。</p>

<p><img src="/assets/images/20210201/3.png" alt="image" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.pairplot(df,hue='test_result')
</code></pre></div></div>
<p>我们通过<code class="language-plaintext highlighter-rouge">pairplot</code>方法绘制特征两两之间的对应关系。</p>

<p><img src="/assets/images/20210201/4.png" alt="image" /></p>

<p>我们可以大致做出判断，当年龄超过60很难通过测试，通过测试者普遍健康得分超过30。</p>

<h2 id="14-训练模型">1.4 训练模型</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score,classification_report,plot_confusion_matrix

#准备数据
X = df.drop('test_result',axis=1)
y = df['test_result']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=50)
scaler = StandardScaler()
scaled_X_train = scaler.fit_transform(X_train)
scaled_X_test = scaler.transform(X_test)

#定义模型
log_model = LogisticRegression()

#训练模型
log_model.fit(scaled_X_train,y_train)

#预测数据
y_pred = log_model.predict(scaled_X_test)
accuracy_score(y_test,y_pred)
</code></pre></div></div>
<p>我们经过准备数据，定义模型为<code class="language-plaintext highlighter-rouge">LogisticRegression</code>逻辑回归模型，通过<code class="language-plaintext highlighter-rouge">fit</code>方法拟合训练数据，最后通过<code class="language-plaintext highlighter-rouge">predict</code>方法进行预测。<br />
最终我们调用<code class="language-plaintext highlighter-rouge">accuracy_score</code>方法得到模型的准确率为92.2%。</p>

<h1 id="二模型性能评估准确率精确度召回率">二、模型性能评估：准确率、精确度、召回率</h1>

<p>我们是如何得到准确率是92.2%的呢？我们调用<code class="language-plaintext highlighter-rouge">plot_confusion_matrix</code>方法绘制混淆矩阵。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plot_confusion_matrix(log_model,scaled_X_test,y_test)
</code></pre></div></div>
<p>我们观察500个测试实例，得到矩阵如下：</p>

<p><img src="/assets/images/20210201/5.png" alt="image" /></p>

<p>我们对以上矩阵进行定义如下：</p>

<ul>
  <li><strong>真正类TP(True Positive)</strong> ：预测为正，实际结果为正。如，上图右下角285。</li>
  <li><strong>真负类TN(True Negative)</strong> ：预测为负，实际结果为负。如，上图左上角176。</li>
  <li><strong>假正类FP(False Positive)</strong> ：预测为正，实际结果为负。如，上图左下角19。</li>
  <li><strong>假负类FN(False Negative)</strong> ：预测为负，实际结果为正。如，上图右上角20。</li>
</ul>

<p><strong>准确率(Accuracy)</strong> 公式如下：</p>

\[Accuracy = \frac{TP+TN}{TP+TN+FP+FN}\]

<p>带入本例得：</p>

\[Accuracy = \frac{285+176}{285+176+20+19} = 0.922\]

<p><strong>精确度(Precision)</strong> 公式如下：</p>

\[Precision = \frac{TP}{TP+FP}\]

<p>带入本例得：<br />
\(Precision = \frac{285}{285+19} = 0.9375\)</p>

<p><strong>召回率(Recall)</strong> 公式如下：</p>

\[Recall = \frac{TP}{TP+FN}\]

<p>带入本例得：</p>

\[Recall = \frac{285}{285+20} = 0.934\]

<p>我们调用<code class="language-plaintext highlighter-rouge">classification_report</code>方法可验证结果。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>print(classification_report(y_test,y_pred))
</code></pre></div></div>

<p><img src="/assets/images/20210201/6.png" alt="image" /></p>

<h1 id="三softmax多分类">三、Softmax：多分类</h1>

<h2 id="31-理解softmax多元逻辑回归">3.1 理解softmax多元逻辑回归</h2>

<p>Logistic回归和Softmax回归都是基于线性回归的分类模型，两者无本质区别，都是从伯努利分结合最大对数似然估计。</p>

<p><strong>最大似然估计</strong>：简单来说，最大似然估计就是利用已知的样本结果信息，反推最具有可能（最大概率）导致这些样本结果出现的模型参数值。</p>

<p><em>术语“概率”(probability)和“似然”(likelihood)在英语中经常互换使用，但是它们在统计学中的含义却大不相同。给定具有一些参数θ的统计模型，用“概率”一词描述未来的结果x的合理性（知道参数值θ），而用“似然”一词表示描述在知道结果x之后，一组特定的参数值θ的合理性。</em></p>

<p>Softmax回归模型首先计算出每个类的分数，然后对这些分数应用softmax函数，估计每个类的概率。我们预测具有最高估计概率的类，简单来说就是找得分最高的类。</p>

<h2 id="32-代码实践---导入数据集">3.2 代码实践 - 导入数据集</h2>

<p>导入数据集（大家不用在意这个域名）：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>df = pd.read_csv('https://blog.caiyongji.com/assets/iris.csv')
df.head()
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th style="text-align: right">sepal_length</th>
      <th style="text-align: right">sepal_width</th>
      <th style="text-align: right">petal_length</th>
      <th style="text-align: right">petal_width</th>
      <th style="text-align: left">species</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">5.1</td>
      <td style="text-align: right">3.5</td>
      <td style="text-align: right">1.4</td>
      <td style="text-align: right">0.2</td>
      <td style="text-align: left">setosa</td>
    </tr>
    <tr>
      <td style="text-align: right">4.9</td>
      <td style="text-align: right">3</td>
      <td style="text-align: right">1.4</td>
      <td style="text-align: right">0.2</td>
      <td style="text-align: left">setosa</td>
    </tr>
    <tr>
      <td style="text-align: right">4.7</td>
      <td style="text-align: right">3.2</td>
      <td style="text-align: right">1.3</td>
      <td style="text-align: right">0.2</td>
      <td style="text-align: left">setosa</td>
    </tr>
    <tr>
      <td style="text-align: right">4.6</td>
      <td style="text-align: right">3.1</td>
      <td style="text-align: right">1.5</td>
      <td style="text-align: right">0.2</td>
      <td style="text-align: left">setosa</td>
    </tr>
    <tr>
      <td style="text-align: right">5</td>
      <td style="text-align: right">3.6</td>
      <td style="text-align: right">1.4</td>
      <td style="text-align: right">0.2</td>
      <td style="text-align: left">setosa</td>
    </tr>
  </tbody>
</table>

<p>该数据集，包含150个鸢尾花样本数据，数据特征包含花瓣的长度和宽度和萼片的长度和宽度，包含三个属种的鸢尾花，分别是山鸢尾(setosa)、变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica)。</p>

<ul>
  <li><strong>特征</strong>：1. 花萼长度 2. 花萼宽度 3. 花瓣长度 4 花萼宽度</li>
  <li><strong>标签</strong>：种类：山鸢尾(setosa)、变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica)</li>
</ul>

<h2 id="33-观察数据">3.3 观察数据</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.scatterplot(x='sepal_length',y='sepal_width',data=df,hue='species')
</code></pre></div></div>
<p>我们用<code class="language-plaintext highlighter-rouge">seaborn</code>绘制<strong>花萼</strong>长度和宽度特征对应鸢尾花种类的散点图。</p>

<p><img src="/assets/images/20210201/7.png" alt="image" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.scatterplot(x='petal_length',y='petal_width',data=df,hue='species')
</code></pre></div></div>
<p>我们用<code class="language-plaintext highlighter-rouge">seaborn</code>绘制<strong>花瓣</strong>长度和宽度特征对应鸢尾花种类的散点图。</p>

<p><img src="/assets/images/20210201/8.png" alt="image" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sns.pairplot(df,hue='species')
</code></pre></div></div>
<p>我们通过<code class="language-plaintext highlighter-rouge">pairplot</code>方法绘制特征两两之间的对应关系。</p>

<p><img src="/assets/images/20210201/9.png" alt="image" /></p>

<p>我们可以大致做出判断，综合考虑花瓣和花萼尺寸最小的为山鸢尾花，中等尺寸的为变色鸢尾花，尺寸最大的为维吉尼亚鸢尾花。</p>

<h2 id="34-训练模型">3.4 训练模型</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#准备数据
X = df.drop('species',axis=1)
y = df['species']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=50)
scaler = StandardScaler()
scaled_X_train = scaler.fit_transform(X_train)
scaled_X_test = scaler.transform(X_test)

#定义模型
softmax_model = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10, random_state=50)

#训练模型
softmax_model.fit(scaled_X_train,y_train)

#预测数据
y_pred = softmax_model.predict(scaled_X_test)
accuracy_score(y_test,y_pred)
</code></pre></div></div>
<p>我们经过准备数据，定义模型<code class="language-plaintext highlighter-rouge">LogisticRegression</code>的<code class="language-plaintext highlighter-rouge">multi_class="multinomial"</code>多元逻辑回归模型，设置求解器为<code class="language-plaintext highlighter-rouge">lbfgs</code>，通过<code class="language-plaintext highlighter-rouge">fit</code>方法拟合训练数据，最后通过<code class="language-plaintext highlighter-rouge">predict</code>方法进行预测。<br />
最终我们调用<code class="language-plaintext highlighter-rouge">accuracy_score</code>方法得到模型的准确率为92.1%。</p>

<p>我们调用<code class="language-plaintext highlighter-rouge">classification_report</code>方法查看准确率、精确度、召回率。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>print(classification_report(y_test,y_pred))
</code></pre></div></div>

<p><img src="/assets/images/20210201/10.png" alt="image" /></p>

<h2 id="35-拓展绘制花瓣分类">3.5 拓展：绘制花瓣分类</h2>

<p>我们仅提取花瓣长度和花瓣宽度的特征来绘制鸢尾花的分类图像。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#提取特征
X = df[['petal_length','petal_width']].to_numpy() 
y = df["species"].factorize(['setosa', 'versicolor','virginica'])[0]

#定义模型
softmax_reg = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10, random_state=50)

#训练模型
softmax_reg.fit(X, y)

#随机测试数据
x0, x1 = np.meshgrid(
        np.linspace(0, 8, 500).reshape(-1, 1),
        np.linspace(0, 3.5, 200).reshape(-1, 1),
    )
X_new = np.c_[x0.ravel(), x1.ravel()]

#预测
y_proba = softmax_reg.predict_proba(X_new)
y_predict = softmax_reg.predict(X_new)

#绘制图像
zz1 = y_proba[:, 1].reshape(x0.shape)
zz = y_predict.reshape(x0.shape)
plt.figure(figsize=(10, 4))
plt.plot(X[y==2, 0], X[y==2, 1], "g^", label="Iris virginica")
plt.plot(X[y==1, 0], X[y==1, 1], "bs", label="Iris versicolor")
plt.plot(X[y==0, 0], X[y==0, 1], "yo", label="Iris setosa")
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0'])
plt.contourf(x0, x1, zz, cmap=custom_cmap)
contour = plt.contour(x0, x1, zz1, cmap=plt.cm.brg)
plt.clabel(contour, inline=1, fontsize=12)
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
plt.legend(loc="center left", fontsize=14)
plt.axis([0, 7, 0, 3.5])
plt.show()
</code></pre></div></div>

<p>得到鸢尾花根据花瓣分类的图像如下：</p>

<p><img src="/assets/images/20210201/11.png" alt="image" /></p>

<h1 id="四小结">四、小结</h1>

<p>相比于概念的理解，本文更侧重上手实践，通过动手编程你应该有“手热”的感觉了。截至到本文，你应该对机器学习的概念有了一定的掌握，我们简单梳理一下：</p>

<ol>
  <li>机器学习的分类</li>
  <li>机器学习的工业化流程</li>
  <li>特征、标签、实例、模型的概念</li>
  <li>过拟合、欠拟合</li>
  <li>损失函数、最小二乘法</li>
  <li>梯度下降、学习率
7.线性回归、逻辑回归、多项式回归、逐步回归、岭回归、套索(Lasso)回归、弹性网络(ElasticNet)回归是最常用的回归技术</li>
  <li>Sigmoid函数、Softmax函数、最大似然估计</li>
</ol>

<p>如果你还有不清楚的地方请参考：</p>

<ul>
  <li><a href="https://mp.weixin.qq.com/s/_bHi-XH5ZXI4jDUzwH3xpQ">机器学习(二)：理解线性回归与梯度下降并做简单预测</a></li>
  <li><a href="https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q">机器学习(一)：5分钟理解机器学习并上手实践</a></li>
  <li><a href="https://mp.weixin.qq.com/s/5brLPnUP6sYvc-_JO7IzkA">前置机器学习（五）：30分钟掌握常用Matplotlib用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/LlLkkBfI-4s3qdVaiv7EdQ">前置机器学习（四）：一文掌握Pandas用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/U8dV8ENzzSx_VwBDdJdr_w">前置机器学习（三）：30分钟掌握常用NumPy用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/PCGThwI-YD7_hHxO35V8xw">前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法</a></li>
  <li><a href="https://mp.weixin.qq.com/s/BLxyqK3CGV9yd92yGEs4XQ">前置机器学习（一）：数学符号及希腊字母</a></li>
</ul>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="机器学习" /><category term="逻辑回归" /><category term="Softmax回归" /><summary type="html"><![CDATA[本文是机器学习系列的第三篇，算上前置机器学习系列是第八篇。本文的概念相对简单，主要侧重于代码实践。 上一篇文章说到，我们可以用线性回归做预测，但显然现实生活中不止有预测的问题还有分类的问题。我们可以从预测值的类型上简单区分：连续变量的预测为回归，离散变量的预测为分类。 一、逻辑回归：二分类 1.1 理解逻辑回归 我们把连续的预测值进行人工定义，边界的一边定义为1，另一边定义为0。这样我们就把回归问题转换成了分类问题。 如上图，我们把连续的变量分布压制在0-1的范围内，并以0.5作为我们分类决策的边界，大于0.5的概率则判别为1，小于0.5的概率则判别为0。 我们无法使用无穷大和负无穷大进行算术运算，我们通过逻辑回归函数（Sigmoid函数/S型函数/Logistic函数）可以讲数值计算限定在0-1之间。 \[\sigma(x) = \frac{1}{1+e^{-x}}\] 以上就是逻辑回归的简单解释。下面我们应用真实的数据案例来进行二分类代码实践。 1.2 代码实践 - 导入数据集 添加引用： import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt 导入数据集（大家不用在意这个域名）： df = pd.read_csv('https://blog.caiyongji.com/assets/hearing_test.csv') df.head() age physical_score test_result 33 40.7 1 50 37.2 1 52 24.7 0 56 31 0 35 42.9 1 该数据集，对5000名参与者进行了一项实验，以研究年龄和身体健康对听力损失的影响，尤其是听高音的能力。此数据显示了研究结果对参与者进行了身体能力的评估和评分，然后必须进行音频测试（通过/不通过），以评估他们听到高频的能力。 特征：1. 年龄 2. 健康得分 标签：（1通过/0不通过） 1.3 观察数据 sns.scatterplot(x='age',y='physical_score',data=df,hue='test_result') 我们用seaborn绘制年龄和健康得分特征对应测试结果的散点图。 sns.pairplot(df,hue='test_result') 我们通过pairplot方法绘制特征两两之间的对应关系。 我们可以大致做出判断，当年龄超过60很难通过测试，通过测试者普遍健康得分超过30。 1.4 训练模型 from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score,classification_report,plot_confusion_matrix #准备数据 X = df.drop('test_result',axis=1) y = df['test_result'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=50) scaler = StandardScaler() scaled_X_train = scaler.fit_transform(X_train) scaled_X_test = scaler.transform(X_test) #定义模型 log_model = LogisticRegression() #训练模型 log_model.fit(scaled_X_train,y_train) #预测数据 y_pred = log_model.predict(scaled_X_test) accuracy_score(y_test,y_pred) 我们经过准备数据，定义模型为LogisticRegression逻辑回归模型，通过fit方法拟合训练数据，最后通过predict方法进行预测。 最终我们调用accuracy_score方法得到模型的准确率为92.2%。 二、模型性能评估：准确率、精确度、召回率 我们是如何得到准确率是92.2%的呢？我们调用plot_confusion_matrix方法绘制混淆矩阵。 plot_confusion_matrix(log_model,scaled_X_test,y_test) 我们观察500个测试实例，得到矩阵如下： 我们对以上矩阵进行定义如下： 真正类TP(True Positive) ：预测为正，实际结果为正。如，上图右下角285。 真负类TN(True Negative) ：预测为负，实际结果为负。如，上图左上角176。 假正类FP(False Positive) ：预测为正，实际结果为负。如，上图左下角19。 假负类FN(False Negative) ：预测为负，实际结果为正。如，上图右上角20。 准确率(Accuracy) 公式如下： \[Accuracy = \frac{TP+TN}{TP+TN+FP+FN}\] 带入本例得： \[Accuracy = \frac{285+176}{285+176+20+19} = 0.922\] 精确度(Precision) 公式如下： \[Precision = \frac{TP}{TP+FP}\] 带入本例得： \(Precision = \frac{285}{285+19} = 0.9375\) 召回率(Recall) 公式如下： \[Recall = \frac{TP}{TP+FN}\] 带入本例得： \[Recall = \frac{285}{285+20} = 0.934\] 我们调用classification_report方法可验证结果。 print(classification_report(y_test,y_pred)) 三、Softmax：多分类 3.1 理解softmax多元逻辑回归 Logistic回归和Softmax回归都是基于线性回归的分类模型，两者无本质区别，都是从伯努利分结合最大对数似然估计。 最大似然估计：简单来说，最大似然估计就是利用已知的样本结果信息，反推最具有可能（最大概率）导致这些样本结果出现的模型参数值。 术语“概率”(probability)和“似然”(likelihood)在英语中经常互换使用，但是它们在统计学中的含义却大不相同。给定具有一些参数θ的统计模型，用“概率”一词描述未来的结果x的合理性（知道参数值θ），而用“似然”一词表示描述在知道结果x之后，一组特定的参数值θ的合理性。 Softmax回归模型首先计算出每个类的分数，然后对这些分数应用softmax函数，估计每个类的概率。我们预测具有最高估计概率的类，简单来说就是找得分最高的类。 3.2 代码实践 - 导入数据集 导入数据集（大家不用在意这个域名）： df = pd.read_csv('https://blog.caiyongji.com/assets/iris.csv') df.head() sepal_length sepal_width petal_length petal_width species 5.1 3.5 1.4 0.2 setosa 4.9 3 1.4 0.2 setosa 4.7 3.2 1.3 0.2 setosa 4.6 3.1 1.5 0.2 setosa 5 3.6 1.4 0.2 setosa 该数据集，包含150个鸢尾花样本数据，数据特征包含花瓣的长度和宽度和萼片的长度和宽度，包含三个属种的鸢尾花，分别是山鸢尾(setosa)、变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica)。 特征：1. 花萼长度 2. 花萼宽度 3. 花瓣长度 4 花萼宽度 标签：种类：山鸢尾(setosa)、变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica) 3.3 观察数据 sns.scatterplot(x='sepal_length',y='sepal_width',data=df,hue='species') 我们用seaborn绘制花萼长度和宽度特征对应鸢尾花种类的散点图。 sns.scatterplot(x='petal_length',y='petal_width',data=df,hue='species') 我们用seaborn绘制花瓣长度和宽度特征对应鸢尾花种类的散点图。 sns.pairplot(df,hue='species') 我们通过pairplot方法绘制特征两两之间的对应关系。 我们可以大致做出判断，综合考虑花瓣和花萼尺寸最小的为山鸢尾花，中等尺寸的为变色鸢尾花，尺寸最大的为维吉尼亚鸢尾花。 3.4 训练模型 #准备数据 X = df.drop('species',axis=1) y = df['species'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=50) scaler = StandardScaler() scaled_X_train = scaler.fit_transform(X_train) scaled_X_test = scaler.transform(X_test) #定义模型 softmax_model = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10, random_state=50) #训练模型 softmax_model.fit(scaled_X_train,y_train) #预测数据 y_pred = softmax_model.predict(scaled_X_test) accuracy_score(y_test,y_pred) 我们经过准备数据，定义模型LogisticRegression的multi_class="multinomial"多元逻辑回归模型，设置求解器为lbfgs，通过fit方法拟合训练数据，最后通过predict方法进行预测。 最终我们调用accuracy_score方法得到模型的准确率为92.1%。 我们调用classification_report方法查看准确率、精确度、召回率。 print(classification_report(y_test,y_pred)) 3.5 拓展：绘制花瓣分类 我们仅提取花瓣长度和花瓣宽度的特征来绘制鸢尾花的分类图像。 #提取特征 X = df[['petal_length','petal_width']].to_numpy() y = df["species"].factorize(['setosa', 'versicolor','virginica'])[0] #定义模型 softmax_reg = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10, random_state=50) #训练模型 softmax_reg.fit(X, y) #随机测试数据 x0, x1 = np.meshgrid( np.linspace(0, 8, 500).reshape(-1, 1), np.linspace(0, 3.5, 200).reshape(-1, 1), ) X_new = np.c_[x0.ravel(), x1.ravel()] #预测 y_proba = softmax_reg.predict_proba(X_new) y_predict = softmax_reg.predict(X_new) #绘制图像 zz1 = y_proba[:, 1].reshape(x0.shape) zz = y_predict.reshape(x0.shape) plt.figure(figsize=(10, 4)) plt.plot(X[y==2, 0], X[y==2, 1], "g^", label="Iris virginica") plt.plot(X[y==1, 0], X[y==1, 1], "bs", label="Iris versicolor") plt.plot(X[y==0, 0], X[y==0, 1], "yo", label="Iris setosa") from matplotlib.colors import ListedColormap custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0']) plt.contourf(x0, x1, zz, cmap=custom_cmap) contour = plt.contour(x0, x1, zz1, cmap=plt.cm.brg) plt.clabel(contour, inline=1, fontsize=12) plt.xlabel("Petal length", fontsize=14) plt.ylabel("Petal width", fontsize=14) plt.legend(loc="center left", fontsize=14) plt.axis([0, 7, 0, 3.5]) plt.show() 得到鸢尾花根据花瓣分类的图像如下： 四、小结 相比于概念的理解，本文更侧重上手实践，通过动手编程你应该有“手热”的感觉了。截至到本文，你应该对机器学习的概念有了一定的掌握，我们简单梳理一下： 机器学习的分类 机器学习的工业化流程 特征、标签、实例、模型的概念 过拟合、欠拟合 损失函数、最小二乘法 梯度下降、学习率 7.线性回归、逻辑回归、多项式回归、逐步回归、岭回归、套索(Lasso)回归、弹性网络(ElasticNet)回归是最常用的回归技术 Sigmoid函数、Softmax函数、最大似然估计 如果你还有不清楚的地方请参考： 机器学习(二)：理解线性回归与梯度下降并做简单预测 机器学习(一)：5分钟理解机器学习并上手实践 前置机器学习（五）：30分钟掌握常用Matplotlib用法 前置机器学习（四）：一文掌握Pandas用法 前置机器学习（三）：30分钟掌握常用NumPy用法 前置机器学习（二）：30分钟掌握常用Jupyter Notebook用法 前置机器学习（一）：数学符号及希腊字母]]></summary></entry><entry><title type="html">机器学习(二)：理解线性回归与梯度下降并做简单预测</title><link href="/2021/01/19/machine-learning-2.html" rel="alternate" type="text/html" title="机器学习(二)：理解线性回归与梯度下降并做简单预测" /><published>2021-01-19T00:00:00+00:00</published><updated>2021-01-19T00:00:00+00:00</updated><id>/2021/01/19/machine-learning-2</id><content type="html" xml:base="/2021/01/19/machine-learning-2.html"><![CDATA[<h1 id="预测从瞎猜开始">预测从瞎猜开始</h1>

<p>按<a href="https://mp.weixin.qq.com/s/-KsbtgOc3C3ry-8P5f8K-Q">上一篇文章</a>所说，机器学习是应用数学方法在数据中发现规律的过程。既然数学是对现实世界的解释，那么我们回归现实世界，做一些对照的想象。</p>

<p>想象我们面前有一块塑料泡沫做的白板，白板上分布排列着数枚蓝色的图钉，隐约地它们似乎存在着某种规律，我们试着找出规律。</p>

<p><img src="/assets/images/20210119/1.png" alt="image" /></p>

<p>白板上的图钉（<strong>数据</strong>）如上图所示，我们有没有一种方法（<strong>数学算法</strong>）来寻找规律（<strong>模型解释</strong>）呢？  既然不知道怎么做，那我们瞎猜吧！</p>

<p>我拿起两根木棒在白板前比划，试着用木棒表示数据的规律。我随便放了放，如下图所示：</p>

<p><img src="/assets/images/20210119/2.png" alt="image" /></p>

<p>它们似乎都在一定程度上能表示蓝色图钉的规律，那么问题来了，绿色（虚线）和红色（实线）哪一个表示更好呢？</p>

<h1 id="损失函数成本函数">损失函数（成本函数）</h1>

<p>好与坏是很主观的表达，主观的感受是不可靠的，我们必须找到一种客观的度量方式。我们想当然的认为误差最小的表示，是最好的。那么，我们引出一种量化误差的方法—最小二乘法。</p>

<p><strong>最小二乘法</strong>：使误差的平方和最小的办法，是一种误差统计方法，二乘就是平方的意思。<br />
$ SE = \sum{(y_{pred} -y_{true})^2} $</p>

<p>最小二乘法的解释是这样的，我们用<code class="language-plaintext highlighter-rouge">预测值-实际值</code>表示单点的误差，再把它们的<code class="language-plaintext highlighter-rouge">平方和</code>加到一起来表示整体误差。（<em>平方的好处可以处理掉负数值，用绝对值的和也不是不可以。</em>）我们用这个最终值来表示损失（成本），而可以表示损失（成本）的函数就叫做损失函数（成本函数）。</p>

<p><img src="/assets/images/20210119/3.png" alt="image" /></p>

<p>如上图我们可以看到，蓝色点到实线的距离就是我们要带入公式的误差。虽然它们看上去相近，但经过计算的结果是红色实线(<code class="language-plaintext highlighter-rouge">y=3x+2</code>)的损失为27.03，而绿色实线（<code class="language-plaintext highlighter-rouge">y=4x+4</code>）的损失为29.54，显然红色模型优于绿色模型。</p>

<p>那么，还有没有比红色实线更好的模型来表示数据呢？有没有一种方式来找到它呢？</p>

<h1 id="梯度下降">梯度下降</h1>

<p>我们把木棒（实线、模型）的表示数学化，我们既然可以用3、4做为x的系数，那我们当然可以尝试别的数字。我们用如下公式表示这种关系：</p>

<p>$ y = wx + b $</p>

<p>其中，x和y是已知的，我们不断调整<code class="language-plaintext highlighter-rouge">w</code>(<strong>权重</strong>)和<code class="language-plaintext highlighter-rouge">b</code>(<strong>偏差</strong>)，然后再带入损失函数以求得最小值的过程，就是<strong>梯度下降</strong>。</p>

<p>我们从-50开始到50结束设置<code class="language-plaintext highlighter-rouge">w</code>的值，我们通过随机数来设置偏置<code class="language-plaintext highlighter-rouge">b</code>，然后再带入损失函数计算我们的预测和实际值的误差损失，得到如下曲线：</p>

<p><img src="/assets/images/20210119/4.png" alt="image" /></p>

<p><strong>需要注意的是，我们绘制的图像是根据权重和损失绘制的曲线。而我们的模型表示是一条直线。</strong><br />
我们可以看到，在上图中我们是可以找到极小值的，大概在5左右，此处是我们损失最小的位置，这时我们的模型最能表示数据的规律。</p>

<p>梯度可以<strong>完全</strong>理解为导数，梯度下降的过程就是我们不断求导的过程。</p>

<h1 id="学习率步长">学习率（步长）</h1>

<p>不断调整权重和偏差来来寻找损失函数最小值的过程就是我们使用梯度下降方法拟合数据寻找最佳模型的过程。那么既然我们有了解决方案，是不是该考虑如何提升效率了，我们如何快速地找到最低点？</p>

<p>想象一下，当你迷失在山上的浓雾之中，你能感觉到的只有你脚下路面的坡度。快速到达山脚的一个策略就是沿着最陡的方向下坡。梯度下降中的一个重要的参数就是每一步的<strong>步长</strong>（<strong>学习率</strong>），如果步长太小，算法需要经过大量迭代才会收敛，如果步长太大，你可能会直接越过山谷，导致算法发散，值越来越大。</p>

<p>设置步长为过小：</p>

<p><img src="/assets/images/20210119/5.gif" alt="image" /></p>

<p>设置步长过大：</p>

<p><img src="/assets/images/20210119/6.gif" alt="image" /></p>

<p>设置步长适当：</p>

<p><img src="/assets/images/20210119/7.gif" alt="image" /></p>

<p>步长是算法自己学习不出来的，它必须由外界指定。<br />
这种算法不能学习，需要人为设定的参数，就叫做<strong>超参数</strong>。</p>

<h1 id="线性回归">线性回归</h1>

<p>最终我们找到了<strong>线性</strong>模型来解释自变量x与因变量y之间的关系，这就是<strong>线性回归</strong>。回归的解释是，事物总是倾向于朝着某种“平均”发展，这种<strong>趋势</strong>叫做回归，所以回归多用于预测。</p>

<p><img src="/assets/images/20210119/8.png" alt="image" /></p>

<p>上图，红线是我们拟合出的最佳模型，在此模型上我们可以寻找到2.2，2.6，2.8的预测值，分别对应图中的三个红点。</p>

<p>这也是线性回归的基本意义。</p>

<h1 id="代码实践">代码实践</h1>

<p>准备数据：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
X = 2 * np.random.rand(10)
y = 4 + 3 * X + np.random.randn(10)

plt.plot(X, y, "bo")
plt.xlabel("$X$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([0, 2, 0, 15])
plt.show()
</code></pre></div></div>

<p>绘制<code class="language-plaintext highlighter-rouge">y=3x+2</code>和<code class="language-plaintext highlighter-rouge">y=4x+4</code>两条直线：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plt.plot(X, y, "bo")
plt.plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2")
plt.plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4")
plt.xlabel("$X$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([0, 2, 0, 15])
plt.legend(loc="upper left")
plt.show()
</code></pre></div></div>

<p>计算损失，并比较<code class="language-plaintext highlighter-rouge">y=3x+2</code>和<code class="language-plaintext highlighter-rouge">y=4x+4</code>两条直线：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fig, ax_list = plt.subplots(nrows=1, ncols=2,figsize=(20,10))
ax_list[0].plot(X, y, "bo")
ax_list[0].plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2")
loss = 0
for i in range(10):
    ax_list[0].plot([X[i],X[i]], [y[i],3*X[i]+2], color='grey')
    loss= loss + np.square(3*X[i]+2-y[i])
    pass
ax_list[0].axis([0, 2, 0, 15])
ax_list[0].legend(loc="upper left")
ax_list[0].title.set_text('loss=%s'%loss)


ax_list[1].plot(X, y, "bo")
ax_list[1].plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4")
loss = 0
for i in range(10):
    ax_list[1].plot([X[i],X[i]], [y[i],4*X[i]+4], color='grey')
    loss= loss + np.square(4*X[i]+4-y[i])
    pass
ax_list[1].axis([0, 2, 0, 15])
ax_list[1].legend(loc="upper left")
ax_list[1].title.set_text('loss=%s'%loss)
fig.subplots_adjust(wspace=0.1,hspace=0.5)
fig.suptitle("Calculate loss",fontsize=16)
</code></pre></div></div>

<p>训练模型，并预测：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X.reshape(-1,1),y.reshape(-1,1))

X_test = [[2.2],[2.6],[2.8]]
y_test = lr.predict(X_test)
X_pred = 3 * np.random.rand(100, 1)
y_pred = lr.predict(X_pred)
plt.scatter(X,y, c='b', label='real')
plt.plot(X_test,y_test, 'r', label='predicted point' ,marker=".", ms=20)
plt.plot(X_pred,y_pred, 'r-', label='predicted')
plt.xlabel("$X$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.axis([0, 3, 0, 15])
plt.legend(loc="upper left")
loss = 0
for i in range(10):
    loss = loss + np.square(y[i]-lr.predict([[X[i]]]))
plt.title("loss=%s"%loss)
plt.show()
</code></pre></div></div>

<h1 id="其他回归">其他回归</h1>

<p>要怎么真正理解回归(regression)呢？通过大量的数据统计，个体小的豆子往往倾向于产生比其更大的后代，而个体大的豆子往往倾向于产生比其更小的后代，新产生的个体有向着豆子的平均值的一种趋势，这种趋势就是回归。我们本篇文章讲的线性回归就是应用于<strong>预测</strong>的一种技术。这时，回归往往与分类相对。</p>

<p>线性回归、逻辑回归、多项式回归、逐步回归、岭回归、套索(Lasso)回归、弹性网络(ElasticNet)回归是最常用的回归技术。我先对这些技术做一个简单整理，让大家把脉络理清，等大家实际需要再深入探索。<strong>试图去穷尽知识只会把自己拖向疲累</strong>。</p>

<table>
  <thead>
    <tr>
      <th>名称</th>
      <th>解释</th>
      <th>公式</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>线性回归(Linear Regression)</td>
      <td>一种以线性模型来建模自变量与因变量关系的方法</td>
      <td>$ y = wx+b $</td>
    </tr>
    <tr>
      <td>逻辑回归(Logistic Regression)</td>
      <td>对特定类别进行建模，用于二分类</td>
      <td>$ y=\frac{1}{1+e^{-x}} $</td>
    </tr>
    <tr>
      <td>多项式回归(Polynomial Regression)</td>
      <td>自变量 x 和因变量 y 之间的关系被建模为关于 x 的 n 次多项式</td>
      <td>$ y=\beta_0 + \beta_1x + \beta_2x^2 + … + \beta_mx^m + \varepsilon $ （cαiyongji水印）</td>
    </tr>
    <tr>
      <td>逐步回归(Stepwise Regression)</td>
      <td>将多个变量一个一个地引入到模型，找到其对模型影响大的变量</td>
      <td> </td>
    </tr>
    <tr>
      <td>套索回归(Lasso Regression)</td>
      <td>稀疏矩阵，消除不重要的特征，MSE+L1范数</td>
      <td>$ J(\theta)=MSE(\theta) + \alpha\sum\mid\theta\mid $ ，其中，α越大模型权重越小</td>
    </tr>
    <tr>
      <td>岭回归(Ridge Regression)</td>
      <td>正则化线性回归，增加模型自由度，防止过拟合，MSE+L2范数</td>
      <td>$ J(\theta)=MSE(\theta) + \alpha\frac{1}{2}\sum\theta^2 $  ，其中，α越大模型权重越小</td>
    </tr>
    <tr>
      <td>弹性网络(ElasticNet)</td>
      <td>介于岭回归和Lasso回归之间</td>
      <td>$ J(\theta)=MSE(\theta) + \gamma\alpha\sum\mid\theta\mid + \alpha\frac{1-\gamma}{2}\sum\theta^2 $ ，其中，γ介于0和1之间，接近0则更倾向于岭回归，接近1则更倾向于Lasso回归</td>
    </tr>
  </tbody>
</table>]]></content><author><name>caiyongji</name><email>i@caiyongji.com</email></author><category term="机器学习" /><category term="梯度下降" /><category term="线性回归" /><category term="损失函数" /><category term="成本函数" /><summary type="html"><![CDATA[预测从瞎猜开始 按上一篇文章所说，机器学习是应用数学方法在数据中发现规律的过程。既然数学是对现实世界的解释，那么我们回归现实世界，做一些对照的想象。 想象我们面前有一块塑料泡沫做的白板，白板上分布排列着数枚蓝色的图钉，隐约地它们似乎存在着某种规律，我们试着找出规律。 白板上的图钉（数据）如上图所示，我们有没有一种方法（数学算法）来寻找规律（模型解释）呢？ 既然不知道怎么做，那我们瞎猜吧！ 我拿起两根木棒在白板前比划，试着用木棒表示数据的规律。我随便放了放，如下图所示： 它们似乎都在一定程度上能表示蓝色图钉的规律，那么问题来了，绿色（虚线）和红色（实线）哪一个表示更好呢？ 损失函数（成本函数） 好与坏是很主观的表达，主观的感受是不可靠的，我们必须找到一种客观的度量方式。我们想当然的认为误差最小的表示，是最好的。那么，我们引出一种量化误差的方法—最小二乘法。 最小二乘法：使误差的平方和最小的办法，是一种误差统计方法，二乘就是平方的意思。 $ SE = \sum{(y_{pred} -y_{true})^2} $ 最小二乘法的解释是这样的，我们用预测值-实际值表示单点的误差，再把它们的平方和加到一起来表示整体误差。（平方的好处可以处理掉负数值，用绝对值的和也不是不可以。）我们用这个最终值来表示损失（成本），而可以表示损失（成本）的函数就叫做损失函数（成本函数）。 如上图我们可以看到，蓝色点到实线的距离就是我们要带入公式的误差。虽然它们看上去相近，但经过计算的结果是红色实线(y=3x+2)的损失为27.03，而绿色实线（y=4x+4）的损失为29.54，显然红色模型优于绿色模型。 那么，还有没有比红色实线更好的模型来表示数据呢？有没有一种方式来找到它呢？ 梯度下降 我们把木棒（实线、模型）的表示数学化，我们既然可以用3、4做为x的系数，那我们当然可以尝试别的数字。我们用如下公式表示这种关系： $ y = wx + b $ 其中，x和y是已知的，我们不断调整w(权重)和b(偏差)，然后再带入损失函数以求得最小值的过程，就是梯度下降。 我们从-50开始到50结束设置w的值，我们通过随机数来设置偏置b，然后再带入损失函数计算我们的预测和实际值的误差损失，得到如下曲线： 需要注意的是，我们绘制的图像是根据权重和损失绘制的曲线。而我们的模型表示是一条直线。 我们可以看到，在上图中我们是可以找到极小值的，大概在5左右，此处是我们损失最小的位置，这时我们的模型最能表示数据的规律。 梯度可以完全理解为导数，梯度下降的过程就是我们不断求导的过程。 学习率（步长） 不断调整权重和偏差来来寻找损失函数最小值的过程就是我们使用梯度下降方法拟合数据寻找最佳模型的过程。那么既然我们有了解决方案，是不是该考虑如何提升效率了，我们如何快速地找到最低点？ 想象一下，当你迷失在山上的浓雾之中，你能感觉到的只有你脚下路面的坡度。快速到达山脚的一个策略就是沿着最陡的方向下坡。梯度下降中的一个重要的参数就是每一步的步长（学习率），如果步长太小，算法需要经过大量迭代才会收敛，如果步长太大，你可能会直接越过山谷，导致算法发散，值越来越大。 设置步长为过小： 设置步长过大： 设置步长适当： 步长是算法自己学习不出来的，它必须由外界指定。 这种算法不能学习，需要人为设定的参数，就叫做超参数。 线性回归 最终我们找到了线性模型来解释自变量x与因变量y之间的关系，这就是线性回归。回归的解释是，事物总是倾向于朝着某种“平均”发展，这种趋势叫做回归，所以回归多用于预测。 上图，红线是我们拟合出的最佳模型，在此模型上我们可以寻找到2.2，2.6，2.8的预测值，分别对应图中的三个红点。 这也是线性回归的基本意义。 代码实践 准备数据： import numpy as np import matplotlib.pyplot as plt np.random.seed(42) X = 2 * np.random.rand(10) y = 4 + 3 * X + np.random.randn(10) plt.plot(X, y, "bo") plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 2, 0, 15]) plt.show() 绘制y=3x+2和y=4x+4两条直线： plt.plot(X, y, "bo") plt.plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2") plt.plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4") plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 2, 0, 15]) plt.legend(loc="upper left") plt.show() 计算损失，并比较y=3x+2和y=4x+4两条直线： fig, ax_list = plt.subplots(nrows=1, ncols=2,figsize=(20,10)) ax_list[0].plot(X, y, "bo") ax_list[0].plot(X, 3*X+2, "r-", lw="5", label = "y=3x+2") loss = 0 for i in range(10): ax_list[0].plot([X[i],X[i]], [y[i],3*X[i]+2], color='grey') loss= loss + np.square(3*X[i]+2-y[i]) pass ax_list[0].axis([0, 2, 0, 15]) ax_list[0].legend(loc="upper left") ax_list[0].title.set_text('loss=%s'%loss) ax_list[1].plot(X, y, "bo") ax_list[1].plot(X, 4*X+4, "g:", lw="5", label = "y=4x+4") loss = 0 for i in range(10): ax_list[1].plot([X[i],X[i]], [y[i],4*X[i]+4], color='grey') loss= loss + np.square(4*X[i]+4-y[i]) pass ax_list[1].axis([0, 2, 0, 15]) ax_list[1].legend(loc="upper left") ax_list[1].title.set_text('loss=%s'%loss) fig.subplots_adjust(wspace=0.1,hspace=0.5) fig.suptitle("Calculate loss",fontsize=16) 训练模型，并预测： from sklearn.linear_model import LinearRegression lr = LinearRegression() lr.fit(X.reshape(-1,1),y.reshape(-1,1)) X_test = [[2.2],[2.6],[2.8]] y_test = lr.predict(X_test) X_pred = 3 * np.random.rand(100, 1) y_pred = lr.predict(X_pred) plt.scatter(X,y, c='b', label='real') plt.plot(X_test,y_test, 'r', label='predicted point' ,marker=".", ms=20) plt.plot(X_pred,y_pred, 'r-', label='predicted') plt.xlabel("$X$", fontsize=18) plt.ylabel("$y$", rotation=0, fontsize=18) plt.axis([0, 3, 0, 15]) plt.legend(loc="upper left") loss = 0 for i in range(10): loss = loss + np.square(y[i]-lr.predict([[X[i]]])) plt.title("loss=%s"%loss) plt.show() 其他回归 要怎么真正理解回归(regression)呢？通过大量的数据统计，个体小的豆子往往倾向于产生比其更大的后代，而个体大的豆子往往倾向于产生比其更小的后代，新产生的个体有向着豆子的平均值的一种趋势，这种趋势就是回归。我们本篇文章讲的线性回归就是应用于预测的一种技术。这时，回归往往与分类相对。 线性回归、逻辑回归、多项式回归、逐步回归、岭回归、套索(Lasso)回归、弹性网络(ElasticNet)回归是最常用的回归技术。我先对这些技术做一个简单整理，让大家把脉络理清，等大家实际需要再深入探索。试图去穷尽知识只会把自己拖向疲累。 名称 解释 公式 线性回归(Linear Regression) 一种以线性模型来建模自变量与因变量关系的方法 $ y = wx+b $ 逻辑回归(Logistic Regression) 对特定类别进行建模，用于二分类 $ y=\frac{1}{1+e^{-x}} $ 多项式回归(Polynomial Regression) 自变量 x 和因变量 y 之间的关系被建模为关于 x 的 n 次多项式 $ y=\beta_0 + \beta_1x + \beta_2x^2 + … + \beta_mx^m + \varepsilon $ （cαiyongji水印） 逐步回归(Stepwise Regression) 将多个变量一个一个地引入到模型，找到其对模型影响大的变量   套索回归(Lasso Regression) 稀疏矩阵，消除不重要的特征，MSE+L1范数 $ J(\theta)=MSE(\theta) + \alpha\sum\mid\theta\mid $ ，其中，α越大模型权重越小 岭回归(Ridge Regression) 正则化线性回归，增加模型自由度，防止过拟合，MSE+L2范数 $ J(\theta)=MSE(\theta) + \alpha\frac{1}{2}\sum\theta^2 $ ，其中，α越大模型权重越小 弹性网络(ElasticNet) 介于岭回归和Lasso回归之间 $ J(\theta)=MSE(\theta) + \gamma\alpha\sum\mid\theta\mid + \alpha\frac{1-\gamma}{2}\sum\theta^2 $ ，其中，γ介于0和1之间，接近0则更倾向于岭回归，接近1则更倾向于Lasso回归]]></summary></entry></feed>