在我最近的SmugMug API和Python冒险中,有一个艾弗森鬼魂出没:NumPy。
Iverson Ghost是在非APL语言和工具中嵌入类似APL的数组编程功能。
你会惊讶于艾弗森鬼魂出现的频率。每当程序员面临处理大型数值数组的挑战时,他们都会重新发现一些APL代码。他们往往没有意识到数组处理语言的丰富遗产,但在NumPy的案例中,他们间接承认了这一点。在Numerical Python中,作者写道:
用于指导NumPy开发的语言包括声名狼藉的APL系列语言、BASE、MATLAB、FORTRAN、S和S+等。
我认为“臭名昭著”是从“一个错误延续到完美”的升级。
不仅开发人员经常召唤出艾弗森的鬼魂。他们也总是变成数组编程的小使者,不会闭嘴,谈论减少所有该死的循环是如何澄清和简化算法的。学习如何考虑对整个数组进行操作,而不是一次只考虑一个微不足道的数字,这是如何解放思想的。为什么它几乎就像是数组编程是一种思维工具。
啊,我想起来了,大约50年前我第一次遇到APL的时候。
是的,我是一个老程序员,一个化石,一个活的遗物。我的大脑是一个腐烂的朋克编程语言池。Python只是一长串语言中最新的一种。有些人集邮。我收集编程语言。而且,就像集邮者有最喜欢的邮票一样,我发现一些编程语言比其他编程语言更有吸引力。例如,我认识到C/C++不可否认的实用价值,对于许多任务来说,它们是唯一重要的选项,但与C/C++一样有用和普遍,它们从未激起我的兴趣。符号太难看了!是的,我说过了;吸吧,伙计们。同样,世界上最常用的编程语言JavaScript也同样难看。同样,JavaScript非常有用,程序员不得不忍受它的许多缺点。一些人甚至写了一些关于它微不足道的好部分的书,赚了几美元。
我对其他广泛使用的语言也有类似的煽动性观点。现在让我痛苦的是SQL,特别是微软的变种T-SQL。纯粹出于美学原因,我发现格式良好的SQL查询没有一般的C指针狂欢那么可怕。核心SQL相当优雅,但围绕它发展起来的宏编程特性却很糟糕。当我被迫使用它们的时候,我感觉很脏,几乎每隔一天就会用一次。
在我的编程日结束时,我想看一些美丽的东西。我并不特别关心一段代码的用处有多大,或者它能赚多少钱,或者它解决了什么愚蠢的小业务问题。如果这该死的代码很难看,我不想看到它。
人们不断地重新发现数组编程,Ken Iverson在1962年出版的《A Programming Language》一书中对此进行了最好的描述,原因有两个:
这两个原因都体现在NumPy在Python世界的巨大成功中。
为什么需要这些扩展?核心原因非常平淡无奇,那就是在Python中使用标准数据结构(如列表、元组或类)操作一百万个数字的速度太慢,并且占用太多空间。
面对“不计算”的情况,你可以尝试其他方法,也可以修复你已有的东西。Python人用NumPy修复了Python。Pythonistas不情愿地接受了NumPy,但很快就变成了使徒!现在,像优雅的SciPy和构建在NumPy上的整个SciPy工具集这样的书籍认为这是理所当然的。
对于几十年来一直在喝数组处理Kool-aid的程序员来说,在NumPy中有什么特别的东西吗?答案是肯定的!特别是J程序员,他们正在享受与最新的J8.07测试版一起发布的新Python3插件。这个插件直接支持NumPy数组,使得在J/Python环境中交换数据变得很容易。这是两个世界中最好的事情之一。
以下NumPy示例来自于本网站的NumPy快速入门教程。对于每个NumPy语句,我都提供了一个等价的J。J是APL的后代。它在很大程度上是由同一个人设计的:肯·艾弗森(Ken Iverson)。看过这些例子后,一个卑鄙的律师或贪婪的专利流氓可能会考虑起诉NumPy的创造者。APL的影响是显而易见的。幸运的是,肯·艾弗森(Ken Iverson)更感兴趣的是推广从中获利的好想法。我怀疑他会受宠若惊,APL已经变异并殖民了陌生的新世界,我想即使是狂热的Python主义者也会同意Python是一个令人愉快的陌生世界。
此处已取消显示从https://docs.scipy.org/doc/numpy-dev/user/quickstart.html输出中选择的示例。有关这些例子的更详细信息,请浏览Jupyter笔记本:The NumPy and J Make Sweet Array Love。
#numpy a=np.arange(15).rehape(3,5)nb.。Ja=。3 5$i.15#numpy a=np.array([2,3,4])Nb.。Ja=。2 3 4#numpy b=np.array([(1.5,2,3),(4,5,6)])Nb.。J b=。1.5 2 3,:4 5 6#numpy c=np.array([1,2],[3,4]],dtype=Complex)Nb.。J j.1 2,:3 4#numpy np.zeros((3,4))Nb.。J3 4$0#numpy-使用内存np.空((2,3))nb中的任何内容分配数组。J-使用Fill-更安全,但比Numpy的信任记忆方法慢2 3$0.0001。
#numpy a=np.array([20,30,40,50])b=np.arange(4)c=a-b nb。Ja=。20 30 40 50 b=。I.4c=。A-b#numpy-使用先前定义的(B)b**2NB。J b^2#numpy-使用先前定义的(A)10*np.sin(A)nb。J 10*1 O.a#Numpy-Booleans是真的和假的a<;35NB。J-布尔值为1和0a<;35。
#numpy a=np.array([[1,1],[0,1]])b=np.array([[2,0],[3,4]])#元素积a*bNb。Ja=。1 1,:0 1 b=。2 0,:3 4 a*b#数值矩阵乘积np.dot(a,b)nb。J-矩阵乘积a+/。*b#个数均匀伪随机a=np.随机.随机((2,3))Nb.。J-一致伪随机数a=。?2 3$0#Numpy-求所有数组元素的和-隐式Ravel a.sum(A)nb。J-对所有数组元素求和-显式Ravel+/,a#numpy b=np.arange(12).RESHAPE(3,4)#每列的SUM b.sum(轴=0)#每行的分钟b.min(轴=1)#沿每行的累计和b.Cumsum(轴=1)#转置B.TNB。J b=。3 4$I12 NB。每列的总和+/b Nb。每行最少<;。/";1 b NB。每行累计和+/\";0 1b Nb。转置|:B。
#numpy a=np.arange(10)**3a[2]a[2:5]a[::-1]#反转Nb。Ja=。(i.10)^3 2{a(2+i.3){a|。一个