数据分析之Numpy库

1 Numpy简介

Numpy(Numerical Python)是一个开源的高性能的科学计算和数据分析库,用于快速处理任意维度的数组。并且,Numpy支持常见的数组和矩阵操作。Numpy使用ndarray对象来处理多为数组,ndarray对象是一个快速灵活的大数据容器。

2 ndarray简介

Python中有列表,可当数组使用。Python中也有array模块,但是不支持多维数组。并且列表和array模块都没有科学运算函数。所以,Python不适合做矩阵等科学计算。Numpy没有使用Python本身的数组机制,而是提供了ndarray这个n维数组类型对象,ndarray不仅能够很方便地对数组进行存取,而且拥有丰富的科学计算函数,如向量的加法、减法、乘法等。下面通过实例演示创建一个ndarray多维数组:

# 导入numpy函数库并指定库的别名
import numpy as np
# 创建一维数组
array1 = np.array([1, 2, 3, 4])
# 创建二维数组
array2 = np.array([[1, 2, 3, 4],[5, 6, 7, 8]])
# 创建三维数组
array3 = np.array([[[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]],[[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]])
array1:array([1, 2, 3, 4])
array2:array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
array3:array([[[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]],

       [[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]]])
3 ndarray与list执行效率的对比

使用Python的list可以作为一维数组,通过列表的嵌套可以实现多维数组。那为什么还要使用Numpy的ndarray,其实使用ndarray处理数组,其效率要比list要高很多,下面通过例子来比较下两者的执行效率:

import random
import numpy as np
# 定义一个空列表用于存放(数组)元素
lst = []
# 向lst中添加一千万个元素
for i in range(10000000):
    lst.append(random.random())
%time sum01 = sum(lst) # 使用Python中的sum函数对数组元素进行求和;%time是魔法方法,可以查看当前行代码运行一次需要花费的时间。
lst2 = np.array(lst) # 将lst的存储方式转换成ndarray中的存储方式
%time sum02 = np.sum(lst2) # 使用ndarray中的sum对同样的数组进行求和
第一次运行上面的代码:
CPU times: user 40.8 ms, sys: 70 µs, total: 40.8 ms
Wall time: 40.9 ms
CPU times: user 4.07 ms, sys: 0 ns, total: 4.07 ms
Wall time: 3.87 ms

第一次运行上面的代码:
CPU times: user 41.1 ms, sys: 0 ns, total: 41.1 ms
Wall time: 41.1 ms
CPU times: user 3.86 ms, sys: 0 ns, total: 3.86 ms
Wall time: 3.87 ms

第三次运行上面的代码:
CPU times: user 40.8 ms, sys: 87 µs, total: 40.9 ms
Wall time: 40.9 ms
CPU times: user 4.23 ms, sys: 31 µs, total: 4.26 ms
Wall time: 4.07 ms

很明显使用numpy的ndarray对数组求和的效率要比原生Python的sum函数求和高10倍以上。机器学习最大的特点是需要对大量的数据做运算,如果没有一个快速的解决方案,那么可能Python在机器学习领域就达不到很好的效果。Numpy专门对ndarray的操作和运算进行设计,所以,数组的存储效率和输入输出性能远优于Python中的嵌套列表。数组越大,Numpy的优势就越明显。

4 ndarray的优势
  • 内存块风格:ndarray在存储数据的时候是直接存储,Python的list中的数据不是直接存储,需要先找寻一个地址,然后通过地址找到需要的内容。ndarray中的所有元素的类型都是相同的,所以ndarray在存储元素时,内存是可以连续的。而Python中list中的元素是任意的,所以只能通过寻址的方式找到下一个元素。ndarray在通用性上要输于list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python的list要简洁。
  • ndarray支持并行化运算(向量化运算):Numpy内置并行运算功能,当系统有多个核心时,做运算会自动做并行运算。
  • 效率远高于纯Python代码,Numpy底层使用C语言编写,内部解除GIL(全局解释器锁),其对数组的操作速度不受Python GIL的影响。
5 ndarray数组的属性

数组的维度:

# 导入numpy模块并为模块设置别名
import numpy as np
# 创建一个维度是3行4列的ndarray数组
array01 = np.array([
    [80, 78, 98, 88],
    [89, 87, 89, 78],
    [78, 84, 89, 87]
])
array01.shape
Out[](3, 4)

数组的维数:

# 导入numpy模块并为模块设置别名
import numpy as np
# 创建一个维度是3行4列的ndarray数组
array01 = np.array([
    [80, 78, 98, 88],
    [89, 87, 89, 78],
    [78, 84, 89, 87]
])
array01.ndim
Out[]2

数组中的元素数量:

# 导入numpy模块并为模块设置别名
import numpy as np
# 创建一个维度是3行4列的ndarray数组
array01 = np.array([
    [80, 78, 98, 88],
    [89, 87, 89, 78],
    [78, 84, 89, 87]
])
array01.size
Out[]12

一个数组元素的长度(字节):

# 导入numpy模块并为模块设置别名
import numpy as np
# 创建一个维度是3行4列的ndarray数组
array01 = np.array([
    [80, 78, 98, 88],
    [89, 87, 89, 78],
    [78, 84, 89, 87]
])
array01.itemsize
Out[]8

数组元素的类型:

# 导入numpy模块并为模块设置别名
import numpy as np
# 创建一个维度是3行4列的ndarray数组
array01 = np.array([
    [80, 78, 98, 88],
    [89, 87, 89, 78],
    [78, 84, 89, 87]
])
array01.dtype
Out[]:dtype('int64')
6 ndarray数组的形状

一维数组:

import numpy as np
a = np.array([1, 2, 3, 4, 5])
print(a)
print(a.shape)
[1 2 3 4 5]
(5,) # 表示一维数组,5:数组中有5个元素

二维数组:

import numpy as np
b = np.array([
    [1, 2, 3, 4, 5],
    [4, 5, 6, 7, 8]
])
print(b)
print(b.shape)
[[1 2 3 4 5]
 [4 5 6 7 8]]
(2, 5) # 有两个元素,表示的是二维数组。2:二维数组中有两个一维数组;5:一维数组中有5个元素

三维数组(三维数组是二维数组的叠加):

import numpy as np
c = np.array([
    [[1, 2, 3, 4, 5],
    [4, 5, 6, 7, 8]],
    [[9, 10, 11, 12, 13],
    [14, 15, 16, 17, 18]]
])
print(c)
print(c.shape)
[[[ 1  2  3  4  5]
  [ 4  5  6  7  8]]
 [[ 9 10 11 12 13]
  [14 15 16 17 18]]]
(2, 2, 5) # 第一个2:有2个二维数组;第二个2:二维数组中有2个一维数组;3:在一维数组中有3个元素
7 ndarray数组的类型

不指定数组类型(整型):

import numpy as np
a = np.array([
    [[1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,17]],
    [[1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,12]]
])
a.dtype
dtype('int64')

不指定数组类型(小数):

import numpy as np
a = np.array([
    [[1.1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,17]],
    [[1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,12]]
])
a.dtype
dtype('float64')

如果不指定,整型默认是int64,小数默认是float64。如果指定数组类型:

指定数组类型,将整型指定为float64类型:

import numpy as np
a = np.array([
    [[1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,17]],
    [[1, 2, 3, 4, 5, 6],
    [7, 8, 9, 10, 11,12],
    [12, 13, 14, 15, 16,12]]
], dtype=np.float64)
print(a)
a.dtype
[[[ 1.  2.  3.  4.  5.  6.]
  [ 7.  8.  9. 10. 11. 12.]
  [12. 13. 14. 15. 16. 17.]]

 [[ 1.  2.  3.  4.  5.  6.]
  [ 7.  8.  9. 10. 11. 12.]
  [12. 13. 14. 15. 16. 12.]]]
dtype('float64')

不指定数组类型(字符串):

import numpy as np
a = np.array(['I', 'Like' ,'qianqian'])
a
array(['I', 'Like', 'qianqian'], dtype='<U8')

指定数组类型(字符串):

import numpy as np
a = np.array(['I', 'Like' ,'qianqian'], dtype=np.string_)
a
array([b'I', b'Like', b'qianqian'], dtype='|S8') # S:String;8:数组中最长字符串是8个字母
8 ndarray数组的生成

从已存在的数组中生成数组的两种方法,numpy.arraynumpy.asarray方法,下面通过一个小案例来区别这两种方法:

首先创建一个数组作为已存在数组:

import numpy as np
a = np.array([[1, 2, 3, 4, 5, 6],[7,8,9,10,11,112]])
a
array([[  1,   2,   3,   4,   5,   6],
       [  7,   8,   9,  10,  11, 112]])

使用array在原有数组的基础上生成数组(深度拷贝):

a1 = np.array(a) # 深拷贝
a1[0, 0] = 0
a
array([[  1,   2,   3,   4,   5,   6],
       [  7,   8,   9,  10,  11, 112]])

使用asarray在原有数组的基础上生成数组:(浅拷贝)

a2 = np.asanyarray(a) # 浅拷贝
a2[0, 0] = 0
a
array([[  0,   2,   3,   4,   5,   6],
       [  7,   8,   9,  10,  11, 112]])

生成固定范围的数组:

创建等差数列的数组,指定数量,使用的函数是:linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,axis=0)

import numpy as np
arr = np.linspace(0,21,6) # start:0,序列的起始值; stop:20,序列的终止值; num:5, 要生成的等间隔样例数量, 默认是50。endpoint:序列中是否是否包含stop值,默认是True
arr
array([ 0. ,  4.2,  8.4, 12.6, 16.8, 21. ])

创建等差数列的数组,指定步长,使用的函数:arange(start=None, *args, **kwargs)

import numpy as np
arr = np.arange(0, 20, 2, dtype=np.int64) # step:2,步长;dtype:数据类型
arr
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

创建等比数列,使用的函数:logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,axis=0)

import numpy as np
# 注意这里是生成10的多少次方
arr = np.logspace(0, 2, 3) # num是要生成等比数列的数量;0、2的意思分别是10的0次方~10的2次方;3:生成3个数
arr
array([  1.,  10., 100.])

创建随机数组(正太分布方式),使用np.random模块创建正太分布有三种方式,分别是:randn(*dn),normal(loc=0.0, scale=1.0, size=None),standard_normal(size=None)。

  • randn:从标准动态分布中返回一个或多个样本值。
  • normal:返回指定形状的标准正太分布数组。loc:此动态分布的均值(对应着整个分布的中心);scale:概率分布的标准差,值越大越矮胖,反之越瘦高。size:输出的是shape,默认是None,只输出一个值。
  • standard_normal:返回指定形状的标准正太分布的数组

生成均值为1.75,标准差为1的100000000个正态分布数据。使用到的函数:normal(loc=0.0, scale=1.0, size=None)

# 导入相关模块
import numpy as np
import matplotlib.pyplot as plt
# 数据的准备
x = np.random.normal(1.75, 1, 100000000) # array是一维数组,也就是一个列表
# 创建画布
plt.figure(figsize=(8,4), dpi=100)
# 绘制图像(绘制直方图)
plt.hist(x, 1000) # 1000:1000组数据
# 显示图像
plt.show()

在这里插入图片描述
模拟生成一组股票的涨跌幅数据:随机生成4支股票1周的交易日涨幅数据(随机生成涨跌幅在某个正太分布内,如均值是0,方差是1):

import numpy as np
arr = np.random.normal(0, 1, (4,5))
arr
array([[ 1.39648189,  0.17949331, -0.0393186 ,  1.54571909, -0.89729191],
       [-1.30231063, -0.21940802,  0.43169118, -0.68724142, -1.11523206],
       [-1.93539031, -2.21212029, -1.39101401, -2.27047266, -0.1254774 ],
       [ 1.67693295, -2.22111556,  1.5863305 ,  0.69848128,  2.25766984]])

创建随机数组(均匀分布方式),使用np.random模块创建正太分布有三种方式,分别是:rand(*dn),uniform(low=0.0, high=1.0, size=None),randint(low, high=None, size=None, dtype=‘l’)

  • rand:返回[0.0,1.0)内的一组均匀分布的数。
  • uniform:从一个均匀分布[low=0.0, hegh=1.0, size=None)中随机采样,low是采用下界,float类型,默认是0;high是采样下界,float类型,默认值是1。size是输出样本的数目,int或元祖类型。如size=(m,n,k)则输出mnk个样本,缺省时输出1个值。返回值:ndarray类型,其形状和参数size中的描述一致。
  • randint:从一个均匀分布中随机采样,生成一个整数或N维整数数组。对于取数范围,如果high不是None时,取[low,high)之间的随机数,否则取值[low,high)之间随机整数。
# 导入模块
import numpy as np
# 准别数据,生成均匀分布的数据
x = np.random.uniform(-1, 1, 100000000)
# 创建画布
plt.figure(figsize=(8,4), dpi=100)
# 绘制图像(绘制直方图)
plt.hist(x, 1000) # 1000:1000组数据
# 显示图像
plt.show()

在这里插入图片描述

9 ndarray数组的索引和切片
  • 一维数组的索引和切片
import numpy as np
arr = np.array([1, 2, 3, 4])
print(arr)
arr[0]
[1 2 3 4]
1
  • 二维数组的索引和切片
import numpy as np
arr2 = np.array([[1, 2, 3, 4],[5, 6, 7, 8]])
print(arr2)
arr2[1,1]
[[1 2 3 4]
 [5 6 7 8]]
6
  • 三维数组的索引和切片
import numpy as np
arr3 = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 21, 22, 23]]])
print(arr3)
arr3[1, 1, 1]
[[[ 1  2  3  4]
  [ 5  6  7  8]
  [ 9 10 11 12]]

 [[13 14 15 16]
  [17 18 19 20]
  [21 21 22 23]]]
18
10 ndarray数组形状的修改
  • reshape(self, shape, order='C ')函数的应用
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
# 打印这个数组的形状
print(arr.shape)
# 修改数组的形状
arr2 = arr.reshape([6, 3])
# 打印改变后数组的形状
print(arr2.shape)
arr2
(3, 6)
(6, 3)
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12],
       [13, 14, 15],
       [16, 17, 18]])

当不知到有多少列的时候:

import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
# 打印这个数组的形状
print(arr.shape)
# 修改数组的形状
arr2 = arr.reshape([6, -1])
# 打印这个数组的形状
print(arr2.shape)
arr2
(3, 6)
(6, 3)
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12],
       [13, 14, 15],
       [16, 17, 18]])

当不知道有多少行的时候:

import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
# 打印这个数组的形状
print(arr.shape)
# 修改数组的形状
arr2 = arr.reshape([-1, 2])
# 打印这个数组的形状
print(arr2.shape)
arr2
(3, 6)
(9, 2)
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [ 7,  8],
       [ 9, 10],
       [11, 12],
       [13, 14],
       [15, 16],
       [17, 18]])
  • resize(self, new_shape, refcheck=True)函数的应用,要区别与reshape方法,其返回结果并不是新的数组,而是把原来的数组给修改了
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
# 打印这个数组的形状
print(arr.shape)
# 修改数组的形状
arr.resize([2,8])
# 打印这个数组的形状
print(arr.shape)
arr
(3, 6)
(2, 8)
array([[ 1,  2,  3,  4,  5,  6,  7,  8],
       [ 9, 10, 11, 12, 13, 14, 15, 16]])
  • 数组的转置,将数组的行列进行互换,使用数组名.T
# 数组的转置
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
arr.T
array([[ 1,  7, 13],
       [ 2,  8, 14],
       [ 3,  9, 15],
       [ 4, 10, 16],
       [ 5, 11, 17],
       [ 6, 12, 18]])
11 ndarray数组类型的修改
  • ndarray.astype(type):返回修改类型之后的数组
# 返回修改了类型之后的数组
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
print(arr.dtype)
arr2 = arr.astype(np.float)
arr2
int64
array([[ 1.,  2.,  3.,  4.,  5.,  6.],
       [ 7.,  8.,  9., 10., 11., 12.],
       [13., 14., 15., 16., 17., 18.]])
  • ndarray.tostring([order])或者ndarray.tobytes([order]):构造包含数组原始数据字节的Python字节
# 构造包含数组原始数据字节的Python字节1
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
str_arr = arr.tostring()
str_arr
b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00'
# 构造包含数组原始数据字节的Python字节2
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]])
str_arr = arr.tobytes()
str_arr
b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00'
12 ndarray数组的去重

数组去重的方法是unique(ar, return_index=False, return_inverse=False,return_counts=False, axis=None):

# 返回修改了类型之后的数组
import numpy as np
arr = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 2, 10, 5, 6], [13, 14, 15, 16, 17, 18]])
arr2 = np.unique(arr)
arr2
array([ 1,  2,  3,  4,  5,  6,  7,  8, 10, 13, 14, 15, 16, 17, 18])
13 ndarray的运算
  • 逻辑运算
# 生成10名同学5门课程的分数
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
# 取出最后4名同学的成绩,用于逻辑判断
ret1 = scores[6:, 0:5] # 或者scores[6:, 0:5] 
# 逻辑判断,如果成绩不小于60分,标记为True,否则为False
ret2 = ret1 > 60 # 返回的结果是标记后的
'''
array([[False,  True,  True,  True,  True],
       [ True,  True,  True,  True, False],
       [ True,  True, False,  True,  True],
       [ True,  True, False,  True,  True]])
'''
ret1[ret1 > 60] = 1
ret1
'''
array([[54, 51, 59,  1,  1],
       [ 1,  1,  1,  1,  1],
       [ 1,  1, 60,  1,  1],
       [57,  1,  1,  1,  1]])
'''
  • 通用判断函数

numpy.all方法:

'''
numpy.all方法是:只要有一个不满足条件,就返回False;所有都满足条件,返回True
判断前两名同学的成绩是否都及格
'''
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores[0:2, :])
ret = np.all(scores[0:2, :] > 90)
ret
[[77 81 89 51 66]
 [78 64 53 53 70]]
False

numpy.any方法:

'''
numpy.any方法是:只要有一个满足条件,就返回True;所有都不满足条件返回False
判断前两名同学的成绩是否有不小于90分的
'''
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores[0:2, :])
ret = np.any(scores[0:2, :] > 90)
ret
[[82 97 82 79 53]
 [54 81 91 67 64]]
True
  • 三元运算符

通过使用numpy.where能够进行更加复杂的运算:

# 将前四名学生的前四门课程中成绩中大于60的置为1,否则置为0
import numpy as np
scores = np.random.randint(50, 100, (10, 5))[:4, :4]
print(scores)
np.where(scores > 60, 1, 0)
[[76 84 84 52]
 [52 85 50 90]
 [57 71 93 92]
 [90 72 66 67]]
array([[1, 1, 1, 0],
       [0, 1, 0, 1],
       [0, 1, 1, 1],
       [1, 1, 1, 1]])

复合逻辑需要结合np.logical_and和np.logical_or使用:

# 将前四名学生前四门课程中成绩大于60且小于90的置为1,否知置为0
import numpy as np
scores = np.random.randint(50, 100, (10, 5))[:4, :4]
print(scores)
np.where(np.logical_and(scores > 60, scores < 90), 1, 0)
[[61 99 91 92]
 [78 80 78 56]
 [63 88 80 59]
 [84 79 65 86]]
array([[1, 0, 0, 0],
       [1, 1, 1, 0],
       [1, 1, 1, 0],
       [1, 1, 1, 1]])
# 将前四名学生前四门课程中成绩大于90或小于60的置为1,否知置为0
import numpy as np
scores = np.random.randint(50, 100, (10, 5))[:4, :4]
print(scores)
np.where(np.logical_or(scores > 90, scores < 60), 1, 0)
[[76 63 99 78]
 [84 85 74 56]
 [72 72 92 61]
 [56 54 89 60]]
array([[0, 0, 1, 0],
       [0, 0, 0, 1],
       [0, 0, 1, 0],
       [1, 1, 0, 0]])
14 ndrray统计运算相关的函数

max(a, axis)函数的使用:

# 取最大值
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.max(scores)
[[82 51 86 57 79]
 [90 87 50 97 90]
 [81 93 72 69 90]
 [86 50 83 65 83]
 [68 66 78 59 65]
 [71 64 56 50 72]
 [79 69 91 97 76]
 [68 67 64 83 54]
 [66 63 60 58 53]
 [87 64 63 55 60]]
97

min(a, axis)函数的使用:

# 取最小值
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.min(scores)
[[83 81 55 73 93]
 [57 61 51 60 91]
 [66 77 83 95 56]
 [75 76 58 59 96]
 [90 72 72 53 84]
 [83 67 93 82 57]
 [50 91 51 98 62]
 [83 53 91 78 91]
 [99 77 93 81 99]
 [89 71 73 81 87]]
50

mean(a, axis, dtype)函数的使用:

# 取平均值
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.mean(scores)
[[50 90 77 76 78]
 [92 84 76 59 58]
 [77 69 66 73 68]
 [69 57 64 94 75]
 [82 52 97 93 57]
 [73 53 88 64 60]
 [84 98 64 65 88]
 [72 54 67 61 57]
 [99 83 73 80 64]
 [70 63 65 94 58]]
72.6

也可以按照行和列求解最大值、最小值、平均值等,下面以求解最大值、最小值为例子:

# 按照列求最大值
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.max(scores, axis=0)  # axis=0表示按照列来求解
[[57 66 72 90 69]
 [85 90 98 95 71]
 [97 75 83 57 55]
 [81 77 95 92 61]
 [79 68 79 54 66]
 [50 52 95 52 96]
 [55 64 86 54 73]
 [63 67 78 56 84]
 [54 76 92 88 89]
 [52 79 75 91 62]]
array([97, 90, 98, 95, 96])
# 按照行求最大值
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.max(scores, axis=1)  # axis=1表示按照行来求解
[[54 77 71 85 54]
 [65 89 95 69 75]
 [56 95 54 75 63]
 [62 84 58 94 89]
 [66 51 55 91 85]
 [70 97 75 70 84]
 [94 80 83 59 90]
 [76 70 55 99 74]
 [79 60 81 99 57]
 [96 82 50 57 80]]
array([85, 95, 95, 94, 91, 97, 94, 99, 99, 96])

argmax(a, axis)方法的使用:

# 最大值的下标
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.argmax(scores)
[[67 73 95 94 92]
 [52 91 74 96 76]
 [82 70 61 86 81]
 [90 69 57 86 66]
 [50 53 85 69 65]
 [84 69 81 61 52]
 [69 61 65 91 70]
 [87 50 68 78 83]
 [72 93 62 79 89]
 [99 75 77 53 87]]
45
# 按列求最大值的下标
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.argmax(scores, axis=0)
[[85 68 60 71 62]
 [65 71 86 60 84]
 [57 81 76 58 95]
 [57 83 66 73 55]
 [88 77 54 81 68]
 [78 53 54 99 54]
 [99 86 63 56 97]
 [92 96 52 83 57]
 [85 83 65 55 76]
 [79 77 67 63 69]]
array([6, 7, 1, 5, 6])
# 按行求最大值的下标
import numpy as np
scores = np.random.randint(50, 100, (10, 5))
print(scores)
np.argmax(scores, axis=1)
[[78 53 79 82 60]
 [61 92 72 56 61]
 [71 64 80 81 81]
 [95 55 81 85 74]
 [63 82 65 89 91]
 [94 62 52 61 93]
 [91 69 98 54 63]
 [76 53 93 86 83]
 [97 98 92 52 95]
 [70 60 75 83 74]]
array([3, 1, 3, 0, 4, 0, 2, 2, 1, 3])

argmin(a, axis)的使用同argmax(a, axis)的相似,统计运算中还可以求中位数[median(a, axis)]、平均值、标准差[std(a, axis, dtype)]和方差[var(a, axis, dtype)]等。

15 数组间的运算

数组与数之间的运算:

执行程序1:

import numpy as np
arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
arr + 3 # 所有元素加3

打印结果:

array([[ 4,  5,  6,  7,  8],
       [ 9, 10, 11, 12, 13]])

执行程序2:

import numpy as np
arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
arr / 2 # 所有元素除以2

打印结果:

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

执行程序3:

import numpy as np
arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
arr * 3 # 所有元素乘3

打印结果:

array([[ 3,  6,  9, 12, 15],
       [18, 21, 24, 27, 30]])

注意:如果是列表*3,则只会分别粘贴复制3次列表中的元素,组成新的列表

数组与数组的运算:(不同形状的数组是不可以在一起运算的)

测试程序:

import numpy as np
arr1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
arr2 = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
arr1 + arr2

测试结果:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-44-18acd144a7ff> in <module>
      2 arr1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
      3 arr2 = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
----> 4 arr1 + arr2

ValueError: operands could not be broadcast together with shapes (2,4) (2,5) 

广播机制:数组在进行矢量运算时,要求数组的形状是相等的。当形状不相等的数组执行算术运算时,就会出现广播机制,该机制会对数组进行扩展,使数组的形状属性值一样。这样,就可以进行矢量化运算。广播机制实现了两个或两个以上数组的运算,即使这些数组的shape不是完全相同的,只要满足一个条件即可:

  • 数组的某一维度等长
  • 其中一个数组的某一个维度是1

执行程序:

import numpy as np
arr1 = np.array([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]])
arr2 = np.array([[1], [2]])
print('arr1的形状是:',arr1.shape)
print('arr2的形状是:',arr2.shape)
arr1 + arr2

执行结果:

arr1的形状是: (2, 6)
arr2的形状是: (2, 1)
array([[ 2,  3,  4,  5,  6,  7],
       [ 9, 10, 11, 12, 13, 14]])

广播机制需要扩展维度小的数组,使得它与维度大的数组的shape值相同,以便使用元素级函数或者运算符进行运算。

16 矩阵与向量相关

矩阵和数组的区别是矩阵必须是二维的,而数组可以是多维的。矩阵和向量的区别是向量是特殊的矩阵。
矩阵的加法:行和列相等可以进行加法,对应元素进行加和。
标量乘法:矩阵中的每个元素都要一一和标量进行相乘。
矩阵和向量乘法:m * n阶的矩阵和n * 1阶的向量进行相乘,得到m * 1阶的向量
矩阵乘法:m * n矩阵乘以n * o,得到m*n阶矩阵
矩阵乘法的性质:

  • 矩阵乘法不满足交换律:AxB不等于BxA
  • 矩阵乘法满足结合律:(AxB)xC=Ax(BxC)
  • 单位矩阵:主对角线上的元素都是1,其它元素都是0,这种矩阵是单位矩阵

矩阵的逆:如矩阵是一个m*m矩阵(方阵),如果有逆矩阵,则AA-1=A-1A。低阶矩阵球逆的方法是待定系数法和初等变换
矩阵的转置:矩阵的行转置后变成矩阵的列,矩阵的列变成矩阵的行。
矩阵的运算:矩阵的运算可以使用在大学求最终成绩上,很多位学生(决定矩阵的行数)的平时成绩和期末成绩组成n行2列的矩阵,再乘以0.7和0.3组成的2行1列的矩阵,得到n行1列的矩阵就是每位学生的最终成绩。在numpy库中矩阵乘法使用到matmul和dot函数:两者相同点是都可以做矩阵之间的乘法,不同点是matmul不支持矩阵与标量的乘法,而dot支持

测试两者都可以做矩阵之间的乘法

# 测试dot和matmul函数都可以做矩阵之间的乘法
import numpy as np
a = np.array([[89, 90], [88, 89], [87, 78]])
b = np.array([0.7, 0.3])
arr1 = np.matmul(a, b)
print(arr1)
arr2 = np.dot(a, b)
print(arr2)

测试结果:

[89.3 88.3 84.3]
[89.3 88.3 84.3]

测试只有dot函数支持矩阵与标量的乘法:

# 测试只有dot函数支持矩阵与标量的乘法
import numpy as np
a = np.array([[89, 90], [88, 89], [87, 78]])
arr1= np.dot(2,a)
print(arr1)
arr2= np.matmul(2, a)
[[178 180]
 [176 178]
 [174 156]]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-59-653e8ec1b561> in <module>
      4 arr1= np.dot(2,a)
      5 print(arr1)
----> 6 arr2= np.matmul(2, a)

ValueError: matmul: Input operand 0 does not have enough dimensions (has 0, gufunc core with signature (n?,k),(k,m?)->(n?,m?) requires 1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章