1.2 不学数学怎么办
那里有很多数学书籍,但并非所有书籍都同样有用。 我有不少程序员朋友试图学习上一节中提到的数学概念,要么是出于求知欲,要么是出于职业抱负。 当他们使用传统的数学教科书作为主要资源时,他们经常会陷入困境并放弃。 这是一个典型的不成功的数学学习故事的样子。
1.2.1 简想学点数学
我的(虚构的)朋友 Jane 是一名全栈 Web 开发人员,在旧金山的一家中型科技公司工作。 在大学里,简没有深入学习计算机科学或任何数学科目,她的职业生涯始于产品经理。 在过去的十年中,她学习了 Python 和 JavaScript 编码,并能够过渡到软件工程领域。 现在,在她的新工作中,她是团队中最有能力的程序员之一,能够构建向客户提供重要新功能所需的数据库、Web 服务和用户界面。 显然,她很聪明!
Jane 意识到学习数据科学可以帮助她在工作中设计和实施更好的功能,使用数据来改善客户的体验。 大部分时间在上班的火车上,简都会阅读有关新技术的博客和文章,最近,她对一些名为“深度学习”的话题感到惊讶。 一篇文章谈到了由深度学习驱动的谷歌 AlphaGo,它在棋盘游戏中击败了世界上排名第一的人类棋手。 另一篇文章展示了由普通图像生成的令人惊叹的印象派绘画,同样使用了深度学习系统。
读完这些文章后,简无意中听到她的朋友马库斯在一家大型科技公司找到了一份深度学习研究工作。 据推测,马库斯每年的薪水和股票收入超过 400,000 美元。 考虑到她职业生涯的下一步,简除了研究一个引人入胜且有利可图的问题之外,还有什么想要的呢?
简做了一些研究,并在网上找到了一个权威(而且是免费的!)资源:Goodfellow 等人的《深度学习》一书(麻省理工学院出版社,2016 年)。 简介读起来很像她习惯的技术博客文章,让她对学习这个主题更加兴奋。 但随着她继续阅读,这本书的内容变得越来越难。 第一章涵盖了所需的数学概念,并介绍了许多简从未见过的术语和符号。 她略读并试图进入书的核心,但它继续变得更加困难。
简决定她需要暂停她对人工智能和深度学习的研究,直到她学会了一些数学。 幸运的是,深度学习的数学章节列出了线性代数的参考资料,供从未见过该主题的学生参考。 她找到了 Georgi Shilov 的《线性代数》(Dover,1977 年)的这本教科书,发现它有 400 页长,与深度学习一样密集。
在花了一个下午阅读有关数域、行列式和辅因子等概念的深奥定理后,她称之为放弃。 她不知道这些概念将如何帮助她编写程序来赢得棋盘游戏或生成艺术品,她不再愿意花几十个小时来研究这些枯燥的材料。
简和我碰头喝杯咖啡。 她告诉我她在阅读真正的 AI 文献时遇到的困难,因为她不懂线性代数。 最近,我听到很多相同形式的哀叹:
我正在尝试阅读[新技术],但似乎我需要先学习[数学主题]。
她的方法令人钦佩:她为她想学习的主题找到了最好的资源,并为她缺少的先决条件寻找资源。 但在采用这种方法得出合乎逻辑的结论时,她发现自己陷入了对技术文献的令人作呕的“深度优先”搜索中。
1.2.2 翻阅数学教科书
大学水平的数学书,比如简拿起的线性代数书,往往非常公式化。 每个部分都遵循相同的格式:它定义了一些新的术语,使用该术语陈述一些事实(称为定理),然后证明这些定理是正确的。
这听起来像是一个很好的、合乎逻辑的顺序:你介绍你正在谈论的概念,陈述一些可以得出的结论,然后证明它们的合理性。 那为什么读高级数学教科书这么难呢?
问题是这不是数学的实际创建方式。 当你想出新的数学思想时,可能需要很长时间才能找到正确的定义。 我认为大多数专业数学家会这样描述他们的步骤:
- 发明游戏。 例如,通过尝试列出所有数学对象、在其中找到模式或找到具有特定属性的对象来开始玩一些数学对象。
- 形成一些猜想。 推测一些你可以陈述的关于你的游戏的一般事实,至少,说服自己这些一定是真实的。
- 开发一些精确的语言来描述你的游戏和你的猜想。 毕竟,你的猜想在你能传达它们之前没有任何意义。
- 最后,带着一些决心和运气,为你的猜想找到一个证明,说明为什么它必须是真的。
从这个过程中学到的主要教训是,你应该从思考大想法开始,形式主义可以等待。 一旦你大致了解了数学是如何工作的,词汇和符号就会成为你的资产,而不是分散注意力。 数学教科书通常以相反的顺序工作,所以我建议使用教科书作为参考,而不是作为新学科的介绍。
与其阅读传统的教科书,不如学习数学的最佳方法是探索想法并得出自己的结论。 但是,您一天中没有足够的时间来自己重新发明一切。 什么是正确的平衡点? 我会给你我的拙见,它指导我如何写这本关于数学的非传统书籍。
1.3 使用你训练有素的左脑
这本书是为经验丰富的程序员或那些在学习编程时感到兴奋的人设计的。 为程序员的读者写数学是很棒的,因为如果你会写代码,你已经训练了你的分析左脑。 我认为学习数学的最好方法是借助高级编程语言,并且我预测在不远的将来,这将成为数学课堂的常态。
像您这样的程序员可以通过几种特定的方式来学习数学。 我在这里列出这些,不仅是为了恭维你,也是为了提醒你已经拥有哪些技能可以在你的数学学习中依靠。
1.3.1 使用正式语言
你在编程中学到的第一个艰难的教训就是你不能像写简单的英语那样写代码。 如果在给朋友写便条时你的拼写或语法稍有偏差,他们可能仍能理解你想说的话。 但是代码中的任何语法错误或拼写错误的标识符都会导致您的程序失败。 在某些语言中,即使在其他正确的语句末尾忘记分号也会阻止程序运行。 作为另一个示例,请考虑以下两个语句:
x = 5
5 = x
我可以读到其中任何一个表示符号 x 的值是 5。但这并不是这两个在 Python 中的确切含义,事实上,只有第一个是正确的。 Python 语句 x = 5 是将变量 x 设置为值 5 的指令。另一方面,您不能将数字 5 设置为值 x。 这可能看起来很迂腐,但您需要知道它才能编写正确的程序。
另一个让新手程序员(以及有经验的程序员)绊倒的例子是引用相等。 如果你定义一个新的 Python 类并创建它的两个相同的实例,它们是不相等的!
>>> class A(): pass
...
>>> A() == A()
False
你可能期望两个相同的表达式相等,但这显然不是 Python 中的规则。 因为这些是 A 类的不同实例,所以它们不被认为是相等的。
留意新的数学对象,它们看起来像你认识的对象,但行为方式不同。 例如,如果字母 A 和 B 代表数字,那么 A·B = B·A。但是,正如您将在第 5 章中学到的那样,如果 A 和 B 不是数字,情况就不一定如此。 相反,如果 A 和 B 是矩阵,则乘积 A·B 和 B·A 是不同的。 事实上,有可能只有一种点积是可行的,或者两种点积都不正确。
在编写代码时,仅使用正确的语法编写语句是不够的。 你的陈述所代表的想法需要有意义才能有效。 如果你在编写数学语句时也同样小心,你会更快地发现错误。 更好的是,如果您用代码编写数学语句,您将拥有计算机来帮助检查您的工作。
1.3.2 建立自己的计算器
计算器在数学课中很普遍,因为它对检查你的工作很有用。 您需要知道如何在不使用计算器的情况下将 6 乘以 7,但最好通过咨询计算器来确认您的 42 答案是否正确。 一旦您掌握了数学概念,计算器还可以帮助您节省时间。 如果您正在做三角学,并且您需要知道 3.14159 / 6 的答案,计算器可以处理它,因此您可以考虑答案的含义。 计算器开箱即用的功能越多,理论上它应该越有用。
但有时我们的计算器对我们自己来说太复杂了。 当我开始上高中时,我被要求得到一个图形计算器,我得到了一个 TI-84。 它有大约 40 个按钮,每个按钮有 2 到 3 种不同的模式。 我只知道如何使用其中的 20 个,因此学习如何使用它是一个繁琐的工具。 当我在一年级得到我的第一个计算器时,情况也是如此。 只有 15 个左右的按钮,但我不知道其中一些按钮是做什么的。 如果我必须为学生发明第一个计算器,我会让它看起来像图 1.14 中的那个。
图 1.14 学生数数计算器
这个计算器只有两个按钮。 其中一个将值重置为 1,另一个前进到下一个数字。 像这样的东西将是孩子学习数数的正确“简单”工具。 (我的例子可能看起来很傻,但你实际上可以购买这样的计算器!它们通常是机械的,并作为计数计数器出售。)
掌握数数后不久,您就想练习写数字并将它们相加。 在那个学习阶段,完美的计算器可能会有更多的按钮(图 1.15)。
图 1.15 一个能写出整数并将它们相加的计算器
在这个阶段,不需要像 -、* 或 ÷ 这样的按钮来妨碍你。 当您解决像 5 - 2 这样的减法问题时,您仍然可以通过确认总和 3 + 2 = 5 来检查您的 3 答案。同样,您可以通过重复添加数字来解决乘法问题。 完成探索后,您可以升级到一个计算器,该计算器可以执行所有算术运算。
我认为理想的计算器是可扩展的,这意味着您可以根据需要为其添加更多功能。 例如,您可以为您学习的每一个新数学运算在计算器上添加一个按钮。 一旦你学会了代数,也许你可以让它理解除了数字之外的 x 或 y 等符号。 当您学习微积分时,您可以进一步使其能够理解和操作数学函数。
可以容纳多种类型数据的可扩展计算器似乎有些牵强,但这正是您使用高级编程语言时所得到的。 Python 带有算术运算、数学模块和大量第三方数学库,您可以随时使用它们来使您的编程环境更加强大。 因为 Python 是图灵完备的,所以你可以(原则上)计算任何可以计算的东西。 你只需要一台足够强大的计算机,一个足够聪明的实现,或者两者兼而有之。
在本书中,我们在可重用的 Python 代码中实现了每一个新的数学概念。 自己完成实现可能是巩固你对新概念理解的好方法,到最后,你已经在你的工具带中添加了一个新工具。 在自己尝试之后,如果你愿意,你可以随时换入一个优美的主流库。 无论哪种方式,您构建或导入的新工具都为探索更大的想法奠定了基础。
1.3.3 用函数构建抽象
在编程中,我刚才描述的过程称为抽象。 例如,当您厌倦了重复计数时,您创建了加法的抽象。 当您厌倦了重复加法时,您创建了乘法的抽象,等等。
在您可以在编程中进行抽象的所有方法中,最重要的一种延续到数学是函数。 Python 中的函数是一种重复某些可以接受一个或多个输入或可以产生输出的任务的方法。 例如:
def greet(name):
print("Hello %s!" % name)
允许我用这样的简短、富有表现力的代码发出多个问候:
>>> for name in ["John","Paul","George","Ringo"]:
... greet(name)
...
Hello John!
Hello Paul!
Hello George!
Hello Ringo!
这个函数很有用,但它不像数学函数。 数学函数总是接受输入值,并且总是返回没有副作用的输出值。
在编程中,我们将表现得像数学函数的函数称为纯函数。 例如,平方函数 f(x) = x 2 接受一个数字并返回该数字与自身的乘积。 当你计算 f(3) 时,结果是 9。这并不意味着数字 3 现在已经改变并变成了 9。相反,这意味着 9 是函数 f 的输入 3 的对应输出。 你可以把这个平方函数想象成一台机器,它在输入槽中获取数字并在其输出槽中产生结果(数字)(图 1.16)。
图 1.16 作为具有输入槽和输出槽的机器的函数
这是一个简单而有用的心智模型,我将在本书中反复讨论它。 我最喜欢它的一件事是你可以把一个函数想象成一个对象本身。 在数学中,就像在 Python 中一样,函数是您可以独立操作甚至传递给其他函数的数据。
数学可能令人生畏,因为它是抽象的。 请记住,就像在任何编写良好的软件中一样,引入抽象是有原因的:它可以帮助您组织和交流更大、更强大的想法。 当您掌握这些想法并将它们转化为代码时,您将开辟一些令人兴奋的可能性。
如果你还没有,我希望你现在相信数学在软件开发中有许多令人兴奋的应用。 作为一名程序员,您已经拥有正确的思维方式和工具来学习一些新的数学思想。 这本书中的想法为我提供了专业和个人的丰富,我希望它们也能为你服务。 让我们开始吧!
总结
- 数学在许多软件工程领域都有有趣且有利可图的应用
- 数学可以帮助您量化随时间变化的数据的趋势,例如,预测股票价格的变动。
- 不同类型的函数传达不同类型的定性行为。 例如,指数折旧函数意味着汽车每行驶一英里就会损失一定百分比的转售价值,而不是固定金额。
- 数字元组(称为向量)表示多维数据。 具体来说,3D 向量是三元组的数字,可以表示空间中的点。 您可以通过组装由矢量指定的三角形来构建复杂的 3D 图形
- 微积分是对连续变化的数学研究,许多物理定律都是用称为微分方程的微积分方程写成的。
- 传统教科书很难学数学! 你通过探索学习数学,而不是通过定义和定理直接进行。
- 作为一名程序员,您已经训练自己准确地思考和沟通; 这项技能也将帮助您学习数学。