最近也需要使用Python进行数据处理,但Python一直学了未用,很多知识也都迷迷糊糊的了,所以现在复习回顾一下。(之后抽空也回顾一下Python基础语法)
数据分析一般流程:数据读写–>数据的处理计算–>数据的分析建模–>数据可视化
用Python进行数据分析工具有三:
- NumPy:多维数组/矩阵基础包,是很多其他包(如Pandas)的基石
- Pandas:基于NumPy的数据分析,支持Series、DataFrame等,功能强大
- Matplotlib:用于快速生成2D图像
其中NumPy使用很为频繁,在本文中将对其基本用法详细阐述。
本文以np代指NumPy库,以NP代指一个NumPy对象
注:下文np是
引入的numpy的别名,正常使用可以直接使用numpyimport numpy as np
1.概述
1.1背景介绍
现实世界中很多实际问题都可以抽象成n维数组,比如:一张黑白照片,是由 长度*宽度*单个像素的灰度 三维数组组成;一张彩色照片,也可以抽象成 长度*宽度*单个像素上(R*G*B) 这样更多维数组组成;还有音频等等,普通的表格数据记录更是如此。所以NumPy应运而生。
1.2NumPy介绍
Numpy是用于数据科学计算的基础模块,是Python的一个开源数值计算扩充程序库。不但支持大量的维度数组和矩阵运算,还能被用作高效的多维数据容器,可用于存储和处理大型矩阵。也有助于其他高效的数据处理工具的使用。
NumPy提供了两种基本对象,以弥补传统Python用list(列表)保存值而存在浪费CPU等诸多问题:
- ndarray:是存储单一数据类型的多维数组
- ufunc:一种能够对数据进行处理的函数
2.NumPy数组对象
2.1NumPy创建数组
2.1.1使用np.array()进行类型转化
np.array()方法本意上是将Python对象转化为ndarray对象
-
一维数组
a = np.array([1,2,3])
-
二维数组
a = np.array([1,2,3],[4,5,6],[7,8,9])
-
多维数组
a = np.array([[[1,2], [3,4]],[[5,6],[7,8]]])
等等,三维数组如上,即在二维之上在加一个维度,达成2*2*2。同理,三维数组的3*3*3如下:
import numpy as np a=np.array([[[1,2,3],[1,2,3],[1,2,3]], [[4,5,6],[4,5,6],[4,5,6]], [[7,8,9],[7,8,9],[7,8,9]]]) #输出如下 # [[[1 2 3] # [1 2 3] # [1 2 3]] # [[4 5 6] # [4 5 6] # [4 5 6]] # [[7 8 9] # [7 8 9] # [7 8 9]]]
更多维数组同理。
注意:array数组样式为array([]),无论里面有多少[],最外一层要用[]套起来,要确保括号的数量对应的起来。
2.1.2使用np.arange()函数
格式为:
np.arange(start, stop, step, dtype)
类似于range,由前两个参数指定上界和下界,第三个参数指定步长,并且不同于range,步长可以是浮点数
a = np.arange(1,5)
`得到
`array([1,2,3,4])
b = np.arange(1,5,0.5)
`得到
`array([1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5])
NumPy的reshape()函数可以指定矩阵的维度
格式为:
np.reshape(参数1, 参数2, 参数3, ...)
一个参数代表一个维度的长度,比如二维2*4,就(2,4);三维3*3*6,就(3,3,6)
注意,使用值-1让其自动识别计算
c = np.arange(1,5).reshape(2,2)
`得到
`array([1,2],[3,4])
2.1.3使用np.linspace()函数
格式为:
np.linspace(start, stop, num)
从start开始,到stop结束(包括stop),按等差数列生成数组,num为数组元素个数,默认50个
与np.arange()类似,但arange是按步长生成数组,linspace是按元素个数生成数组
a = np.linspace(1, 10, 5)
`得到
`array([1. 0, 3.25, 5.5, 7.75, 10.0])
2.1.4自动填充函数(zeros(),full()…)
-
用1创建数组np.ones()
括号内表明数组形状
a = np.ones(3) print(a) # [1. 1. 1.] b = np.ones((2,2)) print(b) # [[1. 1.] [1. 1.]]
注意,默认是浮点类型的,如果应用于多维数组,要用小括号将形状括起来作为一个参数,形状只是一个参数
对已知数组NP,用1填充np.ones_like(NP)
a = np.arange(6) b = a.reshape(2,3) arr = np.ones_like(b) print(arr) # [[1 1 1] [1 1 1]] print(b) # [[0 1 2] [3 4 5]] 不会影响b
-
用0创建数组np.zeros()
对已知数组NP,用0填充np.zeros_like(NP)
用法同上
-
np.empty()
只分配内存,不填充数据np.empty_like(NP)
-
**np.full(shape, fill_value)
指定数组形状shape和填充值fill_value
例如
arr = np.full(shape=(2,3), fill_value=2)
np.full_like(NP, fill_value)
例如
arr = np.full_like(b, fill_value=2)
总结常用函数如下:
2.1.5使用np.random库随机创建
要用到np.random库
-
np.random.random(num)
用随机数创建数组,这个函数产生0-1的随机数,参数表明数组元素个数
a = np.random.random(3) print(a) # [0.02594803 0.3378691 0.86790005]
-
np.random.randint(low, high, size=, dtype=)
前两个参数指定随机数产生区间,注意前闭后开[a,b),size参数指定数组形状,dtype参数可以指定数据类型,默认int,一般使用默认值即可
a = np.random.randint(1, 50, size=(2,2)) print(a) # [[ 9 24] [39 2]]
注意,“size=”可以省略,即只写(2,2)也可以,最好还是写上
-
np.random.normal(loc, scale, size=)
创建的数组服从标准正态分布,前两个参数分别指定均值和方差
-
np.random.seed()
随机种子,使接下来生成的随机数属于同一批随机数
np.random.seed(1) a = np.random.random(3) np.random.seed(1) b = np.random.random(3) print(a) # [4.17022005e-01 7.20324493e-01 1.14374817e-04] print(b) # [4.17022005e-01 7.20324493e-01 1.14374817e-04]
2.1.6单位矩阵
-
np.eye(a, b, dtype=, k=)
创建一个单位矩阵,只有指定的对角线上值为1,其余值为0
前两个参数指定矩阵形状,dtype指定矩阵元素类型,k指定“对角线”位置,k值>0即向右平移|k|个元素,k值<0即向左平移|k|个元素
-
np.identity(n, dtype=)
类似于上,创建一个n*n的对角矩阵
2.2NumPy数组属性
NumPy的主要对象是同质多维数组/矩阵。
同质即元素类型都相同,其中维度称作轴axis,轴的数目称为rank。
axis 0 通常指行;axis 1通常指列
属性(方法) | 说明 |
---|---|
NP.ndim(用法下同) | 返回int。数组的维数。 |
shape | 返回tuple。数组的尺寸,例n*m的数组,则为(n,m)。 |
size | 返回int。数组元素总数。 |
dtype | 返回data-type。数组中元素的类型。 |
itemsize | 返回int。数组每个元素的大小(以字节为单位)。 |
实例:
import numpy as np
arr = np.arange(1,13).reshape(3,4)
# [[1 2 3 4] [5 6 7 8] [9 10 11 12]]
print(arr.shape) # (3,4),形状
print(arr.ndim) # 2,维度
print(arr.dtype) # int32,元素类型
print(arr.size) # 12,元素个数
注意:与函数不同,最后不需要(),没有参数
部分数组属性也是一同被实际记录在内存中的,ndarray数组在内存中按以下规则存储
dtype | dimcount | dimensions | strides | data |
---|
3.NumPy数组操作
3.1NumPy数组切片
注意:NumPy数组用切片得到的子矩阵(数组)不同于Python中普通列表的切片,会修改原有数据值。若想不影响,可以先做一个副本,可以使用copy()函数。
3.2.1一维数组切片
与列表切片相同
数组索引是从0开始,且切片[start : end],从start开始到end-1结束。有第三参数表示步长(例:::-1)
arr = np.arrange(3) # [0 1 2]
print(arr[0:2]) # [0 1]
print(arr[-1]) # 2
print(arr[-1:]) # [2]
print(arr[1:]) # [1 2]
3.2.2多维数组切片
以二维数组为例:
格式为arr[x_start:x_end,y_start:y_end]
可以看作有两个切片(从start到end-1)组成的,中间用逗号隔开。前一个是在行的切片,取的是行数;后一个是在列的切片,取的是列数。有第三参数表示步长(例:::-1)
实例如下,比如第一个例子,“:2”取0、1即前两行,“1:”取1、2即后两行,交叉形成的即为取出的切片。
多维数组同理,几维即采用几层切片,中间用逗号隔开即可
多维数组只用一个索引:arr[0],是对行进行操作;而一维数组可以理解成对列进行操作(因为只有一行)
注意,
是不一样的。前者取 :3 行中的2:5 列;后者,后面的[2:5]是对arr[:3]形成的新数组在进行行的选取,即先取 :3 行,再取其中的 2:5 行。arr[:3, 2:5]
与
arr[:3][2:5]
注意:原有的Python列表(list)、数组等,做切片操作是不会影响原有数据的,通过切片生成了一个新的数组,只是继承了数据;而ndarray数组用切片取的一部分数据组成的数组即为原有数组的一部分,改变切片即改变原数组,是共享存储空间的。所以要适当使用.copy()。
3.2.3“花式”索引
前面两个都是普通的索引,一般只能取出连续分布或因设置步长而产生的有规律的元素。但 花式索引(又称神奇索引、整数索引) 可以一次性访问数组中多个没有任何规律的元素。
花式索引又与普通索引不同,它总是将数据复制到一个新的数组,不会影响原有数据
它使用整数数组当作索引,索引称作整数索引
-
一维数组
用索引组成数组,得到索引数组,使用索引数组一次性调用多个数组元素
索引数组也是数组,两边要有中括号“[]”
arr = np.array([10,11,12,13,14,15,16]) f_arr = arr[[0,3,5]] # [0,3,5]即为索引数组,得到f_arr=[10,13,15]
-
多维数组
与前面多维数组的切片可以类似地理解,用逗号隔开,使用多层索引数组进行定位
以二维数组为例,前面一个为行索引,后面一个为列索引,只写一个只单独调用行或、列。当两者同在,即可根据行和列取具体的值,组成数组。
arr = np.array([[10,11,12,13], [20,21,22,23], [30,31,32,33]]) arr_1 = arr[[0,2]] # arr_1 = ([[10,11,12,13], # [30,31,32,33]]),只有行索引,则取的是[0]行和[2]行 arr_2 = arr[[0,2],[1,2]] # arr_2 = ([11,32]),分别取的是[0][1]、[2][2]
三维及以上同理
3.2.4布尔索引
使用布尔数组当作索引
使用比较运算符(
、>、<、…)得到布尔数组,比如在一堆整数的数组中,你想找到等于6或者比6大的数,那么就可以分别使用“==6”和“>6”来创建布尔数组==
注意:一维数组的长度必须和索引数组的长度一致
import numpy as np
arr = np.array([2,3,4,5,6,7,8,9])
arr == 6
# 通过比较运算符创建布尔数组:array([False,False,False,False,True,False,False,False],dtype=bool)
arr_1 = (arr==6) # 赋值给一个变量
arr[arr_1] # 通过布尔索引输出[6]
arr_2 = (arr>6)
# 通过比较运算符创建布尔数组:array([False,False,False,False,False,True,True,True],dype=bool)
arr[arr_2] # 通过布尔索引输出[7 8 9]
arr_3 = np.array([True,True,True,False,False,True,True,True])
# 直接创建一个布尔数组
arr[arr_3] # [2 3 4 7 8 9]
对于多维数组,同其他索引,使用多个一维布尔索引来定位
使用比较运算符只是创建布尔数组的方法之一,还可以手动创建等等
注意:从以上案例可以看出,默认布尔数组元素都是False或True,类型为bool类型,在NumPy,有特殊的bool类型,其中False可以用0代替,True可以用1代替,例:array([1,0,1],dtype=np.bool)
3.3NumPy数组变形
使用
函数,设置和改变数组NP形状NP.reshape()
3.3.1展平
使用
函数,返回原始展平的数组视图,对原数组本身是没有影响的np.ravel(order=)
使用
函数,得到一个展平的数组,与上一个不同,此函数会分配新内存,完成原数组到新数组的拷贝,则原数组数据不会发生改变。参数为order=’F’时,按列展平;默认order=’C’,按行展平np.flatten(order=)
“order=”可以省略
相比于ravel()函数,要达到展平数组的目的,一般还是使用flatten()函数
arr = np.array([0,1,2,3,4,5])
arr.reshape(3,2)
# [ [0 1 2]
# [3 4 5] ]
arr.ravel() # [0 1 2 3 4 5]
arr.flatten() # [0 1 2 3 4 5]
arr.flatten('F') # [0 3 1 4 2 5]
3.3.2堆叠
使用 hstack() 函数实现数组横向组合:np.hstack((arr1,arr2))
使用 vstack() 函数实现数组纵向组合:np.vstack((arr1,arr2))
使用 concatenate() 函数实现数组横向组合,令参数 axis=1 :np.concatenate((arr1,arr2),axis=1))
使用 concatenate() 函数实现数组纵向组合,令参数 axis=0 :np.concatenate((arr1,arr2),axis=0))
注:使用dstack()函数可以实现深度方向上的组合:np.dstack((arr1,arr2))
import numpy as np
arr1 = np.array([[10, 11, 12], [13, 14, 15]])
arr2 = np.array([[20, 21, 22], [23, 24, 25]])
arr_1 = np.hstack((arr1, arr2))
# [[10 11 12 20 21 22]
# [13 14 15 23 24 25]]
arr_2 = np.vstack((arr1, arr2))
# [[10 11 12]
# [13 14 15]
# [20 21 22]
# [23 24 25]]
arr_3 = np.concatenate((arr1, arr2), axis=1) # 同arr_1
arr_4 = np.concatenate((arr1, arr2), axis=0) # 同arr_2
3.3.3分割
使用 hsplit() 函数实现数组横向分割:
,参数indices可以是整数表明分割成的数组个数,也可以直接是数组np.hsplit(arr, indices)
使用 vsplit() 函数实现数组纵向分割:
,参数indices可以是整数表明分割成的数组个数,也可以直接是数组np.vsplit(arr, indices)
使用 split() 函数实现数组横向分割,令参数 axis=1 : np.split(arr, 2, axis=1)
使用 split() 函数实现数组纵向分割,令参数 axis=0 :
可以将数组分成相同大小的子数组np.split(arr, 2, axis=0)
使用使用 split() 函数自定义分割点:
,参数[ax]即表是分割点数组np.split(arr, [ax])
import numpy as np
arr = np.arange(16).reshape(4, 4)
arr_1 = np.hsplit(arr, 2)
# 两个数组在一起,也是一个数组
# [array([[ 0, 1],
# [ 4, 5],
# [ 8, 9],
# [12, 13]]),
# array([[ 2, 3],
# [ 6, 7],
# [10, 11],
# [14, 15]])]
arr_3,arr_4 = np.vsplit(arr, 2) # 分别赋给两个数组
print(arr_3)
# array([[0, 1, 2, 3],
# [4, 5, 6, 7]]),
print(arr_4)
# array([[ 8, 9, 10, 11],
# [12, 13, 14, 15]])
arr_11 = np.split(arr, 2, axis=1) # 同arr_1
arr_22 = np.split(arr, 2, axis=0) # 同arr_3、arr_4
arr_ = np.arange(10)
print(arr_) # [0 1 2 3 4 5 6 7 8 9]
arr_5 = np.split(arr_, [3, 8])
print(arr_5)
# [array([0, 1, 2]), array([3, 4, 5, 6, 7]), array([8, 9])]
更提倡分成几个数组就赋给几个数组,如上面的arr_3、arr_4
注意:遇到无法合并的、无法分割的,程序运行时会报错
3.4NumPy数组基本运算
3.4.1矩阵的+、-、*、/
数组的“+、-、*、/”均是对数组内部元素的操作
此外,可以使用相关运算方法进行数组运算:
数组相加np.add()
数组相减np.subtract()
数组相乘np.multiply()
数组相除np.devide()
一维数组:要求元素数目能够一一对应,则一一对应计算,否则会报错
import numpy as np
arr1 = np.array([2, 1])
arr2 = np.array([4, 5])
print(arr1+arr2)
print(np.add(arr1, arr2)) # [6 6]
print(arr1-arr2)
print(np.substract(arr1, arr2)) # [-2 -4]
print(arr1*arr2)
print(np.multiply(arr1, arr2))# [8 5]
print(arr1/arr2)
print(np.divide(arr1, arr2)) # [0.5 0.2] 除法会自动转浮点型,没有小数也会显示小数点
多维数组:
若数目可以对上,则同一维数组,一一对应计算;
若对不上,另一数组为一维数组,则触发广播机制,使每个或每组元素都进行同一计算,如下例;
若都是多维数组,对不上,触发不了广播机制,则报错。
import numpy as np
arr1 = np.array([[1, 2], [3, 4], [5, 6]])
arr2 = np.array([1, 2])
arr3 = np.array([1, 2], [3, 4])
print(arr1+arr2)
# [[2 4]
# [4 6]
# [6 8]]
print(arr1/arr2)
# [[1. 1.]
# [3. 2.]
# [5. 3.]]
# 其他类似
print(arr1*arr3) # 报错
3.4.2聚合运算
所谓聚合,就是把一组值变为一个值
NumPy中的聚合函数对单个数组进行操作,得到一个值,NumPy常用聚合函数如下:
函数 | 说明 |
---|---|
np.sum(arr) | 计算数组arr的和 |
np.mean(arr) | 计算数组arr均值 |
np.std(arr) | 计算数组arr标准差 |
np.var(arr) | 计算数组arr方差 |
np.median(arr) | 计算数组arr的中位数 |
np.prod(arr) | 计算arr中所有元素相乘,返回一个值 |
np.min(arr) | 计算数组arr最小值 |
np.max(arr) | 计算数组arr最大值 |
np.argmin(arr) | 返回数组arr最小元素的索引 |
np.argmax(arr) | 返回数组arr最大元素的索引 |
np.cumsum(arr) | 计算轴向展平数组元素累加和,返回由中间结果组成的数组 |
np.cumprod(arr) | 计算轴向展平数组元素累乘积,返回由中间结果组成的数组 |
部分聚合函数还可以通过对ndarray对象引用方法来实现
:求arr元素最小值 arr.min()
:求arr元素最大值 arr.max()
:求arr元素和arr.sum()
如果要特定对某行某列进行聚合运算,可以使用axis参数
import numpy as np
arr = np.array([[1,2],[3,4]])
print(np.sum(arr)) # 10
print(np.sum(arr,axis=0)) # 取每一列和[3 7]
print(np.sum(arr,axis=1)) # 取每一行和[4 6]
print(arr.sum(axis=1)) # 同上
3.4.3矩阵点乘
矩阵点乘:对于得到的数组来说,其元素为第一数组同一行上每一元素与第二数组同一列上每一元素相乘之后再求和所得,第一数组与第二数组互相操作的行与列交叉点就是所得元素
这里说的是线性代数里的矩阵点乘
普通元素间乘法使用np.multiply(arr1,arr2)
`或直接
`arr1*arr2
点乘则使用
**np.dot(arr1,arr2)
`** 或 **
`arr1.dot(arr2)
import numpy
a = numpy.array([[1,2],
[3,4]])
b = numpy.array([[5,6],
[7,8]])
a*b
# array([[5, 12],
# [21, 32]])
a.dot(b)
# array([[19, 22],
# [43, 50]])
numpy.dot(a,b)
# array([[19, 22],
# [43, 50]])
numpy.dot(b,a)
# array([[23, 34],
# [31, 46]])
3.5其他操作
3.5.1np.where()获取元素位置
-
满足condition返回x,不满足返回ynp.where(condition, x, y)
arr1 = np.array([1, 2, 3, 7, 8, 9]) arr2 = np.array([7, 8, 9, 1, 2, 3]) arr = np.where(arr1
-
返回满足condition的值的索引np.where(condition)
arr1 = np.array([1, 2, 3, 7, 8, 9]) arr = np.where(arr1<5) print(arr) # (array([0, 1, 2], dtype=int64),)
3.5.2np.power()次方运算 和np.sqrt()开方运算
-
次方运算
:对数组NP中每个元素进行n次方运算np.power(NP, n)
:对整数n分别以数组NP中元素为指数进行次方运算,返回数组np.power(n, NP)
:数组NP1和数组NP2中元素对应进行次方运算,以NP2中元素为指数np.power(NP1, NP2)
-
开方运算
,使用方法同上np.sqrt()
3.5.3NumPy的arg运算
用于得到特殊值的索引
np.argmin(NP)
**、**
np.argmax(NP)
**、**
np.argsort(NP)
特别地,
将矩阵排序后,返回排序后的索引np.argsort(NP)
NP = np.arange(10)
np.random.shuffle(NP)
print(NP) # [2 1 5 4 6 7 8 9 0 3]
print(np.argsort(NP)) # [8 1 0 9 3 2 4 5 6 7]
# 解释:排序后第一个元素是0,则0的下标为8
4.ufunc函数
numpy模块中对ndarray中数据进行快速元素级运算的函数,主
要包括一元函数和二元函数
一元函数
一元ufunc | 描述 | 调用方式 |
---|---|---|
abs , fabs |
计算整数、浮点数或者复数的绝对值。对于非复数,可以使用更快的 fabs 。 |
np.abs(arr) , np.fabs(arr) |
sqrt |
计算各个元素的平方根,相当于 arr ** 0.5 。要求 arr 的每个元素必须是非负数。 |
np.sqrt(arr) |
square |
计算各个元素的平方,相当于 arr ** 2 。 |
np.square(arr) |
exp |
计算各个元素的指数 e 的次方。 |
np.exp(arr) |
log , log10 , log2 , log1p |
分别计算自然对数、底数为 10 的对数、底数为 2 的对数,以及 log(1+x) ;要求 arr 中的每个元素必须为正数。 |
np.log(arr) ,np.log10(arr) , np.log2(arr) , np.log1p(arr) |
sign |
计算各个元素的正负号:1 表示正数,0 表示零,-1 表示负数。 | np.sign(arr) |
ceil |
计算各个元素的 ceiling 值,即不小于该值的最小整数。 | np.ceil(arr) |
floor |
计算各个元素的 floor 值,即不大于该值的最大整数。 | np.floor(arr) |
rint |
将各个元素值四舍五入到最接近的整数,保留 dtype 的类型。 |
np.rint(arr) |
modf |
将数组中元素的小数位和整数位以两部分独立数组的形式返回。 | np.modf(arr) |
isnan |
返回一个表示“那些值是 NaN(不是一个数字)”的布尔型数组。 | np.isnan(arr) |
isfinite , isinf |
分别表示“那些元素是有限的(非 inf、非 NaN)”或者“那些元素是无穷的”的布尔型数组。 | np.isfinite(arr) ,np.isinf(arr) |
cos , cosh , sin , sinh , tan , tanh |
普通以及双曲型三角函数。 | np.cos(arr) ,np.sin(arr) ,np.tan(arr) |
arccos , arccosh , arcsin , arcsinh , arctan , arctanh |
反三角函数。 | np.arccos(arr) ,np.arcsin(arr) ,np.arctan(arr) |
二元函数
二元ufunc | 描述 | 调用方式 |
---|---|---|
mod |
元素级的取模。 | np.mod(arr1, arr2) |
dot |
求两个数组的点积。 | np.dot(arr1, arr2) |
greater , greater_equal , less , less_equal , equal , not_equal |
执行元素级别的比较运算,最终返回一个布尔型数组。 | np.greater(arr1,arr2) np.less(arr1,arr2) np.equal(arr1,arr2) |
logical_and , logical_or , logical_xor |
执行元素级别的布尔逻辑运算,相当于中缀运算符 & ,| ,^ | np.logical_and(arr1,arr2),<br/> np.logical_or(arr1,arr2),<br/> np.logical_xor(arr1,arr2)` |
|
power |
求解数组中的每个元素进行给定次方的指数值。类似于:arr ** 3 。 |
np.power(arr, 3) |
当操作不同类型的数组时,最终的结果数组的类型取决于精度最宽的数组的类型。(即向上造型)