大多数数据在我们拿到时,其形式很不实用,无法直接用机器学习算法处理。如上一个例子所见(上一节) ,数据中有些元素可能缺失,或某些列不是数值型,因此无法直接用机器学习技术处理。因而,机器学习专家通常花费大量时间清洗和准备数据,转换数据的形式,以便进一步分析或做可视化处理。本节教你用NumPy和pandas库,用Python语言创建、准备和处理数据。matplotlib小节,将介绍Python绘图基础知识。NumPy教程结合Python shell进行讲解,但是代码的IPython notebook版和纯Python脚本版,都已放到作者GitHub主页chapter_1文件夹。pandas和matplotlib两个库的讲解则用IPython notebook。
1.2.1 NumPy的用法
Numerical Python或NumPy是Python的一个开源扩展包,是数据分析和高性能科学计算的基础模块。该库问世后,用Python处理大规模、多维数组和矩阵不再是梦想。对于常用数值计算,它提供预先编译好的函数。更进一步来讲,它提供一个巨大的数学函数库来支持数组运算。
该库提供以下功能
用于向量算术运算的快速、多维数组;
对数据中所有数组进行快速运算的标准数学函数;
线性代数运算;
排序、去重( unique )和集合运算;
统计和聚合数据。
比起Python的标准运算, NumPy的主要优势在于数组运算速度快。例如,用传统的求和方法,求10000000个元素的和:
![664669b7eef708f0ccb029287fa0833a.png](https://i-blog.csdnimg.cn/blog_migrate/fdd36b0405021d2cec848c6a3aea6150.jpeg)
与Numpy函数对比:
![6aecedcef64d1510ea0b9d3de156230c.png](https://i-blog.csdnimg.cn/blog_migrate/15b5681601350476dc352b4b7cd84326.jpeg)
两种方法所用时间分别为2.1142539978和0.0807049274445。
1.数组创建
数组对象是NumPy库提供的主要功能。数组相当于Python的列表(list ) ,但数组所有元素的数值类型相同(通常为浮点型或整型)。借助array函数,可用列表定义一个数组对象,需为array函数传入两个参数:即将被转换为数组的列表、新生成的数组的类型:
![7337b20f996123c5bbd2ee78bf04fef2.png](https://i-blog.csdnimg.cn/blog_migrate/d7fd3bc92133f71b49aada1091ad8490.jpeg)
反之,可用如下代码将数组转换为列表:
![7b540dfa3c5d93195fa5e83f1b7a1237.png](https://i-blog.csdnimg.cn/blog_migrate/afd9908749c2e2bb37fe3657733e0763.jpeg)
![2b160b2179014d3b7a66a68aea43b8dc.png](https://i-blog.csdnimg.cn/blog_migrate/3286afcefb9c94f5db86c5c3129c0117.jpeg)
若想用现有数组,创建一个新的数组对象,则要用copy函数:
![265581a197d8d3620b09788d464e60ff.png](https://i-blog.csdnimg.cn/blog_migrate/502ff6147ebab9d87dfa8a917273eafc.jpeg)
此外,还可以用同一个值填充数组,覆盖掉之前的值,得到一个元素全部相同的数组,例如:
![0d3bf7a39d607dec7665602d7bf2de7a.png](https://i-blog.csdnimg.cn/blog_migrate/f37f35daefa24c4b3d78d9a9bf8533a7.jpeg)
还可以用np的子模块random随机选取元素创建数组。例如,将要创建的数组的长度作为permutation函数的参数传入,该函数返回一个由整数组成的随机序列:
![d962548e0c44b1ee7ec80419fdc6d288.png](https://i-blog.csdnimg.cn/blog_migrate/76e1fb0e9f74f83c57398b3b98a21e66.jpeg)
另一种数组创建方法是用normal函数从一个正态分布中抽取一列数字:
![b1f642e9e938fe2df9a35145141db262.png](https://i-blog.csdnimg.cn/blog_migrate/6ecb67e3a9233892a5b3ad72a2c33eec.jpeg)
参数0为正态分布的均值, 1为标准差,5表示抽取5个数字创建数组。若使用均匀分布, random函数将返回0到1之间(不包含0和1)的数字:
![fac71c671235381ff418c09f65158935.png](https://i-blog.csdnimg.cn/blog_migrate/f8ddd814e6c83e308e6a1bac1eaca791.jpeg)
NumPy还提供几个创建二维数组(矩阵)的函数。例如, identity函数创建单位矩阵,其维度用参数来指定:
![0881fb32482aa33a780000ea142c30a2.png](https://i-blog.csdnimg.cn/blog_migrate/2fdca678cd67d7324e4cf73cf73dd640.jpeg)
Eye函数返回第k条对角线上元素为1的矩阵。
![4193afc6893f2fe48803cd49c8fd48cc.png](https://i-blog.csdnimg.cn/blog_migrate/538665c6b888a52d91c950079a4c741b.jpeg)
创建新数组(1或2维)最常用的函数是zeros和ones ,它们按照指定的维度创建数组,并分别用0或1填充。示例如下:
![bfc18e1263c75a421353b24901d4a319.png](https://i-blog.csdnimg.cn/blog_migrate/352e3e2ff703b1989a0ac0940571c4ea.jpeg)
而zeros_like和ones_like函数,创建的是跟现有数组元素的类型[7]和维度都相同的数组:
![b0dac32cd3cc6fbe37a6c2a8589948a0.png](https://i-blog.csdnimg.cn/blog_migrate/188173586d0f70fff6d6c996bfa7e51f.jpeg)
另外一种创建二维数组的方法是,用vstack函数(垂直方向合并)合并一维数组:
![724522368f17c6562815ae3a5a6061ed.png](https://i-blog.csdnimg.cn/blog_migrate/ff0c9aa4bb7da9a57a301d1ec1bb72cf.jpeg)
二维数组也可以用random子模块按照某种分布进行创建。例如,随机从0到1的均匀分布中选取数字作为数组元素,创建一个2x3型数组,方法如下:
![2fcf4a0075447bdd851fc335d70c1a13.png](https://i-blog.csdnimg.cn/blog_migrate/389d47cf4836fa97e7ed5eacd69443f1.jpeg)
另一种经常用来创建数组的分布是多元正态分布:
![926e1a52f41e646bb98df73ae1583239.png](https://i-blog.csdnimg.cn/blog_migrate/f3d0c925071d8fed38e91cf0659df116.jpeg)
列表[10,0]是均值向量,[[3,1],[1,4]]是协方差矩阵,5是要抽取的元素数量。
![12bdd3936b1c3f821524e8bf59c168f7.png](https://i-blog.csdnimg.cn/blog_migrate/635bdb91d921affe03521b7daa3114df.jpeg)
表1.1
2. 数组操作
访问列表元素、切片以及其他python列表的所有常见操作,均能以相同或相似的方式作用于数组:
![d6ccca9094e8ece6989ffdc6710e73cd.png](https://i-blog.csdnimg.cn/blog_migrate/af7e58b9c2a0d1eb32ae4698cfc52d1b.jpeg)
数组包含的不同元素也可以获取到,用unique函数即可:
![1e955232f0916d52109552469cf2c337.png](https://i-blog.csdnimg.cn/blog_migrate/57532ef4219dee68235c28507b95e088.jpeg)
数组元素的排序也可以用sort函数,数组的索引用argsort函数获取:
![1446722e08cf57fcbd82a74f4c1e510d.png](https://i-blog.csdnimg.cn/blog_migrate/e9ec5bf94442acbdf49c1e299aa39b27.jpeg)
用shuffle函数也可以调整数组元素,使其随机排列:
![4ea585eb795ecc011c052b65ec5db229.png](https://i-blog.csdnimg.cn/blog_migrate/909b41cfaefb1da640ef45a561f84fce.jpeg)
Numpy数组类似,也有一个内置函数array_equal,用来比较两个数组是否相等[8]:
![90501432c4dd08e8514c821a4df1a16b.png](https://i-blog.csdnimg.cn/blog_migrate/57aada2b093952ad45d755409f758dfc.jpeg)
然而,多维数组与列表操作不同。事实上,多维列表各维度用逗号分隔的形式依次指定(而列表用方括号[9])。例如,二维列表(矩阵)元素访问方法如下:
![19e951340bc3c5133e13bfb5c8f75144.png](https://i-blog.csdnimg.cn/blog_migrate/913c307d4911cdf79d8f018295b0f118.jpeg)
对数组的各维进行切片操作使用英文冒号,冒号前后为位于起始位置的元素的索引:
![736be03200e88a37cc8e0fdd20d235c9.png](https://i-blog.csdnimg.cn/blog_migrate/7317b106c0b206e75f9dedfea6136dbc.jpeg)
仅用冒号:,不用数字,表示冒号所在轴上的所有元素都在切片范围之内:
![f5aa54862f253573b08e4c79fcaa73e9.png](https://i-blog.csdnimg.cn/blog_migrate/21a0e87e630eb29c8e3d0ab15fe390f7.jpeg)
Flatten函数可将多维数组变为一堆数组:
![300150d9d986f092b2be034d83deadab.png](https://i-blog.csdnimg.cn/blog_migrate/6a040363f750692023af881ac7eec0a7.jpeg)
我们还可以查看数组对象,获取相关信息。用shape属性,可得到数组的大小:
![fe7a4ec1413a78edc94a20730059fba8.png](https://i-blog.csdnimg.cn/blog_migrate/43bbf8f8bfae50c572bc71d005a01eec.jpeg)
该例中,arr是一个2行3列的矩阵。Dtype属性返回数组元素的类型:
![be7e9b8af59ac153181ab57fc0fb263e.png](https://i-blog.csdnimg.cn/blog_migrate/a3caf2449d8f1148d1307c493b5f3643.jpeg)
数值类型float64用来存储双精度(8字节)实数(类似于Python的标准foat类型)。其他数据类型有int64, int32和字符串。数组的数据类型可以转换。例如:
![e7f67643d0324f53708434075bc3c778.png](https://i-blog.csdnimg.cn/blog_migrate/b30c643b37b2c84c519b42d60104ea5d.jpeg)
Len函数返回数组第一维的长度:
![d5f77c6b752c346e2db2f781bbf2793a.png](https://i-blog.csdnimg.cn/blog_migrate/14c9f6e0266fd02c88fb0841395b965a.jpeg)
关键字in,类似于它在python for循环中的用法,可用来判断数组是否包含某个元素:
![f1ad9015af2aad78defbc355a140c7b9.png](https://i-blog.csdnimg.cn/blog_migrate/14a08ddb18470da7a5c4d6a7160b6f95.jpeg)
Reshape函数可调整数组的维度,例如8行1列的矩阵可调整为4行2列的矩阵:
![6e50b155b0581a9af6124261a526f34c.png](https://i-blog.csdnimg.cn/blog_migrate/b200400d28490c1538b6987f21279477.jpeg)
此外,还支持矩阵的转置运算;也就是说,用transpose函数可互换两个维度,创建一个新数组:
![760b71d25c84e6e06c0f8491be02d67b.png](https://i-blog.csdnimg.cn/blog_migrate/00a9af8d16b7bedd819160c63e0dbbd3.jpeg)
数组还可以用T属性实现转置:
![24bbcf8a8bd628189a690e9d58e987cf.png](https://i-blog.csdnimg.cn/blog_migrate/14d7f4fd59e1256ebc98d9244378af48.jpeg)
另一种调整数组元素位置的方法是,用newaxis函数增加维度:
![40a347415a7c09d40cc9da56719eadb3.png](https://i-blog.csdnimg.cn/blog_migrate/e4a755ee2e73799a1ba8a2d3b4a17036.jpeg)
上述例子,两个新数组都是二维的。由newaxis生成的第二个数组长度为1。
NumPy数组的连接操作用concatenate函数,句法形式取决于数组的维度。多个一维数组可相继连接,将要连接的多个数组置于元组中作为参数传入即可:
![7f3e9acdaad62d045d1cac5d1f6dbe79.png](https://i-blog.csdnimg.cn/blog_migrate/c0ce7b98fe472bc64f87c7538aaf98fa.jpeg)
多维数组必须指定沿哪条轴连接。否则,Numpy默认沿第一条轴连接:
![b30311c36facc6ae2f0fda7c4a11a7b0.png](https://i-blog.csdnimg.cn/blog_migrate/fb63afc4c6291815e1a75a708618d6ef.jpeg)
将大量数据保存为二进制文件而不用原格式存储,这样的情况很常见。NumPy的tostring函数可将数组转化为二进制字符串。当然,这个过程是可逆的, fromstring函数可将二进制字符串还原为数组。例如:
![64e31c0d129d1630bce77643c709fa3b.png](https://i-blog.csdnimg.cn/blog_migrate/6c723c3a968c468ef35a9f3c2b4734e4.jpeg)
![15d90a550e542362fe71719fdeeb7fd5.png](https://i-blog.csdnimg.cn/blog_migrate/2f7dcf27cd3fc2e3bbd764bba993bf11.jpeg)
表1.2
3. 数组运算
NumPy数组显然支持常见的数学运算。例如:
![435008e51fb2e56935750101fa1903ee.png](https://i-blog.csdnimg.cn/blog_migrate/b050e754fb94e7972febf208dd41445d.jpeg)
既然上述运算都作用于元素级别,这就要求参与运算的数组大小相同。如果该条件不能满足,就会返回错误:
![8f44248bae1ce280b40ffb9888590120.png](https://i-blog.csdnimg.cn/blog_migrate/632ca0ede4fc6011eb2c0d0445394fa5.jpeg)
上述错误信息的意思是无法对对象进行广播(broadcast ) ,因为大小不同的数组参与运算的唯一方法叫作广播。广播的意思是数组维度不同时,维度少的数组将多次重复自身,直到它跟另外一个数组维度相同。看下面的示例:
![e0a229e67c9cf79ed24bb458b941e929.png](https://i-blog.csdnimg.cn/blog_migrate/db15a2e9e6d1db37e35ffcfdd9e8315d.jpeg)
arr2被广播成大小跟arr1相同的二维数组。因而,对于arr1的每一维, arr2都重复自身一次,相当于arr2变换为下面这个数组后再参加运算:
![ba3c8a883a0ee239dbbc4c4be0a28b8e.png](https://i-blog.csdnimg.cn/blog_migrate/6225174dbaf21a405140d80b34103355.jpeg)
如要明确指定数组的广播方式,可用newaxis常量:
![c77bf8bc1c3206271e2d3e53ed2f2df8.png](https://i-blog.csdnimg.cn/blog_migrate/a8eb72bf0fe8540082d594b10bf0cff5.jpeg)
跟python列表不同的是,数组支持按条件查询,用布尔数组过滤元素就是一个典型的例子:
![f37a703c41b858ae608990a78fb6eed7.png](https://i-blog.csdnimg.cn/blog_migrate/e5870532169b13e8a1d9c1dad1569cb8.jpeg)
可以用多个布尔表示式获取数组的子集:
![0fd120e0c5680c00a76796fd3a358804.png](https://i-blog.csdnimg.cn/blog_migrate/3a1528f141356e8d13ed23cc507ef3e6.jpeg)
我们可以根据索引选取元素,用目标元素的索引构造一个数据类型为整型的数组,然后,将索引数组放到目标数组的后面,并用方括号括起来。例如:
![5b0f88dfd33d39c187a2732602deef28.png](https://i-blog.csdnimg.cn/blog_migrate/bbe0ecac8bf65f16150c34b8f635fd0f.jpeg)
上述第3行代码,表示按照arr2指定的索引顺序,从数组arr1中选取相应的元素,也就是选取arr1的第0、第1、第1、第3、第1、第1和第1个元素。用列表存储目标元素的索引,可以达到同样的选取效果:
![bda4cea34408093dd09428312e3e5fff.png](https://i-blog.csdnimg.cn/blog_migrate/fbcea684dde4a9f3ba3dcdb3724b4bf7.jpeg)
多维数组的选取操作,需要使用多个一维度的索引数组,每个维度对应一个索引数组。索引数组放到Python列表中,再将Python列表置于多维数组后面的方括号之中。
第1个种子数组( selection array )存储矩阵元素的行号,第2个种子数组存储列号。例如:
![a565755a5a7ebf4d1612871a6d10cede.png](https://i-blog.csdnimg.cn/blog_migrate/c2a976bace5516f1e63f600de1b893c0.jpeg)
arr2的元素为arr1元素的行号,而arr3的元素则为arr1元素的列号,因此从arr1选取的第1个元素为位于第1行、第1例的13。
take函数支持以索引数组为参数,从调用它的数组选取元素,效果等同于上面的方括号选择法:
![10f6df2bdf95e9618778b2257ce7aab0.png](https://i-blog.csdnimg.cn/blog_migrate/833072afda7e697af30081965b84d730.jpeg)
用axis参数指定维度,task函数可从调用它的多维数组、沿指定维度选取一部分元素:
![c21110ec8831e515a40226d04663196d.png](https://i-blog.csdnimg.cn/blog_migrate/c0b3b89c287b0e6157f271255b56649c.jpeg)
put函数为take函数的逆操作,它有两个参数:将元素放到什么位置(索引列表)、被投放的元素来自哪个数组。put函数将一个数组的元素放到调用该函数的另一个数组的指定位置:
![42cde367de4ec78dde5d03b37b4a7f4a.png](https://i-blog.csdnimg.cn/blog_migrate/cad05865b3ed3d2fbe266896e955fb93.jpeg)
本节最后,我们想提醒你注意,二维数组的乘法运算也是元素级的(但矩阵乘法不是):
![0d529d86f041f8fb1ca239cdbb1c42bd.png](https://i-blog.csdnimg.cn/blog_migrate/a762f93408e2b5f496dbf4b4d458cdd1.jpeg)
![c9caca8b8e83dd02603510b87e4c9de2.png](https://i-blog.csdnimg.cn/blog_migrate/ce5c69830261325a96f48c4b9f5dfa80.jpeg)
表1.3
4.线性代数运算
矩阵之间最常用的运算是,矩阵与其转置矩阵的内积XTX,计算内积,用np.dot函数 :
![651b5015d616de660e8ca37851623743.png](https://i-blog.csdnimg.cn/blog_migrate/31fe0a9068b9cfd732098942a1ee504c.jpeg)
有几个函数可直接计算数组(矩阵或向量)不同类型的积(内积、外积、向量积)。
一维数组(向量)的内积与点积相同:
![472d802a28262ea53444bab2941ab568.png](https://i-blog.csdnimg.cn/blog_migrate/deecbb0220375ec58b2ca4371d4741fe.jpeg)
NumPy的linalg模块,实现了矩阵的多种线性代数运算。例如,计算矩阵的行列式的值:
![558a73d1881dbab2faa9eb31f7a82f84.png](https://i-blog.csdnimg.cn/blog_migrate/cea1d75660aa4234eadf193d43ebece7.jpeg)
Inv函数生成矩阵的逆矩阵:
![5ce7958acd018477591df88b291d4e86.png](https://i-blog.csdnimg.cn/blog_migrate/a99a009900fb321334fabbabd89ec038.jpeg)
矩阵的特征值(eigenvalues)和特征向量(eigenvectors)计算方法很简单:
![bd4f54fb48efe484f545e61e0dab7097.png](https://i-blog.csdnimg.cn/blog_migrate/2d0118bbb8f1132efeb42216e9748216.jpeg)
![c8c7c5d97472b029f05fecd8313f4263.png](https://i-blog.csdnimg.cn/blog_migrate/f592d3c59546c40dfad8ddc57a9b10bd.jpeg)
表1.4
5.统计和数学函数
NumPy提供一组计算数组元素统计信息的函数。聚合型运算,比如求和、均值、中位数和标准差,可通过访问数组的相应属性得到。例如,随机选取元素(服从某正态分布) ,创建一个数组,我们可以用以下两种方法计算数组元素的均值:
![d101cbe90602d5a216acee1a065e5f74.png](https://i-blog.csdnimg.cn/blog_migrate/29543b56ee7bd73c226d4200e4794aa1.jpeg)
所有这一类函数见表1.5。
![41af3801291e9844ae556cf6d5976f7c.png](https://i-blog.csdnimg.cn/blog_migrate/dfac01e45990f5d5787d523b55fe2fb9.jpeg)
表1.5
本文节选自《机器学习Web应用》
![79ccff11015451ce63740eef6f96fb6c.png](https://i-blog.csdnimg.cn/blog_migrate/b4c97ff19378c0a836f5cfff01dfcf1f.jpeg)
这是一本结合Python语言讲述Web下机器学习的图书,本书内容全面,既能够让读者熟悉最基本的机器学习的相关概念,也能够了解Web下数据挖掘的工具和技术,除此之外,书中还会介绍与Django框架有关的知识以及数据库管理等内容,帮助读者掌握聚类和分类技术并用Python实现它们。