Numpy入门

Numpy

一、什么是Numpy

  • numpy是python中的一个做科学计算的基础库,主要用于对多维数组(可以理解为列表套列表的数据结构)的数值运算,其含有的功能全面且运算效率比简单的for循环强大许多

二、Numpy的简单使用

  • 导包:import numpy as np # 约定俗成的一种命名

1. 创建数组

  • 常用的共3种

    • numpy.array()
    • numpy.arange()
    • numpy.random()
  • 其他创建方式

    • 创建一个全0的数组:numpy.zeros()

    • 创建一个全1的数组:numpy.ones()

  • numpy.empty()

  • numpy.linspace ()

  • numpy.logspace ()

(1)常用创建数组方式

import numpy as np  # 约定俗成的一种命名
# 1. 使用numpy.array创建数组
# 语法:numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
object    数组或嵌套的数列
dtype    数组元素的数据类型,可选
copy     对象是否需要复制,可选
order    创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok    默认返回一个与基类类型一致的数组
ndmin    指定生成数组的最小维度

a1 = np.array([1,2,3,4,5])
print(a1,type(a1))  # [1 2 3 4 5]

# 1.1 numpy.array配合range方法创建
# 值得一提的是,numpy中一些与python中同名的方法,用法基本是一致的。如:range、round、random等
a2 = np.array(range(1,6))
print(a2,type(a2))  # [1 2 3 4 5]


# 2. 使用numpy的arange方法创建
# 语法:numpy.arange(start, stop, step, dtype)
a3 = np.arange(1,6)

print(a3,type(a3))  # [1 2 3 4 5]
a4 = np.arange(4,10,2)
print(a4,type(a4))  # [4 6 8]

"""
上面的打印结果

[1 2 3 4 5] <class 'numpy.ndarray'>
[1 2 3 4 5] <class 'numpy.ndarray'>
[1 2 3 4 5] <class 'numpy.ndarray'>
[4 6 8] <class 'numpy.ndarray'>

# 可以看到,上面a1、a2、a3的输出都相同
"""

# 3. 创建随机数数组
# 4.1 创建随机浮点数的数组
# 语法:numpy.random.random(size=None)   
# 该方法返回 [ 0.0, 1.0 ) 范围的随机浮点数。参数 size 为随机数的数量,默认为None数量为1个

x = np.random.random(size=4)        # 生成4个[0.0,1.0)之间的随机数
y = np.random.random(size=(3,4))    # 生成3行4列个 [0.0,1.0)之间的随机数


# 4.2 创建随机整数数组
# 语法:numpy.random.randint()
# 该方法有三个参数 low、high、size 三个参数。默认 high 是None,如果只有low,那范围就是 [0,low) 。如果有 high,范围就是 [low,high)

x = np.random.randint(5,size=10)        # 生成10个[0,low)范围的随机整数
print(x)
y = np.random.randint(5,10,size=10)     # 生成10个[low,high)范围的整数
print(y)
z = np.random.randint(5,10,size=(2,4))   # 生成2行4列个 [low,high)范围的整数

# 4.3 numpy.random.seed(s)  随机数种子,s是给定的种子值,当我们指定了随机种子之后,后面生成的随机数的值就不会变化了,除非再指定另一个种子值
numpy.random.seed(2)
x = np.random.randint(5,10,size=(3,4)) 
print(x)  # 下面每次打印的x和第一次打印的都一样
print(x) 
print(x) 

# 均匀分布, 在相同的大小范围内的出现概率是相等的
# 正态分布, 呈钟型,两头低,中间高,左右对称,即类似完整左右对称的抛物线
# 4.4 numpy.random.rand(d0,d1,…,dn)
# 产生一个给定形状的浮点数数组,数组中的数值范围在[0, 1)的均匀分布
print("rand")
a = np.random.rand(2, 3)
print(a)
print("*"*50)


# 4.5 numpy.random.randn(d0,d1,…,dn)
# randn 函数返回一个或一组样本,具有标准正态分布(期望为0,方差为1)。dn 表示每个维度,返回值为指定维度的 array。(标准正态分布即半个抛物线)
x = np.random.randn()
print(x)
y = np.random.randn(2,4)
print(y)
z = np.random.randn(2,3,4)
print(z)


# 4.6 numpy.random.normal()  指定期望和方差的正太分布
x = np.random.normal(loc=3,scale=4,size=(2,2,3))
print(x)   


# 4.7 numpy.random.uniform(low, high, size)
# 产生一个数组,数组中的数值符合[low, high)的均匀分布
print("uniform")
d = np.random.uniform(1., 2., (2, 3))
print(d)
print("*"*50)

(2)其他创建方式

1. numpy.zeros 创建指定大小的数组,数组元素以 0 来填充
# 语法:numpy.zeros(shape, dtype = float, order = 'C')

import numpy
x = numpy.zeros(5)      # 创建5个0的数组,默认为float类型
print(x)
y = numpy.zeros((2,5), dtype=int)    # 创建2组5个0的数组,类型为int
print(y)
"""
[0. 0. 0. 0. 0.]
[[0 0 0 0 0]
 [0 0 0 0 0]]
"""

2. numpy.ones 创建指定形状的数组,数组元素以 1 来填充
# 语法:numpy.ones(shape, dtype = None, order = 'C')

import numpy
x = numpy.ones(5)        # 创建5个1的数组,默认类型为float
print(x)
y = numpy.ones((2,4), dtype=int)    # 创建2组4个1的数组,类型为int
print(y)
"""
[1. 1. 1. 1. 1.]
[[1 1 1 1]
 [1 1 1 1]]
"""

3. numpy.empty 方法用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组,里面的元素的值是之前内存的值
# numpy.empty(shape, dtype = float, order = 'C')
shape:  数组形状
dtype:  数组类型,可选
order:  有"C"和"F"两个选项,分别代表行优先和列优先,在计算机内存中的存储元素的顺序

import numpy
x = numpy.empty([3,2], dtype=int, order='F')
print(x)

4. numpy.linspace 函数用于创建一个一维数组,数组是一个等差数列构成的,格式如下:
# 语法:numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
start     序列的起始值
stop     序列的终止值。如果endpoint为True,该值包含于数列中。
mum      要生成的等步长的样本数量,默认为50。
endpoint     该值为True时,数列中包含stop值,反之不包含。默认为True。
retstep    如果为True时,生成的数组中会显示间距,反之不显示。默认为False
dtype      ndarray的数据类型,默认为float。

import numpy
x = numpy.linspace(1, 10, 10)    # 生成样本数为10,起始为1,终止为10的数据(默认为float)
print(x)  # [ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]

import numpy
x = numpy.linspace(10, 15, 10, endpoint=False)        # 生成样本数为10,起始为10,终止为15(不包含)的数据(默认float)
print(x)  # [10.  10.5 11.  11.5 12.  12.5 13.  13.5 14.  14.5] 

import numpy
x = numpy.linspace(1, 5, 10, retstep=True, endpoint=True, dtype=int)    # 生成样本数为10,起始为1,终止为5,类型为int 的数据,生成的数据带间距
print(x)  # (array([1, 1, 1, 2, 2, 3, 3, 4, 4, 5]), 0.4444444444444444)

5. numpy.logspace 函数用于创建一个等比数列
# 语法:numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
start    序列的起始值为:base**start
stop    序列的终止值为:base**stop (如果endpoint为True,该值包含于数列中)
num    要生成的等步长的样本数量,默认为50
endpoint  该值为True时,数列中包含stop值,反之不包含。默认为True
base       对数log的底数
dtype     ndarray的数据类型,默认为float

import numpy
x = numpy.logspace(0, 9, 10, base=2)    # 创建一个长度为10的等比数列,起始值为2的0次方,终止值为2的9次方
print(x)  # [  1.   2.   4.   8.  16.  32.  64. 128. 256. 512.]

2. numpy数组的属性

  • ndarray即为numpy数组对象

    • ndarray 是用于存放同类型元素的多维数组

    • ndarray 中的每个元素在内存中都有相同存储大小的区域

    • ndarray 内部由以下内容组成:

      • 一个指向数据(内存或内存映射文件中的一块数据)的指针。

      • 数据类型或 dtype,描述在数组中的固定大小值的格子。

      • 一个表示数组形状(shape)的元组,表示各维度大小的元组

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n行m列
ndarray.size 数组元素的总个数,相当于.shape中n*m的值
ndarray.dtype ndarray对象的元素类型
ndarray.itemsize ndarray对象中每个元素的大小,以字节为单位
ndarray.flags ndarray对象的内存信息
ndarray.real ndarray对象的实部
ndarray.imag ndarray对象的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。

3. 数组的数值类型

  • 注意:一个numpy数组中的所有数据的数值类型一定是相同的

(1)numpy数组的数值类型的特性

  • 数组中数值类型共有两种,分为整数型和浮点型
    • 整数型 # 元素都是整数即为整数型数组
    • 浮点型 # 元素中含有浮点数,则为浮点型数组
  • 同化定理
    • 往整数型数组里插入浮点数,该浮点数会自动被截断为整数;
    • 往浮点型数组里插入整数,该整数会自动升级为浮点数;
  • 共同改变定理
    • 整数型数组和浮点型数组相互转换,规范的方法是使用 数组.astype() 方法
    • 此外整数型数组在运算过程中容易不经意间升级为浮点型数组,包括以下方面:
      • 整数型数组与浮点数做运算
      • 整数型数组遇到除法(即便是除以整数)
      • 整数型数组与浮点型数组做运算

(2)数值类型的操作

  • 共分为三部分
    • 显示数组的数值类型
    • 创建数组时指定数值类型
    • 调整当前数组的数值类型
# 1. 显示数组的数据类型
# 语法:dtype 显示数组其中的数值类型
print(a1.dtype,a2.dtype,a3.dtype,a4.dtype)  # int32 int32 int32 int32
# 在创建numpy数组时,也可以指定数据类型,未指定时,则默认按照计算机的位数来

# 2. 创建数组时指定数组的数据类型
# 语法:dtype=np.类型  或者 dtype=类型 或者 dtype='类型'
a5= np.array(range(1,6),dtype=np.int64)
print(a5.dtype)  # int64
a5= np.array(range(1,6),dtype=float)
print(a5.dtype)  # float64
a5= np.array(range(1,6),dtype="i1")  # i1表示用1个字节存储int
print(a5.dtype)  # int8
a5= np.array(range(1,6),dtype="int8")
print(a5.dtype)  # int8
a5= np.array(range(1,6),dtype="bool")
print(a5.dtype)  # bool

# 3. 调整数组的数据类型
# 语法: 数组.astype(新类型)
a5= np.array(range(1,6),dtype="int8")
print(a5,a5.dtype)  # [1 2 3 4 5] int8
a6 =a5.astype('float')
print(a6,a6.dtype)  # [1. 2. 3. 4. 5.] float64
a7 =a5.astype('bool')
print(a7,a7.dtype)  # [ True  True  True  True  True] bool

4. 修改浮点型的小数的位数

# 就是指定保留几位小数
# python中使用round方法,numpy中也有这个方法
import random
b = [random.random() for i in range(5)]
print(b)
b1 = np.round(b,2)
print(b1)
"""
[0.9412305815516894, 0.3545380359864132, 0.6146295682019017, 0.04649930657508816, 0.10917508391643027]
[0.94 0.35 0.61 0.05 0.11]
"""

5. 数组的形状

  • 共有两部分
    • 显示数组形状
    • 改变数组形状

(1)显示数组形状

# 语法:数组.shape ,***shape后面不带括号***
a = np.array(range(6))
print(a)
print(a.shape)

a = np.array([[1,2,3],[4,5,6]])
print(a)
print(a.shape)  # 2行3列的二维数组

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

(6,)

[[1 2 3]
 [4 5 6]]
 
(2, 3)

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

 [[ 7  8  9]
  [10 11 12]]]
  
(2, 2, 3)

# 可以看出,shape的结果有几个数字,就是几维的数组。当数组为一维时,shape显示的是数组的数据个数
"""

(2)改变数组形状

# 语法:数组.reshape() ,注意:reshape括号里的元组,长度为几,那么变形后的数组就是几维的
# reshape()括号内也可以不写元组,直接写形状,但是当要变形为一维数组时,必须传入元组。
a = np.arange(12)
print(a)

a = a.reshape((3,4))  # 变形为3行4列的二维数组,同a = a.reshape(3,4)
print(a)

# a = a.reshape((3,5))  # 报错了
"""
[ 0  1  2  3  4  5  6  7  8  9 10 11]

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
 
Traceback (most recent call last):
  File "C:/PycharmProjects/jt_transport/test/numpy_test.py", line 110, in <module>
    a = a.reshape((3,5))
ValueError: cannot reshape array of size 12 into shape (3,5)
"""

a1 = np.arange(24).reshape((2,3,4))
print(a1)
'''
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
  
(2,3,4) 可以简单的理解为2表示块数,一共2块数据,3表示每块的行数,4表示每块的列数
'''

a2 = np.arange(24).reshape((4,6))
print(a2)
a2 = np.arange(24).reshape((1,4,6))   # 同a2 = np.arange(24).reshape(1,4,6)
print(a2)
'''
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
 
 [[[ 0  1  2  3  4  5]
  [ 6  7  8  9 10 11]
  [12 13 14 15 16 17]
  [18 19 20 21 22 23]]]
'''

a3 = np.arange(6).reshape((2,3))
print(a3)
a4 = a3.reshape((6,))
print(a4)  # [0 1 2 3 4 5]
a5 = a3.reshape((6,1))
print(a5)
a6 = a3.reshape((1,6))
print(a6)

'''
[[0 1 2]
 [3 4 5]]
[0 1 2 3 4 5]
[[0]
 [1]
 [2]
 [3]
 [4]
 [5]]
[[0 1 2 3 4 5]]

注意:reshape括号里的元组,长度为几,那么变形后的数组就是几维的
'''

(3)展开数组 flatten() 和 ravel()

# 当我们想将一个数组变形为一个一维数组,但是我们又不知道这个数组中有多少个数据时,可以用下面的方法

# 1. 笨方法:用shape方法求得数组的形状,再将结果相乘即可获取数组的数据个数

a2 = np.arange(24).reshape((1,4,6))

a_sh = a2.shape
print('a_sh',a_sh)
l = a_sh[0] * a_sh[1] * a_sh[2]
print(l)
a3 = a2.reshape((l,))  # 只能这么写,不能 a3 = a2.reshape(l,),也不能 a3 = a2.reshape(l)
print('a3',a3)

# 2. np的flatten()、ravel()方法,直接将数组变形为一维数组
a4 = a2.flatten()
a5 = a2.ravel()
print('a4',a4)
print('a5',a5)
'''
a_sh (1, 4, 6)
24
a3 [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
a4 [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
a5 [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
'''

三、数组的基础运算

1. 数组与数字的的简单运算

  • **numpy中有两种特殊数值,nan 和 inf。nan 全称为 not a number ,inf 全称 infinity,无限无穷的意思 **
# 1. 数组的普通运算
s = np.arange(24).reshape(4, 6)
print(s)

s1 = s + 2  # 会把数据中的每个数据都与该数字进行计算
print(s1)

s2 = s/2
print(s2)

"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
[[ 2  3  4  5  6  7]
 [ 8  9 10 11 12 13]
 [14 15 16 17 18 19]
 [20 21 22 23 24 25]]
[[ 0.   0.5  1.   1.5  2.   2.5]
 [ 3.   3.5  4.   4.5  5.   5.5]
 [ 6.   6.5  7.   7.5  8.   8.5]
 [ 9.   9.5 10.  10.5 11.  11.5]]
"""

# 特殊情况
# 1. 除以 0
s3 = s/0
print(s3)

"""
[[nan inf inf inf inf inf]
 [inf inf inf inf inf inf]
 [inf inf inf inf inf inf]
 [inf inf inf inf inf inf]]
  
numpy中有两种特殊数值,nan 和 inf。nan 全称为 not a number ,inf 全称 infinity,无限无穷的意思 
"""

2. 数组与数组之间的运算

(1)广播原则

  • numpy数组与数组之间的运算,按照广播原则

NumPy 广播是 NumPy 中的一个重要概念,它允许两个形状不同的数组进行运算。两个数组的后缘(从shape的末尾往左数)维度相同,或者不同时其中一方的维度为1,都是可以进行广播的

1)后缘维度

如果两个数组的后缘维度相同,则可以直接进行广播,无需进行任何扩展。

A为(3,4,5)的三维数组,B为(4,5)的二维数组。由于A和B的后缘维度都为(4,5),所以可以进行广播
A为(3,4,5)的三维数组,B为(3,4)的二维数组。由于A的后缘维度为(4,5),B的后缘维度为(3,4),所以不能进行广播。
A为(3,4,5)的三维数组,B为(3,4,1)的三维数组。由于A的后缘维度为(3,4,5),B的后缘维度为(3,4,1),虽然最后的维度不同,但是B最后的维度为1,所以可以进行广播。
A为(3,4,5)的三维数组,B为(3,1,5)的三维数组。由于A的后缘维度为(3,4,5),B的后缘维度为(3,1,5),虽然中间的维度不同,但是B中间的维度为1,所以可以进行广播。
A为(3,4,5)的三维数组,B为(2,1,5)的三维数组。由于A的后缘维度为(3,4,5),B的后缘维度为(2,1,5),虽然中间的维度不同,B中间的维度为1,但是A,B第一个维度不同,所以不能进行广播。
A为(3,4,5)的三维数组,B为(1,1,5)的三维数组。由于A的后缘维度为(3,4,5),B的后缘维度为(1,1,5),虽然第一个和第二个的维度都不同,但是不同的维度中,B的维度都为1,所以可以进行广播。
A为(1,4,5)的三维数组,B为(2,1,5)的三维数组。由于A的后缘维度为(1,4,5),B的后缘维度为(2,1,5),虽然第一个和第二个的维度都不同,但是不同的维度中,有一方的维度为1,所以可以进行广播。
A为(2,3)的二维数组,B为(3,)的1维数组,后缘维度都是3,所以可以进行广播。

2)其中一方维度为1

如果两个数组的后缘维度不同,但其中一方维度的长度为 1,则另一方维度会被拉伸为与其相同的长度。

A为(4,5)的二维数组,B为(4,1)的二维数组,两者维度相同, B的数组中一个维度元素个数为1。
A为(4,5)的二维数组,B为(1,5)的二维数组,两者维度相同, B的数组中一个维度元素个数为1。
A为(4,5)的二维数组,B为(1,1)的二维数组,两者维度相同, B的数组中一个维度元素个数为1。
A为(4,5)的二维数组,B为(1,)的二维数组,两者维度相同, B的数组中一个维度元素个数为1。

3)广播的好处
广播机制可以让 NumPy 数组的运算更加灵活和高效,避免了需要对数组进行 reshape 操作的麻烦。理解和正确使用广播可以极大地提高数据处理和分析的效率。

(1)内存高效

广播避免了不必要的内存分配,只是在算法层面上扩展较小的数组。

(2)性能优化

广播可以减少大量数据的复制,提高计算性能。

(3)代码简洁

可以直接对不同形状的数组进行运算,而不需要显式地调整它们的形状。

(2)简单示例

# 当shape相同的数组之间的运算,是对应位置的数值进行计算
# 当shape不同的数组之间进行运算时,会把对应行或者列的数据广播到另一个数组的每一行或列进行计算

s = np.arange(24).reshape(4, 6)
s4 = np.arange(100,124).reshape((4,6))

s5 = s + s4
print(s5)

"""
[[100 102 104 106 108 110]
 [112 114 116 118 120 122]
 [124 126 128 130 132 134]
 [136 138 140 142 144 146]]
 
 # 对应行列相同的位置的数据进行计算
"""

print(s)
s6 = np.arange(6)
print(s6)

s7 = s - s6
print(s7)

"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
 
[0 1 2 3 4 5]

[[ 0  0  0  0  0  0]
 [ 6  6  6  6  6  6]
 [12 12 12 12 12 12]
 [18 18 18 18 18 18]]
 
# s的每一行都对 s6 进行计算
"""

b = np.arange(6).reshape(1,6)
print(s)
print(b)
b1 = s- b
print(b1)

"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
 
[[0 1 2 3 4 5]]

[[ 0  0  0  0  0  0]
 [ 6  6  6  6  6  6]
 [12 12 12 12 12 12]
 [18 18 18 18 18 18]]

# s和b虽然都是二维数组,但s、b的列数据相同,所以s的每一行都拿来对 b 进行计算
"""

b2 = np.arange(4).reshape(4,1)
print(s)
print(b2)
b3 = s- b2
print(b3)

"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
 
[[0]
 [1]
 [2]
 [3]]
 
[[ 0  1  2  3  4  5]
 [ 5  6  7  8  9 10]
 [10 11 12 13 14 15]
 [15 16 17 18 19 20]]
 
# s和b2虽然都是二维数组,但s、b2的行数据相同,所以s的每一列都拿来对 b2 进行计算
"""

(3)错误示例

s = np.arange(24).reshape(4, 6)
print(s)
c = np.arange(10)  # shape为 (10,)
print(c)

print(s - c)  # 数组的后缘维度不同,无法计算

"""
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
 
[0 1 2 3 4 5 6 7 8 9]

Traceback (most recent call last):
  File "C:/PycharmProjects/jt_transport/test/numpy_test.py", line 137, in <module>
    print(s - c)
ValueError: operands could not be broadcast together with shapes (4,6) (10,)
"""
posted @ 2025-03-12 16:32  BigSun丶  阅读(149)  评论(0)    收藏  举报