《Python数据科学手册》第二章 Numpy入门2.1—2.3
Posted 钟JACK的书桌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Python数据科学手册》第二章 Numpy入门2.1—2.3相关的知识,希望对你有一定的参考价值。
2.1 理解Python中的数据类型
Python的用户被其易用性所吸引,其中一个易用之处就在于动态输入,即在Python中,类型是动态推断的。这意味着可以将任何类型的数据指定给任何变量。但是这种类型灵活性也指出了一个事实: Python 变量不仅是它们的值,还包括了关于值的类型的一些额外信息 。
C语言整型本质上是对应某个内存位置的标签,里面存储的字节会编码成整型。而Python的整型其实是一个指针,只向包含这个Python对象所有信息的某个内存位置,其中包括可以转换成整型的字节。Python 类型中的这些额外信息也会成为负担,在多个对象组合的结构体中尤其明显。
Python中的标准可变多元素容器是列表。 可用如下方式创建一个整型值列表
1 L=list(range(10)) 2 print(L)
输出结果为
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
或者创建一个字符串列表
1 L=list(range(10)) 2 L2=[str(c) for c in L] 3 print(L2)
其输出结果为
[‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘]
因为Python的动态类型特性,甚至可以创建一个异构的列表.
L3=[True,"2",3.0,4]
Python的array数组模块提供了数组型数据的有效存储,而Numpy包中的ndarry对象为该数据加上了高效的操作。
创建Numpy数组的方法,Numpy要求数组必须包含同一类型数据。如果类型不匹配,Numpy将会向上转换(如果可行)。
import numpy as np np.array([1,4,2,5,3])
如果要设置数组的数据类型,可以用dtype关键字:
np.array([1,2,3,4],dtype=‘float32‘)
Numpy数组可以被指定为多维的。以下是用列表的列表初始化多维数组的一种方法
np.array([range(i,i+3) for i in [2,4,6]]) # range(start, stop[, step]) range(起,终,步长)
其输出结果如下,内层列表被当做二维数组的行
([2,3,4], [4,5,6], [6,7,8])
在面对大型数组的时候,用Numpy内置的方法从头创建数组是一种更高效的方法。
# 创建一个长度为10的数组,数组的值均为0 np.zeros(10,dtype=int) #创建一个3×5的浮点数组,数组的值均为3.14,3行5列 np.full((3,5),3.14) #创建一个3×3的、[0,10)区间的随机整型数组 np.array.randint(0,10,(3,3)) #创建一个3×3的单位矩阵 np.eye(3)
当用Numpy构建一个数组时,可以用一个字符串参数来指定数据类型
2.2Numpy数组基础
Python中的数据操作几乎等同于Numpy数组操作,甚至Pandas也是构建在Numpy数组基础之上的。
介绍以下几类基本的数组操作:
属性:确定数组的大小、形状、存储大小、数据类型 索引:获取和设置数组各个元素的值 切分:在大数组中获取或设置更小的数组
变形:改变给定数组的形状 拼接和分裂:将多个数组合并为一个,以及将一个数组分裂成多个
2.2.1 Numpy数组的属性
我们将用Numpy的随机数生成器设置一组种子值,以确保每次程序执行时都可以生成同样的随机数组
import numpy as np np.random.seed(0)# 设置随机数种子 x3=np.random.randint(10,size=(3,4,5))#三维数组 #每个数组有nidm(数组维度)、shape(数组每个维度的大小)、 #size(数组的总大小)、dtype(数组的数据类型) print("x3 nidm",x3.ndim) print("x3 shape",x3.shape) print("x3 size",x3.size) print("x3 dtype",x3.dtype) #x3 nidm: 3 x3数组有3个维度 #x3 shape: (3,4,5) 第一个维度大小为3 #x3 size: 60 3×4×5=60 #x3 dtype: int64
2.2.2 数组索引 获取单个元素
在一维数组中,你也可以通过中括号指定索引获取第i个值(从0开始计数)。为了获取数组末尾的索引,可以用负值
import numpy as np L=np.array([1,2,3,4]) print(L) print(L[-1]) print(L[-4]) #输出结果为 #[1 2 3 4] #4 #1
在多维数组中,可以用逗号分隔的索引元组获取元素:
import numpy as np np.random.seed(0) x2=np.random.randint(10,size=(3,4)) print(x2) #数组为[[5 0 3 3] # [7 9 3 5] # [2 4 7 6]] print(x2[0,0]) #行、列均从0开始计数 prnit(x2[0,3]) #行、列均从0开始计数
用以上方式也可以修改元素值,请注意,和 Python 列表不同, NumPy 数组是固定类型的。这意味着当你试图将一个浮点值插入一个整型数组时,浮点值会被截短成整型。并且这种截短是自动完成的,不会给你提示或警告,所以需要特别注意这一点!
2.2.3数组切片:获取子数组
用切片(slice)获取子数组 x[start:stop:step],如果3个参数均未指定,其默认值start=0、stop=维度大小、step=1
import numpy as np x=np.arrange(10) # 数组为[0 1 2 3 4 5 6 7 8 9] x[:5]#前五个元素 x[5:]#索引五之后的元素 x[4:7]#从索引4开始 到索引7之前 x[::2]#每隔一个元素 x[::-1]#所有元素 逆序的
对于多维子数组,也用冒号分隔进行处理
x2[:2,:3]#前两行 前三列 #子数组维度也可以同时被逆序 x2[::-1,::-1]
一种常见的需求是获取数组的单行和单列。你可以将索引与切片组合起来实现这个功能,用一个冒号(:)表示空切片
#获取x2的第一列 x2[:,0] #获取x2的第一行 x2[0,:] #在获取行时 出于语法简介考虑 可以省略空切片 x2[0]
关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数值数据的副本。
这一点也是NumPy数组切片和Python列表切片的不同之处:在Python 列表中,切片是值的副本,改变切片里的值,原始数组也会修改。
这种默认的处理方式实际上非常有用:它意味着在处理非常大的数据集时,可以获取或处理这些数据集的片段,而不用复制底层的数据缓存 。
创建数组的副本,用copy()方法实现,修改子数组,原始数组不会被改变。
x2_sub_copy=x2[:2,:2].copy()
2.2.4数组的变形
数组变形最灵活的方式是通过reshape()函数来实现,但要求原始数组的大小必须和变形后的数组的大小一致
import numpy as np grid=np.arange(1,10).reshape((3,3)) print(grid)
另一个常见的变形模式是将一个一维数组转变为二维的行或列矩阵,可以用reshape,也可以在切片中用newaxis
import numpy as np x=np.array([1,2,3]) x.reshape((1,3)) #[[1 2 3]] #通过newaxis获得行向量 x[np.newaxis,:] #通过newaxis获得列向量 x[:,np.newaxis]
2.2.5数组的拼接和分裂
拼接或连接NumPy中的两个数组主要由np.concatenate、 np.vstack和np.hstack例程实现 。
np.concatenate将数组元组或数组列表作为第一参数
x=np.array([1,2,3]) y=np.array([3,2,1]) z=[99,99,99] np.concatenate([x,y]) np.concatenate([x,y,z])
np.concatenate也可以用于二维数组的拼接
import numpy as np grid=np.array([[1,2,3], [4,5,6]]) #沿着第一个轴拼接 np.concatenate([grid,grid]) #[[1, 2, 3], # [4, 5, 6], # [1, 2, 3], # [4, 5, 6]] #沿着第二个轴拼接(轴是从0开始索引的) np.concatenate([grid,grid],axis=1) # [[1, 2, 3, 1, 2, 3], # [4, 5, 6, 4, 5, 6]]
沿着固定维度处理数组时,使用 np.vstack(垂直栈)和 np.hstack(水平栈)函数会更简洁,np.dstack将沿着第三个维度拼接。
与拼接相反的过程是分裂。分裂可以通过 np.split、 np.hsplit(水平分裂) 和 np.vsplit(垂直分裂) 函数来实现。 索引列表作为参数,记录的是分裂点的位置。
import numpy as numpy x=[1,2,34,6,99,56,26,11,22,33,444,50] x1,x2,x3=np.split(x,[3,6]) print(x1,x2,x3) #[ 1 2 34] [ 6 99 56] [ 26 11 22 33 444 50] #N个分裂点会得到N+1个数组
2.3Numpy数组的计算:通用函数
Numpy提供了一个简单灵活的接口来优化数据数组的计算。使Numpy变快的关键是利用向量化操作,通常用Numpy的通用函数。
通用函数有两种存在形式: 一元通用函数(unary ufunc)对单个输入操作, 二元通用函数(binary ufunc)对两个输入操作。
Numpy的通用函数可以对数组进行向量化操作,可以提高数组元素的重复计算的效率。通用函数的主要目标是对Numpy数组中的值执行更快的操作
import numpy as np np.arange(5)/np.arange(1,6) # array([0. , 0.5 , 0.66666667, 0.75 , 0.8 ]) x=np.arange(9).reshape((3,3)) 2**x #array([[ 1, 2, 4], # [ 8, 16, 32], # [ 64, 128, 256]], dtype=int32)
通过通用函数用向量的方式进行计算几乎总比用 Python 循环实现的计算更加有效,尤其是当数组很大时。
只要你看到 Python 脚本中有这样的循环,就应该考虑能否用向量方式替换这个循环。
(1)加减乘除,逻辑非,**表示的指数运算符和%表示的模运算符 都是一元通用函数
(2)绝对值函数。直接abs(),括号内为一个Numpy数组
(3)三角函数。np.sin() np.cos() np.tan() np.arcsin() np.arccos() np.arctan() 括号里直接是一个Numpy数组
(4)指数和对数。np.exp(x)表示 e^x np.exp2(x)表示2^x np.power(3,x)表示3^x。
最基本的 np.log 给出的是以自然数为底数的对数。如果你希望计算以2为底数或者以10为底数的对数 np.log2(),np.log10()
2.3.4高级通用函数的特性
指定输出:所有的通用函数都可以通过out参数来指定计算结果的存放位置
import numpy as np x=np.arange(5) y=np.empty(5) np.multiply(x,10,out=y) print(y) #[ 0. 10. 20. 30. 40.]
聚合:一个reduce方法会对给定的元素和操作重复执行,直至得到单个的结果 。
import numpy as np x=np.arange(10) np.add.reduce(x) # 45
np.add.reduce()#返回数组中所有元素的和
np.multiply.reduce()#返回数组中所有元素的积
如果需要存储中间结果,可以使用accumulate
外积:任何通用函数都可以用 outer 方法获得两个不同输入数组所有元素对的函数运算结果。这意味着你可以用一行代码实现一个乘法表:
import numpy as np x=np.arange(1,6) np.multiply.outer(x,x) Out[17]: array([[ 1, 2, 3, 4, 5], [ 2, 4, 6, 8, 10], [ 3, 6, 9, 12, 15], [ 4, 8, 12, 16, 20], [ 5, 10, 15, 20, 25]])
有关通用函数的更多信息(包括可用的通用函数的完整列表)可以在 NumPy(http://www.numpy.org)和 SciPy(http://www.scipy.org)文档的网站找到。
前面的章节介绍过,可直接在 IPython 中通过导入相应的包,然后利用 IPython 的 Tab 键补全和帮助(?)功能获取信息 。
以上是关于《Python数据科学手册》第二章 Numpy入门2.1—2.3的主要内容,如果未能解决你的问题,请参考以下文章
数据科学速查手册(包括机器学习,概率,微积分,线性代数,python,pandas,numpy,数据可视化,SQL,大数据等方向)
Python数据科学快速入门系列 | 01Numpy初窥——基础概念