Python系列 之 NumPy库

Python NumPy库学习

  • NumPy库
    • ndarray对象
      • 创建ndarray对象
      • ndarray对象的重要属性
    • 基本操作
    • 通函数 ufunc
    • 索引 切片和迭代
      • 一维数组的索引切片和迭代
      • 多维数组的索引切片和迭代
    • 形状操作
      • 改变数组形状
      • 数组连接 堆叠
      • 数组拆分
    • 副本和视图
      • 完全不复制
      • 视图
      • 副本

NumPy库

NumPy 是一个运行速度非常快的数学库,主要用于数组计算;
NumPy库不在Python的标准模块中,需要先下载NumPy库;
可以使用pip工具下载:

pip install numpy

引用NumPy库:

import numpy as np

可以通过 numpy._version_ 查看 numpy 的版本:

# 查看Numpy的版本
print("Numpy版本:", np.__version__)
# 输出:
# Numpy版本: 1.20.1

ndarray对象

Numpy包的核心对象是 ndarray;它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray 对象是用于存放同类型元素的多维数组,每个元素在内存中都有相同存储大小的区域。

创建ndarray对象

通过array函数创建 np.array(list|tuple|其他类似的数组对象)

# 参数 ndmin 可以指定数组的维度;
# 参数 dtype 可以指定数组元素的数据类型
arr = np.array((0, 1, 2), ndmin=3, dtype=float)
print("arr的元素:\n", arr)
# 输出:
# arr的元素:
#  [[[0. 1. 2.]]]

np.random.random()方法 创建ndarray对象

# np.random.random()方法 创建ndarray对象
arr_random = np.random.random((2, 2))
print("arr_random的元素:\n", arr_random)
# 输出:
# arr_random的元素:
#  [[0.98249212 0.38319581]
#  [0.0135647  0.36293739]]

np.arange()方法:

# np.arange([start, ]stop, [step, ]dtype=None) 函数 
# 类似range函数 只是不返回列表而是ndarray数组对象 dtype定义元素的数据类型
# 例如:从10-50(不含50)之间每隔10个数字选取一个数字作为数组元素,元素类型设置为float
arr_arange = np.arange(10, 50, 10, dtype=float)
print("arr_arange的元素:\n", arr_arange)
# 输出:
# arr_arange的元素:
#  [10. 20. 30. 40.]

np.linspace()方法:

# np.linspace(start, stop, num=50) 函数 
# 选取start和stop之间等差的num个元素
# 例如:选取1-5之间6个等差的数值作为数组的元素
arr_linspace = np.linspace(1, 5, 6)
print("arr_linspace的元素:\n", arr_linspace)
# 输出:
# arr_linspace的元素:
#  [1.  1.8 2.6 3.4 4.2 5. ]

很多时候数组的元素是未知的,但是数组的维度大小可能是已经确定的;可以通过zeros,ones,empty函数快速创建固定结构的数组

np.zeros方法

# np.zeros(shape: _ShapeLike) 函数 创建的数组 
# 元素默认值是 0 元素数据类型 float
# 创建和arr结构一样的元素为0的数组
# arr_zero = np.zeros(arr.shape)
arr_zero = np.zeros((1, 1, 3))
print("arr_zero的元素:\n", arr_zero)
# 输出:
# arr_zero的元素:
#  [[[0. 0. 0.]]]

np.ones方法

# np.ones(shape: _ShapeLike)  函数 创建的数组 
# 元素默认值是 1  元素数据类型 float
# arr_one = np.ones(arr.shape)
arr_one = np.ones((1, 1, 3))
print("arr_one的元素:\n", arr_one)
# 输出:
# arr_one的元素:
#  [[[1. 1. 1.]]]

np.empty方法

# np.empty(shape: _ShapeLike) 函数 创建的数组 
# 元素默认值是随机的,取决于内存状态 元素数据类型 float
# arr_empty = np.empty(arr.shape)
arr_empty = np.empty((1, 1, 3))
print("arr_empty的元素:\n", arr_empty)
# 输出:
# arr_empty的元素:
#  [[[1. 1. 1.]]]

ndarray对象的重要属性

ndim 轴:rank
ndarray.ndim 数组的轴(维度)的个数:rank
轴的概念:
[0,1,2] 该数组有一个轴,轴拥有 3 个元素
[[0,1,2],[1,2,3]]该数组有 2 个轴,第1轴长度为 2,第2轴长度为 3

arr1 = np.array(range(5))
arr2 = np.array([range(10)])
arr3 = np.array([[range(15)]])
arr4 = np.array(range(20), ndmin=4)
print("arr1轴(维度)的个数:", arr1.ndim,
      "\narr2轴(维度)的个数:", arr2.ndim,
      "\narr3轴(维度)的个数:", arr3.ndim,
      "\narr4轴(维度)的个数:", arr4.ndim)
# 输出:
# arr1轴(维度)的个数: 1 
# arr2轴(维度)的个数: 2 
# arr3轴(维度)的个数: 3 
# arr4轴(维度)的个数: 4

shape 数组的维度:
ndarray.shape 一个tuple 表示每个维度数组的长度;tuple的每个元素对应表示每个轴的长度;tuple的长度就是数组的轴的个数;如果返回tuple(n,m) 表示该数组是个 n行 m列 的矩阵

print("arr1.shape:", arr1.shape,
      "\narr2.shape:", arr2.shape,
      "\narr3.shape:", arr3.shape,
      "\narr4.shape:", arr4.shape)
# 输出:
# arr1.shape: (5,) 
# arr2.shape: (1, 10) 
# arr3.shape: (1, 1, 15) 
# arr4.shape: (1, 1, 1, 20)

size 数组元素的总和:
ndarray.size 等于 ndarray.shape 返回 tuple 元素的乘积;

print("arr1.size:", arr1.size,
      "\narr2.size:", arr2.size,
      "\narr3.size:", arr3.size,
      "\narr4.size:", arr4.size)
# 输出:
# arr1.size: 5 
# arr2.size: 10 
# arr3.size: 15 
# arr4.size: 20

dtype 数组中元素类型的对象

arr5 = np.array(list("abc"))
arr6 = np.array(range(5))
print("arr5元素类型:", arr5.dtype.name,
      "\narr6元素类型:", arr6.dtype.name)
# 输出:
# arr5元素类型: str32 
# arr6元素类型: int32

itemsize 数组中每个元素的字节大小

print("arr5元素字节大小:", arr5.itemsize,
      "\narr6元素字节大小:", arr6.itemsize)
# 输出:
# arr5元素字节大小: 4 
# arr6元素字节大小: 4

data 包含实际数组元素的缓冲区:
由于一般通过数组的索引获取元素,所以通常不需要使用这个属性

基本操作

数组上的算术运算都是应用到每个元素
一般运算 加减乘除:
如果数组的shape不同会出现:ValueError

arr_a = np.arange(5)
arr_b = np.array([6, 7, 8, 9, 10])
# 一般运算 加减乘除
print("arr_a + arr_b =  ", arr_a + arr_b)
print("arr_a - arr_b =  ", arr_a - arr_b)
print("arr_a * arr_b =  ", arr_a * arr_b)
print("arr_a / arr_b =  ", arr_a / arr_b)
# 输出:
# arr_a + arr_b =   [ 6  8 10 12 14]
# arr_a - arr_b =   [-6 -6 -6 -6 -6]
# arr_a * arr_b =   [ 0  7 16 27 40]
# arr_a / arr_b =   [0.         0.14285714 0.25       0.33333333 0.4       ]

赋值:

# 赋值 利用+= *= 可以直接改变被操作的数组而不会生成新的数组
arr_a += 1
print("arr_a 元素 +1:", arr_a)
arr_b *= 2
print("arr_b 元素 *2 :", arr_b)
# 输出:
# arr_a 元素 +1: [1 2 3 4 5]
# arr_b 元素 *2 : [12 14 16 18 20]

通函数 ufunc

NumPy提供熟悉的数学函数,如:sin cos和exp等;在NumPy中称为:通函数;

max函数:

arr_a = np.array([[1, 2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
print("arr_a.max()元素最大值:", arr_a.max())

# 利用指定参数axis可以沿数组的指定轴进行操作
# axis=0 垂直方向,axis=1 水平方向
print("arr_a.max(axis=0)垂直方向最大值,返回结果元素数组:",
      arr_a.max(axis=0))
# 输出:
# arr_a.max()元素最大值: 10
# arr_a.max(axis=0)垂直方向最大值,返回结果元素数组: [ 6  7  8  9 10]

min函数:

arr_a = np.array([[1,2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
print("arr_a.min()元素最小值:", arr_a.min())
# axis=0 垂直方向,axis=1 水平方向
print("arr_a.min(axis=1)水平方向最小值,返回结果元素数组:",
      arr_a.min(axis=1))
# 输出:
# arr_a.min()元素最小值: 1
# arr_a.min(axis=1)水平方向最小值,返回结果元素数组: [1 6]

sum函数:

arr_a = np.array([[1,2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
print("arr_a.sum()元素求和:", arr_a.sum())
# 输出:
# arr_a.sum()元素求和: 55

cumsum累加函数:

arr_a = np.array([[1,2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
# 相当于 [1,1+2,1+2+3,1+2+3+4,...]
print("arr_a.cumsum()元素累加,返回累加结果元素的一维数组:",
      arr_a.cumsum())
# 输出:
# arr_a.cumsum()元素累加,返回累加结果元素的一维数组: [ 1  3  6 10 15 21 28 36 45 55]

sin 函数:

arr_a = np.array([[1,2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
print("np.sin(arr_a)获取数组元素sin值:\n", np.sin(arr_a))
# 输出:
# np.sin(arr_a)获取数组元素sin值:
#  [[ 0.84147098  0.90929743  0.14112001 -0.7568025  -0.95892427]
#  [-0.2794155   0.6569866   0.98935825  0.41211849 -0.54402111]]

where函数:

arr_a = np.array([[1,2, 3, 4, 5],
                  [6, 7, 8, 9, 10]])
# np.where(condition,[x,y,]/)
# 例如:arr_a中大于5的元素,将元素值减5,小于等于5的元素+5,返回ndarray数组
print("where函数:\n",
      np.where(arr_a > 5, arr_a - 5, arr_a + 5))   
# 输出:
# where函数:
#  [[ 6  7  8  9 10]
#  [ 1  2  3  4  5]]      

索引 切片和迭代

数组可以像Python中list一样进行索引 切片和迭代的操作;一维数组和多为数组略微不同

一维数组的索引切片和迭代

一维数组就可以像list一样进行索引,切片,迭代的操作

arr_b = np.arange(10)
print("一维数组索引访问 arr_b[5]:", arr_b[5])
print("一维数组切片访问 arr_b[-5:- 2]:", arr_b[-5:- 2])
for b in arr_b:
    print("迭代访问一维数组arr_b:", b)
# 输出:
# 一维数组索引访问 arr_b[5]: 5
# 一维数组切片访问 arr_b[-5:- 2]: [5 6 7]
# 迭代访问一维数组arr_b: 0
# 迭代访问一维数组arr_b: 1
#     ...
# 迭代访问一维数组arr_b: 8
# 迭代访问一维数组arr_b: 9

多维数组的索引切片和迭代

多维的数组可以对每个轴进行索引切片操作,每个轴之间用逗号隔开:

arr_a = np.array([[[1, 2, 3],
                   [4, 5, 6]],
                  [[7, 8, 9],
                   [10, 11, 12]]])
print("多维数组索引访问 arr_a[0, 0, 0]: ", arr_a[0, 0, 0])
# 输出:
# 多维数组索引访问 arr_a[0, 0, 0]:  1

print("多维数组切片访问 arr_a[0:1, 0:2, 0:2]:\n",
      arr_a[0:1, 0:2, 0:2])
# print("多维数组切片访问 arr_a[..., 0:2, 0:2]",
#       arr_a[..., 0:2, 0:2])
# print("多维数组切片访问 arr_a[:, :, :2]",
#       arr_a[:, :, :2])

# 输出:
# 多维数组切片访问 arr_a[0:1, 0:2, 0:2]:
#  [[[1 2]
#   [4 5]]]

如果提供的索引少于轴的数量,缺少的索引将会被认为成完整的切片 ;三个点 ()表示会补齐索引所有需要的冒号
例如:

arr_a[...] == arr_a[:, :, :]

迭代:

多维数组迭代是对第一轴进行迭代:
只是返回第一轴的元素

arr_a = np.array([[[1, 2, 3],
                   [4, 5, 6]],
                  [[7, 8, 9],
                   [10, 11, 12]]])
# 多维数组迭代是对第一轴进行迭代
print("迭代访问多维数组arr_a:")
for a in arr_a:
    print("\n", a)
# 输出:
# 迭代访问多维数组arr_a:

#  [[1 2 3]
#  [4 5 6]]

#  [[ 7  8  9]
#  [10 11 12]]

数组的flat属性是所有元素的迭代器;可以利用flat属性迭代多维数组中的所有元素:

arr_a = np.array([[[1, 2, 3],
                   [4, 5, 6]],
                  [[7, 8, 9],
                   [10, 11, 12]]])
# 数组的flat属性是所有元素的迭代器
print("数组的flat属性:", arr_a.flat)
print("利用数组的flat属性迭代多维数组所有元素:")
for a in arr_a.flat:
    print(a)
# 输出:
# 数组的flat属性: 
# 利用数组的flat属性迭代多维数组所有元素:
# 1
# 2
# 3
# ...
# 11
# 12

形状操作

每个数组的形状都是由数组的轴和轴的元素数量决定的,可以使用各种不同的方法对数组的形状进行更改;例如:ravel(),reshape(),T方法 以及 resize()方法。

改变数组形状

ravel(),reshape(),T方法 – 返回新数组 不会改变原始数组结构
resize()方法 – 会修改原始数组结构

定义一个数组,然后通过不同的方法对数组的形状进行更改:

arr_a = np.array([[1, 2, 3, 4],
                  [5, 6, 7, 8],
                  [9, 10, 11, 12]])

ravel()方法:

# ravel()方法 将数组所有元素变成一维数组
print("ravel()方法:\n", arr_a.ravel())
# 输出:
# ravel()方法:
#  [ 1  2  3  4  5  6  7  8  9 10 11 12]

reshape方法:

# reshape(shape: Sequence[int])方法 改变数组的shape值
print("reshape(4, 3)方法:\n", arr_a.reshape(4, 3))
# 输出:
# reshape(4, 3)方法:
#  [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

# 如果reshape()中的size设置为 -1 则会自动计算size的值
print("reshape(2,-1)方法:\n", arr_a.reshape(2, -1))
# 输出:
# reshape(2,-1)方法:
#  [[ 1  2  3  4  5  6]
#  [ 7  8  9 10 11 12]]

T方法 : 转置

# T方法 转置
print("T方法 转置:\n", arr_a.T)
# 输出:
# T方法 转置:
#  [[ 1  5  9]
#  [ 2  6 10]
#  [ 3  7 11]
#  [ 4  8 12]]

resize() 方法:

resize()方法 – 会修改原始数组结构

# resize() 方法
arr_a.resize(4, 3)
print("resize(4, 3)方法:\n", arr_a)
# 输出:
# resize(4, 3)方法:
#  [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

数组连接 堆叠

定义两个数组:

arr_a = np.array([[1, 2],
                  [3, 4]])
arr_b = np.array([[5, 6],
                  [7, 8]])

np.concatenate方法:

# np.concatenate((a1, a2, a3...), axis=0, out=None, dtype=None, casting="same_kind")
# 默认axis=0,垂直方向;axis=1 水平方向
arr_c = np.concatenate((arr_a, arr_b), axis=1)
print("np.concatenate方法:\n", arr_c)
# 输出:
# np.concatenate方法:
#  [[1 2 5 6]
#  [3 4 7 8]]

np.vstack方法:垂直堆叠

# np.vstack(tup: Sequence[ArrayLike])方法 垂直堆叠
arr_c = np.vstack((arr_a, arr_b))
print("np.vstack方法:\n", arr_c)
# 输出:
# np.vstack方法:
#  [[1 2]
#  [3 4]
#  [5 6]
#  [7 8]]

np.hstack方法:水平堆叠

# np.hstack(tup: Sequence[ArrayLike])方法 水平堆叠
arr_c = np.hstack((arr_a, arr_b))
print("np.hstack方法:\n", arr_c)
# 输出:
# np.hstack方法:
#  [[1 2 5 6]
#  [3 4 7 8]]

np.dstack方法:沿着深度(高度)堆叠

# np.dstack() 方法 沿着深度(高度)堆叠
arr_c = np.dstack((arr_a, arr_b))
print("np.dstack方法:\n", arr_c)
# 输出:
# np.dstack方法:
#  [[[1 5]
#   [2 6]]

#  [[3 7]
#   [4 8]]]

数组拆分

定义一个数组 准备进行拆分:

arr_a = np.array([[0, 1, 2, 3, 4, 5],
                  ['a', 'b', 'c', 'd', 'e', 'f']])

np.array_split方法:

# np.array_split(ary,indice_or_sections,axis=0)
# indice_or_sections 平均拆分的个数或者 数组 例如:[2,5] 左开右闭
# 拆分的axis=0垂直方向拆分 xis=1水平方向拆分

# xis=0垂直方向拆分
arr_b = np.array_split(arr_a, 2, axis=0)
print("np.array_split方法平均拆分数组:\n", arr_b)
# 输出: 垂直方向拆分成 2 个数组
# np.array_split方法平均拆分数组:
#  [array([['0', '1', '2', '3', '4', '5']], dtype='
#   array([['a', 'b', 'c', 'd', 'e', 'f']], dtype='
 
# axis=1水平方向拆分 
arr_c = np.array_split(arr_a, [2, 5], axis=1)
print("np.array_split方法按位置拆分数组:\n", arr_c)
# print(arr_a[:, 2:5])
# 输出:
# np.array_split方法按位置拆分数组:
#  [array([['0', '1'],
#          ['a', 'b']], dtype='
#   array([['2', '3', '4'],
#          ['c', 'd', 'e']], dtype='
#   array([['5'],
#          ['f']], dtype='

np.hsplit():水平方向拆分

arr_b = np.hsplit(arr_a, 2)
print("np.hsplit()水平方向拆分:\n", arr_b)
# 输出:
# np.hsplit()水平方向拆分:
#  [array([['0', '1', '2'],
#          ['a', 'b', 'c']], dtype='
#   array([['3', '4', '5'],
#          ['d', 'e', 'f']], dtype='

np.vsplit() :垂直方向拆分

# np.vsplit() 垂直方向拆分
arr_b = np.vsplit(arr_a, 2)
print("np.vsplit() 垂直方向拆分:\n", arr_b)
# 输出:
# np.vsplit() 垂直方向拆分:
#  [array([['0', '1', '2', '3', '4', '5']], dtype='
#   array([['a', 'b', 'c', 'd', 'e', 'f']], dtype='

np.dsplit():dsplit仅适用于3维或更高维的阵列

# np.dsplit() dsplit仅适用于3维或更高维的阵列
arr_a.shape = (1, 2, 6)
arr_b = np.dsplit(arr_a, 2)
print("np.dsplit()方法拆分",arr_b)
# 输出:
# np.dsplit()方法拆分:
#  [array([[['0', '1', '2'],
#         ['a', 'b', 'c']]], dtype='
#   array([[['3', '4', '5'],
#          ['d', 'e', 'f']]], dtype='

副本和视图

副本就是数据的完整拷贝,对副本的修改不会影响原始数据
视图是数据的一个别称,如果对视图进行修改,会影响原始数据

完全不复制

简单的分配不会复制数组对象或者数组数据
只是对其进行引用

arr_a = np.arange(5)
arr_b = arr_a
print("arr_a is arr_b:", arr_b is arr_a)
# 输出:
# arr_a is arr_b: True
print("id(arr_a) == id(arr_b):", id(arr_a) == id(arr_b))
# 输出:
# id(arr_a) == id(arr_b): True

# 如果改变arr_b arr_a也会改变
arr_b[:] = 0
print("arr_b元素重新赋值为0,打印arr_a:", arr_a)
# 输出:
# arr_b元素重新赋值为0,打印arr_a: [0 0 0 0 0]

视图

view方法创建视图:view方法创建一个查看相同数据的新数组对象

arr_a = np.arange(6)
arr_b = arr_a.view()
print("arr_a is arr_b:", arr_b is arr_a)
# 输出:
# arr_a is arr_b: False
print("id(arr_a) == id(arr_b):", id(arr_a) == id(arr_b))
# 输出:
# id(arr_a) == id(arr_b): False

# 如果改变arr_b的数据 arr_a也会改变
arr_b[:] = 0
print("arr_b元素重新赋值为0,打印arr_a:", arr_a)
# 输出:
# arr_b元素重新赋值为0,打印arr_a: [0 0 0 0 0 0]

# arr_b是通过view方法创建的新的数组对象 改变arr_b的shape不会对arr_a有影响
arr_b.shape = (2, 3)
print("arr_a.shape:",arr_a.shape)
# 输出:
# arr_a.shape: (6,)

切片数组返回视图:
修改切片数组返回的视图 会对原始数据进行修改

arr_a = np.arange(6)
arr_c = arr_a[2:4]
print("arr_c:", arr_c)
# 输出:
# arr_c: [2 3]

# 修改arr_c
arr_c[:] = 0
print("arr_a:", arr_a)
# 输出:
# arr_a: [0 1 0 0 4 5]

副本

copy方法生成数组以及原始数组数据的完整副本:

arr_a = np.arange(6)
arr_b = arr_a.copy()
print("arr_a is arr_b:", arr_b is arr_a)
# 输出:
# arr_a is arr_b: False

print("id(arr_a) == id(arr_b):", id(arr_a) == id(arr_b))
# 输出:
# id(arr_a) == id(arr_b): False

arr_b[:] = 0
print("arr_b元素重新赋值为0,打印arr_a:", arr_a)
# 输出:
# arr_b元素重新赋值为0,打印arr_a: [0 1 2 3 4 5]

arr_b.shape = (2, 3)
print("arr_a.shape:", arr_a.shape)
# 输出:
# arr_a.shape: (6,)

如果原始数组数据较大的时候,可以先从原始数组中获取切片数组,如果不再需要对原始数据进行更改的话,可以将切片数组通过copy方法进行深拷贝一个新的数组对象。

主要参考资料:
NumPy官方的中文文档

以上就是关于Python NumPy库的一些基础用法的学习;
如果有什么不对的地方,欢迎指正!

你可能感兴趣的:(Python,python,数据挖掘,机器学习)