17

手把手教你学Numpy,从此处理数据不再慌「一」

 3 years ago
source link: http://www.cnblogs.com/techflow/p/12880160.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

当当当,我又开新坑了,这次的专题是Python机器学习中一个非常重要的工具包,也就是大名鼎鼎的 numpy

所以今天的文章是 Numpy专题的第一篇

俗话说得好,机器学习要想玩的溜,你可以不会写Python,但一定不能不会调库(大雾)。Numpy可以说是Python中最基础也是最重要的工具库了,要用Python做机器学习,玩转各种框架,Numpy是必须要会的。像是TensorFlow、pytorch这些知名框架都是基于Numpy进行计算的,可想而知它的重要性。

Numpy存在的必要性

网上关于Numpy的介绍非常多,但说来说去无非是一个Python中数值计算的非常重要的基础包,可以用来很方便地做一些矩阵和大数据的运算。

Numpy是做什么的我们很好理解,但是我们可能更加好奇它 更深层次的意义 究竟是什么?关于这个问题我们从浅到深不停地追问,可以得到许多不同的答案。

最浅层的回答很简单,Numpy很方便, 计算速度快 ,可以很方便地进行矩阵运算。在Andrew的课程当中,他曾经演示过,同样的矩阵运算,如果我们通过Python中的循环实现速度会比调用Numpy慢上至少上百倍。这个差异显然是非常可怕的。

但为什么Numpy会更快呢?

我们追问下去,又会得到一个新的答案。因为Numpy包 底层是通过C++实现的 ,显然C++运算比Python快得多,所以Numpy自然就更快了。

难道Numpy就只是因为C++更快这么简单吗?

这个问题已经超越了Numpy本身,我们需要从Python的特性来回答了。Python是一门解释型语言,也就是说当我们执行Python的时候,其实是执行了一个Python的解释器。由Python的解释器来解释执行Python的每一行代码。

如果我们把解释器理解成虚拟机,把Python执行的代码理解成虚拟机当中的程序。如果我们虚拟机多开的话,是很难保证线程安全的。为了解决这个问题,Python设计了 GIL机制 ,也就是全局解释器锁,它保证了同一时刻最多只有一个解释器线程在执行。

这个机制保证了线程安全,但是也限制了Python多线程的使用。Python的多线程本质上是伪多线程,因为解释器只有一个线程在跑。所以如果我们想要通过多线程并发来加速计算的话,这是不可能的。

而矩阵和向量的一些操作是可以通过多线程并发来加速计算的,而Python本身的特性导致了Python不能执行这样的操作。那么通过Python调用C++实现的计算库也就是唯一的选择了。实际上不仅是Numpy,几乎所有Python的计算库,都是通过Python调用其他语言实现的。Python本身只是最上层的调用方。

理解了这点除了对于Python可以有更加清晰的认识之外,也有助于之后学习TensorFlow等其他框架。

Numpy中的n维数组

Numpy之所以好用,是因为我们可以通过Numpy 很方便地创建高维的数组和矩阵

举个例子,比如在原生Python当中,当我们需要创建一个二维数组的时候,往往需要些很长的定义。比如我们想要一个10 * 10的数组:

arr = [[0 for _ in range(10)] for _ in range(10)]

但是在Numpy当中就会很方便,只需要一行。

import numpy as np
arr = np.zeros((10, 10))

第一行当中我们引入了numpy,为了编码方便,我们将它重新命名成了np。这个是业内惯用做法,几乎所有使用numpy的程序员都会这么重命名。

在numpy当中,存储高维数组的对象叫做ndarray,与之对应的是存储矩阵的mat。其实这两者区别不大,支持矩阵的运算,ndarray基本上也都支持。我们有这么一个印象即可,关于mat内容我们会在之后介绍。

我们创建除了ndarray之后,关于获取ndarray基本信息的api大概有下面四个。

第一个是 通过.ndim 查看ndarray的维度,也就是查看这是一个几维的数组:

Rvy6vq6.jpg!web

第二个是 通过.shape 获取这个ndarray在各个维度的大小:

zMFVvai.jpg!web

第三个是 通过.dtype 获取这个ndarray中元素的类型:

UFr67jz.jpg!web

最后一个是 tolist()方法 ,可以将一个ndarray转化成Python原生的list进行返回。

36r26fN.jpg!web

ndarray

那么我们怎么创建numpy中的ndarray呢?

大概也有几种办法,首先,既然numpy中的ndarray可以转换成Python原生的list,同样Python中原生的list也可以转换成numpy中的ndarray。

和转换变量类型的语法很像,我们通过np.array()转换即可。

nums = [1, 3, 4, 6]
arr = np.array(nums)

除了通过Python中原生的list转换,我们还可以根据自己的需要创建新的ndarray。numpy创建array的方法有很多,我们先来介绍一下其中比较基础的几种。

创建出一个range

np.arange可以 生成一个序列 ,有些类似于Python中原生的range。不过它更加灵活,我们可以之传入一个整数,它会返回一个从0开始的序列:

np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

我们也可以 指定首尾元素和间隔 ,numpy会自动帮我们生成一个等差序列:

np.arange(1, 5, 0.5)
array([1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5])

除此之外,numpy中还提供了 ones和zeros 两个api,可以生成全为0和全为1的元素。

np.zeros((3, 4))
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
np.ones((2, 3))
array([[1., 1., 1.],
       [1., 1., 1.]])

我们还可以使用 eye或者是identity 生成一个N*N的单位矩阵:

np.eye(3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

除此之外,还有一个full的api可以 指定shape和数值 ,用我们指定的数值填充出一个指定大小的数组来:

np.full((3, 4), 3)
array([[3, 3, 3, 3],
       [3, 3, 3, 3],
       [3, 3, 3, 3]])

但是这个api我们用的不多,因为我们可以用ones生成一个全为1的数组,然后乘上一个我们想要的值,就等价于full。

另外,ones, zeros, full这几个api还有一个对应的like方法。所谓的like方法就是我们传入另外一个ndarray代替shape,numpy会根据这个ndarray的形状生成一个对应形状的新array。

我们来看个例子吧,首先我们生成一个顺序的序列:

ex1 = np.arange(10)

然后我们通过zeros_like方法生成一个同样大小的全为0的矩阵:

ex2 = np.zeros_like(ex1)

它其实等价于:

np.zeros(ex1.shape)

其他几个like方法也大同小异,因为可替代性很强,所以我也用的不多。

numpy支持的类型

numpy支持的数据类型很多,除了常用的int和float之外,还支持 复数类型的complex ,某种程度上来说和golang支持的类型比较接近。

其中int类型一共分为int8,int32,int64和int128,其中每一种又分为带符号的和不带符号的。例如int8就是带符号的8位二进制表示的int,而uint8则是不带符号位的。浮点数没有无符号浮点数,一共分为float16,float32,float64和flaot128。

复数也有三种,分别是complex64,complex128和complex256。除此之外还有string_和object以及unicode_这三种类型。

我们可以通过调用astype方法更改ndarray中所有变量的类型:

ex1 = np.arange(10)
ex1.astype(np.float64)
array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])

除了人为转换之外,我们还可以在创建的时候通过dtype这个参数来表示我们想要创建的数据的类型,这样可以避免之后转换的麻烦。

ex1 = np.arange(10, dtype=np.float32)

结尾

这篇文章当中我们不仅介绍了Numpy的创建的方法,还聊了Python这门语言的一些特性。正是因为Python本身多线程的限制,导致它在需要高并发计算的场景下性能很差。才会需要通过Python去调用C++或者是其他语言的底层实现。这也是为什么Python经常被称为 胶水语言 的原因。

Numpy可以认为是Python进行机器学习的基础,当然除了Numpy之外,像是pandas、matplot以及scikit-learn等库也是必不可少的。我们会从Numpy开始,一点一点把这些常用的库都给大家分享一遍。

各位看官大人,喜欢的话,点个关注吧~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK