Numpy基础笔记

Numpy基础笔记

numpy 概述

  1. Numerical Python,数值的 Python,补充了 Python 语言所欠缺的数值计算能力。
  2. Numpy 是其数据分析及机器学习库的底层库。
  3. Numpy 完全标准 C 语言实现,运行效率充分优化。
  4. Numpy 开源免费。

numpy 历史

  1. 1995 年,Numeric,Python 语言数值计算扩充。
  2. 2001 年,Scipy -> Numarray,多维数组运算。
  3. 2005 年,Numeric + Numarray -> Numpy。
  4. 2006 年,Numpy 脱离 Scipy 成为独立项目。

numpy 的核心:多维数组

  1. 代码简洁:减少 Python 代码中的循环。
  2. 底层实现:厚内核(C ) + 薄接口(Python),保证性能。

numpy 基础

ndarray 数组

np.ndarray 类的对象表示 n 维数组:

import numpy as np

arr = np.array([1, 2, 3, 4, 5, 6])
print(arr, type(arr))
print(arr.shape)  # 数组的维度

arr.shape = (2, 3)  # 修改数组的维度为 2 行 3 列
print(arr, arr.shape)

arr.shape = (6,)

# 数组的运算
print(arr)
print("arr * 3: ", arr * 3)
print("arr + 3: ", arr + 3)
print("arr > 3: ", arr > 3)
print("arr + arr: ", arr + arr)

"""
[1 2 3 4 5 6] <class 'numpy.ndarray'>
(6,)
[[1 2 3]
 [4 5 6]] (2, 3)
[1 2 3 4 5 6]
arr * 3:  [ 3  6  9 12 15 18]
arr + 3:  [4 5 6 7 8 9]
arr > 3:  [False False False  True  True  True]
arr + arr:  [ 2  4  6  8 10 12]
"""

内存中的 ndarray 对象

元数组(metadata)

存储对目标数组的描述信息,如:dim countshapesizedtypedata 等。

实际数据

完整的数组数据

将实际数据与元数据分开存放,一方面提高了内存空间的使用效率,另一方面减少对实际数据的访问频率,提高性能。

ndarray 数组对象的特点

  1. Numpy 数组是同质数组,即所有元素的数据类型必须相同。
  2. Numpy 数组的下标从 0 开始,最后一个元素的下标为数组长度减 1

ndarray 数组对象的创建

  • np.array(任何可被解释为 Numpy 数组的逻辑结构):
    import numpy as np
    
    a = np.array([1, 2, 3, 4, 5, 6])
    print(a) 
    """
    [1 2 3 4 5 6]
    """
    
  • np.arange(起始值(0),终止值,步长(1))
    import numpy as np
    
    a = np.arange(0, 5, 1)
    print(a)
    
    b = np.arange(0, 10, 2)
    print(b)
    
    """
    [0 1 2 3 4]
    [0 2 4 6 8]
    """
    
  • np.zeros(数组元素个数,dtype='类型')
    import numpy as np
    
    a = np.zeros(10)
    print(a)
    
    """
    [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
    """
    
  • np.ones(数组元素个数,dtype='类型')
    import numpy as np
    
    a = np.ones(10)
    print(a)
    
    """
    [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
    """
    

ndarray 对象属性的基本操作

数组的维度:np.ndarray.shape

import numpy as np

arr = np.array([1, 2, 3, 4, 5, 6])
print(type(arr), arr, arr.shape)

arr = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]])
print(type(arr), arr, arr.shape)

"""
<class 'numpy.ndarray'> [1 2 3 4 5 6] (6,)
<class 'numpy.ndarray'> [[1 2 3]
 [4 5 6]
 [7 8 9]] (3, 3)
"""

元素的数据类型:np.ndarray.dtype

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6])
print(type(a), a, a.dtype)

b = a.astype(float)  # 转换 a 的类型为 float
print(type(b), b, b.dtype)

c = a.astype(str)  # 转换 a 的类型为 str
print(type(c), c, c.dtype)

"""
<class 'numpy.ndarray'> [1 2 3 4 5 6] int32
<class 'numpy.ndarray'> [1. 2. 3. 4. 5. 6.] float64
<class 'numpy.ndarray'> ['1' '2' '3' '4' '5' '6'] <U11
"""

数组元素的个数:np.ndarray.size

import numpy as np

a = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]])
print(a.shape, a.size, len(a))

"""
(3, 3) 9 3
"""

数组元素索引(下标)

数组对象[..., 页号, 行号, 列号]

下标从 0 开始,到数组 len - 1 结束

import numpy as np

a = np.array([
    [[1, 2], [3, 4]],
    [[5, 6], [7, 8]]
])
print(a, a.shape)
print(a[0])
print(a[0][0])
print(a[0][1][0])
print(a[0, 1, 0])

"""
[[[1 2]  
  [3 4]] 

 [[5 6]  
  [7 8]]] (2, 2, 2)
[[1 2]
 [3 4]]
[1 2]
1
3
"""

ndarray 对象属性操作详解

Numpy 内部基本数据类型

类型名 类型表示符
布尔型 bool_
有符号整数型 int8(-128~127)/int16/int32/int64
无符号整数型 uint8(0~255)/uint16/uint32/uint64
浮点型 float16/float32/float64
复数型 complex64/complex128
字符串型 str_,每个字符用 32 位 Unicode 编码表示

自定义复合类型

import numpy as np

data = [
    ('zs', [90, 80, 85], 14),
    ('ls', [92, 81, 83], 15),
    ('ww', [95, 85, 95], 16),
]

# 第一种设置 dtype 的方式
a = np.array(data, dtype='U2, 3int32, int32')

print(a)
print(a[0]['f0'], ':', a[1]['f1'], a[1]['f2'])

# 第二种设置的 dtype 的方式
b = np.array(data, dtype=[
    ('name', 'str', 2),
    ('scores', 'int32', 3),
    ('age', 'int32', 1),
])
print(b, b[2]['age'])

# 第三种设置的 dtype 的方式
c = np.array(data, dtype={
    'names': ['name', 'scores', 'age'],
    'formats': ['U2', '3int32', 'int32'],
})
print(c)
print(c[1]['name'])
"""
[('zs', [90, 80, 85], 14) ('ls', [92, 81, 83], 15)
 ('ww', [95, 85, 95], 16)]
[('zs', [90, 80, 85], 14) ('ls', [92, 81, 83], 15)
 ('ww', [95, 85, 95], 16)] 16
[('zs', [90, 80, 85], 14) ('ls', [92, 81, 83], 15)
 ('ww', [95, 85, 95], 16)]
ls
"""

类型字符码

类型 字符码
np.bool_ ?
np.int8/16/32/64 i1/i2/i4/i8
np.uint8/16/32/64 u1/u2/u4/u8
np.float/16/32/64 f2/f4/f8
np.complex64/128 c8/c16
np.str_ U<字符数>
np.datetime64 M8[Y] M8[M] M8[D] M8[H] M8[m] M8[s]

字节序前缀

一般用于多字节整数和字符串:

</>/[=]分别表示小端/大端/硬件字节序

类型字符码格式

< 字节序前缀 >< 维度 >< 类型 >< 字节数或字符数 >

  • 3i4:大端字节序,3 个元素的一维数组,每个元素都是整型,每个整型元素占 4 个字节。
  • <(2,3)u8:小端字节序,6 个元素 2 行 3 列的二维数组,每个元素都是无符号整型,每个无符号整型元素占 8 个字节。
  • U7:包含 7 个字符的 Unicode 字符串,每个字符占 4 个字节,采用默认字节序。

ndarray 数组对象维度的操作

视图变维(数据共享)

改变原数组会影响新数组,即数组之间的数据相互共享。

reshape()ravel()

import numpy as np

a = np.arange(1, 9)
print(a)

b = a.reshape(2, 4)  # 视图变维:变为 2 行 4 列的二维数组
print(b)

c = b.reshape(2, 2, 2)  # 视图变维:变维 2 页 2 行 2 列的三维数组
print(c)

d = c.ravel()  # 视图变维:变为 1 维数组
a[0]=99
print(d)

"""
[1 2 3 4 5 6 7 8]
[[1 2 3 4]
 [5 6 7 8]]
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
[99  2  3  4  5  6  7  8]
"""

复制变维(数据独立)

改变原数组不会影响新数组,即数组之间的数据相互独立。

import numpy as np

a = np.arange(1, 9)
b = a.reshape(2, 2, 2)
c = b.flatten()
print(c)
b[0][0][0] = 99
print(c)

"""
[1 2 3 4 5 6 7 8]
[1 2 3 4 5 6 7 8]
"""

ndarray 数组切片操作

一维数组

一维数组切片的语法为 [起始下标:结束下标:步长],表示从起始下标开始,以指定的步长切割数组,到结束下标为止,但不包括结束下标的元素。

注意

  • 起始下标,结束下标和步长可以省略,起始下标默认为 0,结束下标默认为 数组长度,步长默认为 1
  • 起始下标和结束下标可以为负数-1 对应列表最后一个元素,-2 表示倒数第二个,依次类推。步长可以为 -1-1 表示倒序对数组进行切片。

例如 a[3:6:1] 表示对数组 a 从下标 3 开始,到下标 6 结束(不包括 6),步长为 1 进行切片,所得元素下标分别为 3,4,5

下面是一个综合例子:

import numpy as np

a = np.arange(1, 10)
print(a)  # [1 2 3 4 5 6 7 8 9]
print(a[:3])  # [1 2 3]
print(a[3:6])  # [4 5 6]
print(a[6:])  # [7 8 9]
print(a[::-1])  # [9 8 7 6 5 4 3 2 1]
print(a[-1:-4:-1])  # [9 8 7]
print(a[-4:-7:-1])  # [6 5 4]
print(a[-7::-1])  # [3 2 1]
print(a[::])  # [1 2 3 4 5 6 7 8 9]
print(a[:])  # [1 2 3 4 5 6 7 8 9]
print(a[::3])  # [1 4 7]
print(a[1::3])  # [2 5 8]
print(a[2::3])  # [3 6 9]

二维数组

二维数组切片是一维数组切片的扩展,是类似的。语法为 [起始下标:结束下标:步长, 起始下标:结束下标:步长],逗号前表示对行元素进行切片,逗号后表示对列元素进行切片。

例如 a[:2, :2] 表示对二维数组进行切片,行下标从 0 开始,到下标 2 为止(不包括 2),步长默认为 1;列下标从 0 开始,到下标 2 为止(不包括 2),步长默认为 1

下面是一个综合例子:

import numpy as np

a = np.arange(1, 10)
a.resize(3, 3)
print(a)
print(a[:2, :2])
print(a[::2, ::2])

"""
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[1 2]
 [4 5]]
[[1 3]
 [7 9]]
"""

ndarray 掩码操作

基于 bool 数组的掩码

import numpy as np

a = np.arange(100)
# 输出 3 的倍数
print(a[a % 3 == 0])
"""
[ 0  3  6  9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69
 72 75 78 81 84 87 90 93 96 99]
"""

基于索引的掩码

import numpy as np

# 基于索引的掩码
names = np.array(['Apple', ' Huawei', 'Mi', 'Oppo', 'vivo'])
rank = [1, 0, 3, 4, 2]
print(names[rank])
"""
[' Huawei' 'Apple' 'Oppo' 'vivo' 'Mi']
"""

多维数组的组合与拆分

水平方向上的组合与拆分

hstack 函数实现数组水平方向上的组合,hsplit 函数实现数组水平方向上的拆分。

import numpy as np

a = np.arange(1, 7).reshape(2, 3)
b = np.arange(7, 13).reshape(2, 3)

# 水平方向完成组合操作,生成新数组
c = np.hstack((a, b))
# 水平方向完成拆分操作,生成两个数组
d, e = np.hsplit(c, 2)
print(c)
print(d)
print(e)

"""
[[ 1  2  3  7  8  9]
 [ 4  5  6 10 11 12]]
[[1 2 3]
 [4 5 6]]
[[ 7  8  9]
 [10 11 12]]
"""

垂直方向上的组合与拆分

vstack 函数实现数组垂直方向上的组合,vsplit 函数实现数组垂直方向上的拆分。

import numpy as np

a = np.arange(1, 7).reshape(2, 3)
b = np.arange(7, 13).reshape(2, 3)

# 垂直方向完成组合操作,生成新数组
c = np.vstack((a, b))
# 垂直方向完成拆分操作,生成两个数组
d, e = np.vsplit(c, 2)
print(c)
print(d)
print(e)

"""
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
[[1 2 3]
 [4 5 6]]
[[ 7  8  9]
 [10 11 12]]
"""

深度方向上的组合与拆分

dstack 函数实现数组深度方向上的组合,dsplit 函数实现数组深度方向上的拆分。

import numpy as np

a = np.arange(1, 7).reshape(2, 3)
b = np.arange(7, 13).reshape(2, 3)

# 深度方向完成组合操作,生成新数组
c = np.dstack((a, b))
# 深度方向完成拆分操作,生成两个数组
d, e = np.dsplit(c, 2)
print(c)
print(d)
print(e)

"""
[[[ 1  7]
  [ 2  8]
  [ 3  9]]

 [[ 4 10]
  [ 5 11]
  [ 6 12]]]
[[[1]
  [2]
  [3]]

 [[4]
  [5]
  [6]]]
[[[ 7]
  [ 8]
  [ 9]]

 [[10]
  [11]
  [12]]]
"""

多维数组组合与拆分的相关函数

通过 axis 作为关键字参数指定组合方向,取值如下:

  • 若待组合的数组都是二维数组:
    • 0 :垂直方向组合
    • 1:水平方向组合
  • 若待组合的数组都是三维数组:
    • 0:垂直方向组合
    • 1:水平方向组合
    • 2:深度方向组合

concatenate 函数可以实现数组的组合,split 函数可以实现数组的拆分。

import numpy as np

a = np.arange(1, 7).reshape(2, 3)
b = np.arange(7, 13).reshape(2, 3)

c = np.concatenate((a, b), axis=0)
d, e = np.split(c, 2, axis=0)
print('a:', a)
print('b:', b)
print('c:', c)

"""
a: [[1 2 3]
 [4 5 6]]  
b: [[ 7  8  9]
 [10 11 12]]  
c: [[ 1  2  3]
 [ 4  5  6]   
 [ 7  8  9]
 [10 11 12]]
"""

ndarray 的其他属性

  • shape:维度
  • dtype:元素类型
  • size:元素数量
  • ndim:维数,len(shape)
  • itemsize:元素字节数
  • nbytes:总字节数 = size x itemsize
  • real:复数数组的实部数组
  • imag:复数数组的虚部数组
  • T:数组对象的转置视图
  • flat:扁平迭代器
import numpy as np

a = np.array([
    [1+1j, 2+4j, 3+7j],
    [4+2j, 5+5j, 6+8j],
    [7+3j, 8+6j, 9+9j]
])

print(a.shape)
print(a.dtype)
print(a.ndim)
print(a.size)
print(a.itemsize)
print(a.nbytes)
print(a.real)
print(a.imag)
print(a.T)
print(a.flat)

"""
(3, 3)
complex128
2
9
16
144
[[1. 2. 3.]
 [4. 5. 6.]
 [7. 8. 9.]]
[[1. 4. 7.]
 [2. 5. 8.]
 [3. 6. 9.]]
[[1.+1.j 4.+2.j 7.+3.j]
 [2.+4.j 5.+5.j 8.+6.j]
 [3.+7.j 6.+8.j 9.+9.j]]
<numpy.flatiter object at 0x55eaebdf7380>
"""

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://cangmang.xyz/articles/1642849032398