用Numpy从0开始学Python
写在开始前
本文从0开始,主要讲述Python中的Numpy程序库的用法。即使你之前对Python一无所知,只要你感兴趣,我相信本文可以带你入门。
在开始前,请快速浏览以下内容,并点击高亮部分的链接进行阅读,了解即可,看不懂直接跳过。
-
首先你需要知道什么是Python。总之,它是当前互联网时代可能最强大的工具之一。我预测,未来编程也会像算术一样成为每个人必备的技能。
-
简要介绍NumPy:
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
其前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。1
现在,让我们开始吧~😁
为什么要学习NumPy
Python作为一门强有力的编程语言,以简洁的代码,强大的功能著称。然而,相比于C,它的运行速度是很慢的。2
而Numpy仿佛就是Python的救星,它能把简单好用的 Python 和高性能的 C 语言合并在一起。当你调用 Numpy 功能的时候, 它其实调用了很多 C 语言而不是纯 Python。这就是为什么大家都爱用 Numpy 的原因。
在这个大数据的时代,如果你想进行数据分析,运用数据进行统计推断,那NumPy正好就可以满足你的需求。
同时,正如前面所说,它简直就是速度怪兽,唰唰唰地就能跑完你的代码!
让我们抛弃语法,开始!
我很赞成国外一位程序员Jeff Olson的观点:(Teachers) stop teaching code, solicit prediction instead.3
- 某种程度上,我们被传统的教学方式禁锢了。对于编程,它是像做菜一样,你根本不用了解做菜发生的化学反应是什么,你只要知道:这样做我吃起来很香,我感觉很快乐。
- 所以,让我们抛弃语法,直接去体验代码,它就长这样,很美。同时,你需要“猜”,猜这块代码执行的是什么功能(也就是solicit predicition instead)。
- 那猜了过后呢?请自己按照我的代码自己敲一遍,验证自己的猜想,根据结果的反馈来更正自己的认知。
- 试着更改代码,加入自己的东西,观察结果。你可以更改的不仅仅是函数变量,你甚至可以更改函数名,看看有没有这个函数,它实现的是怎样的功能。
- 图像是搬运的Jay Alammar的 A Visual Intro to NumPy and Data Representation。别人做得很好,这里就不重复造轮子了。
- 请停留三秒钟再体会一下这句话:它就长这样,很美。
首先,引入NumPy。
>>> import numpy as np
打开IDLE,按回车执行。你会发现它什么也没有发生,但Python现在已经将这个模块以np的名字引入了,所以你可以直接用np.的形式调用里面的函数。
构造数组
>>> data = np.array([1, 2, 3])
执行,什么也没有发生
>>> data.max()
执行,观察结果。以下是图解:
有时,我们希望可以快速地对数组进行初始化,这时候就要用到NumPy提供给我们的方法ones(),zeros(),random.random()。
>>> ones = np.ones(3)
>>> zeros_1 = np.zeros(3)
>>> random_1 = np.random.random(3)
运行,然后我们在屏幕上打印出结果:
>>> for each in (ones, zeros_1, random_1):
print(each)
按两次回车,执行。
请务必根据图像和代码本身进行理解!
同样的,试试:
>>> zeros_2 = np.zeros([1,3])
>>> zeors_3 = np.zeros(1,3)
发生了什么?尝试通过互联网解决自己的疑问吧~
那如果我更改一下函数名:
>>> random_2 = np.random.randn(3)
>>> random_3 = np.random.randint(3)
代码能正常运行吗?如果可以,像上面一样,打印出结果试试!
我直接跳过了维度的问题,请参考文章Numpy中的shape函数的用法详解,同样,使用上述的学习方法,先预测结果,再实现代码,最后加入自己的东西重复验证结果。
也许部分结果无法吻合,没关系。以你电脑上的输出为准。
数组的计算
先自己动手,按照之前的代码照猫画虎,实现以上图像。
那如果我对这两个数组进行加减乘除计算会怎样呢?
>>> a = data - ones
>>> b = data + ones
>>> c = data * ones
>>> d = data / ones
同样地,试着用for循环和print逐个打印出a, b, c, d 。
注意,这里的乘法是逐项相乘(element-wise),与矩阵的点乘不同。
以下是图解:
那如果和一个常数进行计算呢?
>>> e = data * 1.6
>>> f = data + 1.6
Wow, wonderful!
这叫broadcasting,也就是NumPy的广播机制。它将一个常数展开为一个维数相当的数组,然后再进行加减乘除运算。
引用数组中的元素
请依次运行以下代码:
>>> data = np.array([1, 2, 3])
>>> data[0]
>>> data[3] # 代码报错,为什么?
>>> data[0:2]
>>> data[1:]
是不是结果很酷炫?来看看图解吧:
以上我们用到了NumPy的切片操作,感兴趣可以看一下这篇文章 NumPy 数组切片
在更高维度
当数组到了更高维度,我们可以叫它 矩阵(matrix)
请观察图像,并自己写出对应的代码。
构造数组
数组的计算
同样地,矩阵当中也有广播机制
矩阵点乘
矩阵点乘即是求矩阵内积。
>>> data = np.array([[1, 2, 3]])
>>> temp = [10**i for i in range(6)] # 使用列表推导式得出一个列表
>>> powers_of_ten = np.array(temp) # 将list转换为numpy
>>> powers_of_ten = powers_of_ten.reshape(3, 2)
>>> data.shape
>>> powers_of_ten.shape
>>> np.dot(data, powers_of_ten)
先执行自己的代码,观察结果。图解如下:
矩阵的内积究竟做了什么呢?
其实是将data的一个行的元素逐个乘以powers_of_ten的一个列的元素,并求和(sum)。
求矩阵的内积在深度学习中运用十分广泛,通过向量化(vectorization),可以将庞大的数据构建成矩阵,并运用numpy进行求内积,即是将数据统一地乘以对应权重。通过numpy,可以大大提升神经网络前向传播的速度。
引用矩阵中的元素
>>> temp = [i for i in range(1, 7)]
>>> data = np.array(temp