数据处理中模块之numpy
一、numpy
模块
Numpy
是Python
科学计算的基础包,它提供不了多维数组对象,基于数组的各种派生对象(例如掩码数组和矩阵),以及用于对数组进行快速操作的各种例程,包括数学、逻辑、形状操作、排序、选择、I/O 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。
1.1 基础介绍
Numpy
的核心是ndarray
对象。一方面,ndarray
对象封装了可以包含相同数据类型的多维数组,另一方面,为了获得更好的性能,在ndarray
上的操作都是在编译过的代码上执行的,和Python
自身的序列对象相比,两者有如下区别:
Numpy
数组的大小是固定的,Python
的list
是可以动态增长的,改变Numpy
的大小会重新创建一个新的数组并把原来的删掉;Numpy
数组中的元素一定是同一类型的(相应地,每个元素所占的内存大小也是一样的),数组的维度被称为axes
,维数称为rank
;Numpy
数组支持在大量数据上进行数学计算和其他类型的操作,通常情况下与Python
自带序列相比,Numpy
数组上的操作执行更高效,代码量也更少;- 原来越多的
Python
科学计算都用到了Numpy
数组。虽然这些库支持Python
序列类型的输入,但是内部操作还是要先将其转换为Numpy
的数组类型,而且输出通常就是Numpy
数组。所以,如果你想要高效地使用这些Python
的科学计算包,仅仅知道Python
内建的序列类型是不够的,你还需要知道如何使用Numpy
数组。
1.2 重要属性
ndarray
的重要属性包括:
ndarray.ndim
:数组的维数,也称为rank
;ndarray.shape
:数组各维的大小,tuple
类型;对一个n
行m
列的矩阵来说,shape
为(n,m)
;ndarray.size
:元素的总数;ndarray.dtype
:每个元素的类型,可以是numpy.int32
、numpy.int16
、numpy.float64
、numpy.bool
、numpy.complex128
等;ndarray.itemsize
:数组中每一个元素分别所占空间的大小;ndarray.data
:指向数据内存;
1.2.1 简单示例
有许多种方法生成数组。比如,可以将Python list
或 tuple
转化为数组,转化后的数组元素的类型由原来的对象的类型来决定;
import numpy as np
a = np.array([1,2,3,4])
print(a) # [1 2 3 4]
print(a.dtype) #每个元素的类型 int32
print(a.shape) #数组各维的大小 (4,)
b = np.array([1.2,3.4,5.6,5])
print(b) [1.2 3.4 5.6 5. ]
print(b.dtype) [1.2 3.4 5.6 5. ]
#指定数据类型
c = np.array( [ [1,2], [3,4] ], dtype=complex )
print(c) #[[1.+0.j 2.+0.j][3.+0.j 4.+0.j]]
print(c.dtype) # complex128
1.2.2 生成固定大小数组
我们无法事先知道数组元素的具体值,但是数组大小是已知的。 这时可以用下面几种方法生成数组。 默认的,生成的数组的元素类型为float64
。
#zeros 函数生成元素全部为0的数组,
print(np.zeros((3,4)))
#empty函数生成元素没有赋值的数组,这时元素值由内存中原来的内容决定。
print(np.empty((2,3)))
#ones函数生成元素全部为1的数组
print(np.ones((2,3,4),dtype = np.int16))
#arange 函数生成的数组的元素按照等比数列排布,类似于range函数。
print(np.arange( 10, 30, 5 ))
print(np.arange( 0, 2, 0.3 )) # it accepts float arguments
#linspace函数有些类似matlab中的同名函数,下面是个例子:
print(np.linspace( 0, 2, 9 )) # 9 numbers from 0 to 2
x = np.linspace( 0, 2*pi, 100 ) # useful to evaluate function at lots of points
f = np.sin(x)
输出结果:
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]]
[[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]
[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]]
[10 15 20 25]
[0. 0.3 0.6 0.9 1.2 1.5 1.8]
[0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. ]
二、基础函数
2.1 算数运算
基本的算术运算符都可以应用于数组类型,结果为对应元素之间的运,返回值为一个新的数组;比如
a = np.array([20,30,40,40])
b = np.arange(4)
print(a-b)
print(b**2)
print(10*np.sin(a))
print(a<35)
输出结果:
[20 29 38 37]
[0 1 4 9]
[ 9.12945251 -9.88031624 7.4511316 7.4511316 ]
[ True True False False]
2.1.1 乘法运算符
*
表示的也是元素乘法,如果需要矩阵乘法,可以使用dot
函数或者生成一个matrix
对象;
A = np.array( [[1,1],[0,1]])
B = np.array( [[2,0],[3,4]])
print(A*B) #对应元素相乘
print(np.dot(A,B)) #矩阵乘法
输出结果:
[[2 0]
[0 4]]
[[5 4]
[3 4]]
2.1.2 不同元素类型运算
当两个不同元素类型的数组运算时,结果的元素类型为两者中更精确的那个(类型提升);
a = np.ones(3,dtype=np.int32)
b = np.linspace(0,np.pi,3)
print(b.dtype)
c = a*b
print(c)
print(c.dtype)
输出结果:
float64
[0. 1.57079633 3.14159265]
float64
2.1.3 sum、min、max
Numpy
提供了许多内置的运算方法比如:
a = np.random.a = np.random.random((2,3))
print(a)random((2,3))
print(a.sum()) #计算所有元素和
print(a.min()) #获取最小的元素
print(a.max()) #获取最大的元素
输出结果:
[[0.6028089 0.66860186 0.37737517]
[0.18416065 0.03146056 0.27444081]]
2.1388479560986995
0.03146056041598588
0.668601860383035
默认情况下, 这些方法作用于整个数组,通过指定axis
,可以使其只作用于某一个axis
;
print(a.sum(axis = 0)) #按列求和
print(a.sum(axis = 1)) #按行求和
print(a.cumsum(axis = 1)) #按行累加
输出结果:
[0.78696956 0.70006242 0.65181598]
[1.64878593 0.49006202]
[[0.6028089 1.27141076 1.64878593]
[0.18416065 0.21562121 0.49006202]]
2.1.4 sin, cos, and exp
print(np.sin(a))
print(np.cos(a))
print(np.sqrt(a))
print(np.exp(a))
print(np.add(a,b))
输出结果:
[[0.56695853 0.61988949 0.36848161]
[0.18312145 0.03145537 0.27100871]]
[[0.82374634 0.78468912 0.92963504]
[0.9830903 0.99950516 0.96257689]]
[[0.77640769 0.81768078 0.61430869]
[0.42913943 0.17737125 0.52387098]]
[[1.82724415 1.95150693 1.45845138]
[1.20220895 1.03196067 1.31579469]]
[[0.6028089 2.23939819 3.51896783]
[0.18416065 1.60225689 3.41603346]]
2.2 常用函数
2.2.1 numpy.linalg.norm(x)
顾名思义:linalg = linear + algebra
,norm
则表示范数,首先需要注意的是范数是对向量(或者矩阵)的度量,是一个标量(scalar
) :
首先help(np.linalg.norm)
查看文档
norm(x, ord=None, axis=None, keepdims=False)
x
表示要度量的向量,ord
表示范数的种类
参数 | 说明 | 计算方法 |
---|---|---|
默认 | 二范数 | np.sqrt(\(x_1^2+x_2^2+....+x_n^2\)) |
ord=2 | 二范数 | 同上 |
ord=1 | 一范数 | |\(x_1\)|+|\(x_2\)|+...+|\(x_n\)| |
ord=np.inf | 无穷范数 | max(|\(x_i\)|) |
用于计算向量x
的2
范数;
x = np.array([3,4])
y = np.linalg.norm(x)
print(y)
输出结果为5.0
。
计算矩阵x
的2
范数,对矩阵每一个元素求平方和然后开根号;
x = np.array([3,4,5],[3,4,5])
y = np.linalg.norm(x)
print(x)
输出结果为10.0
。
2.2.2 numpy.log10(x)
计算以10
为底的对数,log
下什么都不写默认是自然对数 e
为底;
x1 = 10
y1 = np.log10(x1)
x2 = np.e
y2 = np.log(x2)
print(y1,y2)
输出结果为1.0 1.0
。
2.2.3 numpy.nan_to_num
Replace nan with zero and inf with finite numbers
,把np.nan
(非常小的数字,接近0)用0取代。
np.inf
,或者-np.inf
(正负无穷大的数字)用有限数替代;
np.set_printoptions(precision=8)
x = np.array([np.inf, -np.inf, np.nan, -128, 128])
print(np.nan_to_num(x))
输出结果为[ 1.79769313e+308 -1.79769313e+308 0.00000000e+000 -1.28000000e+002 1.28000000e+002]
;
2.2.4 numpy.random.randn(d0, d1, …, dn)
从标准正态分布中返回一个或多个样本值。numpy.random.rand(d0, d1, …, dn)
的随机样本位于[0, 1)
中。
x1 = np.random.randn(2,4)
print(x1)
x2 = np.random.rand(2,4)
print(x2)
输出结果
[ 0.37065869 -0.04594328 0.72822393 0.74898655]]
[[ 0.54672608 0.0216933 0.04434537 0.65831692]
[ 0.06332446 0.75230353 0.12993006 0.75911764]]
2.2.5 numpy.random.normal(loc=0.0, scale=1.0, size=None)
正太分布,参数的意义为:
loc:float
:概率分布的均值,对应着整个分布的中心center
;scale:float
:概率分布的标准差,对应于分布的宽度,scale
越大越矮胖,scale
越小,越瘦高;size
:int or tuple of ints
维数;
2.2.6 numpy.random.random(size)
用于生成一个0到1的随机符点数: 0 <= n < 1.0
;例如:
print(np.random.random((2,3)))
输出结果:
[[0.5704968 0.3357748 0.14660701]
[0.96629921 0.39623942 0.2698468 ]]
2.2.7 numpy.random.uniform(a,b)
用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限;
- 如果
a > b
,则生成的随机数n: a <= n <= b
; - 如果
a <b
, 则b <= n <= a
;
测试如下:
print random.uniform(10, 20)
print random.uniform(20, 10)
# 18.7356606526
# 12.5798298022
2.2.8 random.randint(a, b)
用于生成一个指定范围内的整数。其中参数a
是下限,参数b
是上限,生成的随机数n: a <= n <= b
;
print random.randint(12, 20) # 生成的随机数 n: 12 <= n <= 20
print random.randint(20, 20) # 结果永远是20
# print random.randint(20, 10) # 该语句是错误的。下限必须小于上限
2.2.9 random.randrange([start], stop[, step])
从指定范围内,按指定基数递增的集合中获取一个随机数。如:
random.randrange(10, 100, 2)
,结果相当于从[10, 12, 14, 16, ... 96, 98]
序列中获取一个随机;random.randrange(10, 100, 2)
在结果上与random.choice(range(10, 100, 2)
等效;
2.2.10 random.choice(sequence)
从序列中获取一个随机元素。其函数原型为:random.choice(sequence)
。
参数sequence
表示一个有序类型。这里要说明 一下:sequence
在python
不是一种特定的类型,而是泛指一系列的类型。
list
, tuple
, 字符串都属于sequence
。有关sequence
可以查看python
手册数据模型这一章。
下面是使用choice
的一些例子:
print random.choice("学习Python")
print random.choice(["JGood", "is", "a", "handsome", "boy"])
print random.choice(("Tuple", "List", "Dict"))
2.2.11 random.shuffle(x[, random])
用于将一个列表中的元素打乱。如:
p = ["Python", "is", "powerful", "simple", "and so on..."]
random.shuffle(p)
print p
# ['powerful', 'simple', 'is', 'Python', 'and so on...']
2.2.12 len
对ndarray
类型使用len
函数,len
用于获取一个数组的长度,如果是多维数组,则获取数组的行数;
temp = np.zeros(shape=[10,20])
print(len(temp)) #10
2.2.13 numpy.squeeze(a, axis=None)
从数组的形状中删除单维度条目,即把shape
中为1
的维度去掉。
x = np.array([[[0], [1], [2]]])
print(x.shape) #(1, 3, 1)
print(np.squeeze(x).shape) #(3,)
print(np.squeeze(x, axis=(2,)).shape) # (1, 3)
2.2.14 numpy.expand_dims(a, axis)
该函数和np.squeeze()
正好相反,数组形状扩充一个维度的;
x = np.array([1,2])
print(x.shape) #(2,)
y = np.expand_dims(x, axis=0)
print(y.shape) #(1, 2)
2.2.15 其他
列向量和行向量,以及秩为1的数组的区别:
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 25 20:17:21 2018
x = np.array([[[0], [1], [2]]])
print(x.shape) #(1, 3, 1)
print(np.squeeze(x).shape) #(3,)
print(np.squeeze(x, axis=(2,)).shape) # (1, 3)
@author: Administrator
"""
import numpy as np
'''
下面显示了秩为1的数组以及列向量和行向量的使用,以及区别.我们在使用的时候最好不要使用秩为1的数组
并且当我们不确定矩阵或者向量的维数维数时,我们可以使用.reshape(m,n)指定
'''
#a为秩为1的数组,我们可以看到转置和本身一致,shape都是(5,)
a = np.random.randn(5)
print(a,a.shape) #[ 0.58371745 0.62467384 0.72225761 -0.32777546 -1.06321595] (5,)
print(a.T,a.T.shape) #[ 0.58371745 0.62467384 0.72225761 -0.32777546 -1.06321595] (5,)
r = np.dot(a,a)
print(r,r.shape) #2.49046445333 ()
r = np.dot(a,a.T)
print(r,r.shape) #2.49046445333 ()
#a1为5x1的列向量
a1 = np.random.randn(5,1)
print(a1,a1.shape) #[[-0.20126605]
# [-0.08183096]
# [ 0.12709234]
# [ 1.88915869]
# [1.18566033]] (5, 1)
#r1 = np.dot(a1,a1) #会报错 shapes (5,1) and (5,1) not aligned: 1 (dim 1) != 5 (dim 0)
#print(r1,r1.shape)
r1 = np.dot(a1,a1.T)
print(r1,r1.shape) #[[ 0.04050802 0.01646979 -0.02557937 -0.3802235 -0.23863317]
# [ 0.01646979 0.00669631 -0.01040009 -0.15459166 -0.09702372]
# [-0.02557937 -0.01040009 0.01615246 0.24009759 0.15068834]
# [-0.3802235 -0.15459166 0.24009759 3.56892057 2.23990052]
# [-0.23863317 -0.09702372 0.15068834 2.23990052 1.40579042]] (5, 5)
#a2为1x5的行向量
a2 = np.random.randn(1,5)
print(a2,a2.shape) #[ 0.48272148 0.4743339 -0.31309436 2.01153588 -0.58482391] (5,)
#r2 = np.dot(a2,a2) #会报错 shapes (1,5) and (,5) not aligned: 5 (dim 5) != 1 (dim 0)
#print(r2,r2.shape)
r2= np.dot(a2,a2.T)
print(r2,r2.shape) #[[ 3.81502768]] (1, 1)#由list或者touple转换为的秩为数组,我们最好指定其shapec = np.array([1,2,3,4])print(c.shape) #(4,)c = np.array([1,2,3,4]).reshape(4,1)print(c.shape) #(4,1)d = np.array([[1,2,3],[4,5,6]])print(d.shape) #(2,3)
2.3 索引、切片和迭代
与list
类似,数组可以通过下标索引某一个元素,也可以切片,可以用迭代器迭代;
a = np.arange(10) ** 3
print(a)
print([2,3,4,5]) #这是列表
print(a[2])
print(a[2:5])
print(a[0:6:-2])
print(a[::-1]) #倒叙排列
for x in a:
print(x)
def f(x,y):
return 10*x+y
b = np.fromfunction(f,(5,4),dtype=int)
print(b)
print(b[2:3])
print(b[0:5,3]) #0-4行索引第3列
print(b[:,1]) #所有行索引第1列
print(b[-1]) #最后一行
#多维数组迭代时以第一个维度为迭代单位:
for row in b:
print(row)
#如果我们想忽略维度,将多维数组当做一个大的一维数组也是可以的,下面是例子
for ele in b.flat:
print(ele)
输出结果:
[ 0 1 8 27 64 125 216 343 512 729]
[2, 3, 4, 5]
8
[ 8 27 64]
[]
[729 512 343 216 125 64 27 8 1 0]
0
1
8
27
64
125
216
343
512
729
[[ 0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]]
[[20 21 22 23]]
[ 3 13 23 33 43]
[ 1 11 21 31 41]
[40 41 42 43]
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43
三、代码下载
参考文献