python中的numpy(数组)

(0)numpy介绍

NumPy是Python中用于科学计算的基础库,提供高效的多维数组对象ndarray,支持向量化运算,能大幅提高数值计算效率。它集成了大量数学函数(如线性代数、傅里叶变换等),可直接对数组进行操作,无需显式循环。NumPy数组占用内存小,运算速度快,且与SciPy、Pandas等库无缝集成,是数据分析、机器学习等领域不可或缺的工具,极大简化了科学计算流程。

(1)创建数组

①np.array和np.asarray

np.array()和np.asarray():输入任意序列对象,输出 ndarray 对象

np.asarray()与 np.array()不同的是,如果传入的序列对象本身就是一个 ndarray,则返回该序列对象的视图(视图就是与原对象共享内存地址,如果有元素变动会同时变动)

python 复制代码
import numpy as np

print("np.array()")
myarray = np.array([1, 2, 3, 4])
print(type(myarray)) # <class 'numpy.ndarray'>
print(myarray)

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(myarr.shape) # (2, 4)
print(myarr.ndim)  # 2
print(myarr.dtype) # float64



print("np.asarray()")
matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
myarr2 = np.array(myarr)
myarr3 = np.asarray(myarr)
myarr[1] = 0
print(myarr)
print(myarr2)
print(myarr3)

②np.arange()

作用类似于 range(),生成一个一维 ndarray

python 复制代码
myarr = np.arange(10)
print(myarr) # [0 1 2 3 4 5 6 7 8 9]

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

myarr = np.arange(0,10,2)
print(myarr) # [0 2 4 6 8]

myarr = np.arange(10,0,-2)
print(myarr) # [10  8  6  4  2]

③np.random.rand()和np.random.random()

  • 都是返回在 [0,1)服从均匀分布的随机数
  • 只是二者输入参数的形式有所区别
python 复制代码
print("np.random.rand()")
print( np.random.rand(4) )    # 一维
print( np.random.rand(2,3) )  # 二维
print( np.random.rand(2,3,2) )  # 三维


print("np.random.random(shape)")
print( np.random.random( (2,3) ) )  # 二维 # 注意多了一个括号

④np.random.randn()和np.random.normal()

  • np.random.randn()是返回一个服从标准正态分布 N(0,1) 的随机数,负无穷到正无穷(在正负 1.96 内的概率是 95%,在正负 2.58 内的概率为 99%)
  • np.random.normal()正态分布。np.random.normal(loc=0.0, scale=1.0, size=None),loc 为均值,scale 为标准差,size 为 shape。
python 复制代码
print("标准正态分布")
print(np.random.randn(2,3))


print("正态分布")
myarr = np.random.normal(5, 1, (2,3))
print(myarr)

⑤np.random.seed()和np.random.RandomState()

如果不调用设置种子的函数,每次运行程序都会生成不同的随机数

python 复制代码
import numpy as np

# 不设置种子,每次运行生成的随机数不同
print(np.random.rand())  # 输出不同的随机数

如果设置了随机数种子,只要在同一个种子下,后续程序每次运行生成的随机数是相同的。在科学计算、机器学习或算法测试中,全局随机数种子允许用户复现实验结果。

python 复制代码
import numpy as np

# 设置全局随机数种子
np.random.seed(44)

x, y = np.random.randint(10), np.random.randint(10)
print(x, y)
# 种子为42时,每次程序运行都是同一个数A,比如我这里每次都是6 3
# 种子为43时,每次程序运行都是同一个数B,比如我这里每次都是4 0
# 种子为44时,每次程序运行都是同一个数C,比如我这里每次都是4 3

后续无论是其他程序,只要在44这个种子下,调用np.random.randint(10)的前两次都是生成同一个数,我这里是4和3。可以单独再起一个py文件运行程序可以验证。

python 复制代码
import numpy as np

print("我爱中国")
np.random.seed(44)
print(np.random.randint(10))  # 4
print(np.random.randint(10))  # 3

但seed函数是生成全局的随机数种子,而randomstate 是一个与其他隔离的局部生成器。二者区别是什么?局部生成器不会影响到全局其它地方随机数的生成,是独立的,而全局生成器将影响全局。举个例子理解,比如我这里在种子值为44的情况下,前三次调用np.random.randint(10)生成的值每次都一样,都为4、3、1。

python 复制代码
import numpy as np

'''
假设在44种子下,np.random.randint(10)前三次生成的数为4 3 1
'''

np.random.seed(44) # 全局生成器
rng1 = np.random.RandomState(44) # 局部生成器1
rng2 = np.random.RandomState(44) # 局部生成器2


def fun1():
    return np.random.randint(10)


def fun2():
    return np.random.randint(10)


def fun3():
    return np.random.randint(10)


def fun4():
    return rng1.randint(10)


def fun5():
    return rng2.randint(10)


# fun1()、fun2()、fun3()用的全局生成器
print(fun1())  # 4,第一次全局生成器调用生成4
print(fun2())  # 3,第二次全局生成器调用生成3

# fun4()用的rng1这个局部生成器、
# 前面全局生成器无论调用多少次,都不会影响到局部生成器rng1
print(fun4())  # 4 不受全局影响,自己是独立的,自己的第一次调用就是4

print(fun3())  # 1,第三次全局生成器调用生成1

# fun5()用的rng2这个局部生成器
print(fun5())  # 4  # 不受全局也不受其它局部生成器影响,自己的第一次调用就是4

可以明显看到用全局数种子,可能会牵一发动全身,比如我们的数据测试在第一次调用和第二次调用生成随机数用以验证都是正常的,突然有一天改了代码在第一次调用和第二次调用加入了一次调用,则从第二次调用之后的调用将全部受影响。但如果我们第一次调用和第二次调用都用的局部生成器生成的,即使在这二者之间又加了新的随机数生成调用,也依然不会受到影响。

python 复制代码
import numpy as np

# 初始代码:两次调用全局随机数生成
np.random.seed(42)
print("第一次调用:", np.random.rand())  # 输出: 0.3745401188473625
print("第二次调用:", np.random.rand())  # 输出: 0.9507143064099162

# 修改代码:在两次调用之间插入新的随机数生成
np.random.seed(42)  # 重新设置种子
print("第一次调用:", np.random.rand())  # 输出: 0.3745401188473625
# 插入新的随机数生成(例如,其他模块的调用)
np.random.rand()  # 修改了全局状态
print("第二次调用(受影响):", np.random.rand())  # 输出不再是预期值

随着代码复杂度的增加,全局种子的管理变得极其困难。因此随机数种子更推荐用局部生成器。

⑥np.zeros(shape)和 np.zeros_like(otherArray)

创建值全为 0 的数组

python 复制代码
print(np.zeros((2,3)))

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(np.zeros_like(myarr))

⑦np.ones(shape)和 np.ones_like(otherArray)

值全为 1 的数组

python 复制代码
print(np.ones((2,3)))

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(np.ones_like(myarr))

⑧np.full(shape, fill_value)和 np.full_like(otherArray, fill_value)

值全为特定值的数组

python 复制代码
print(np.full((2,3), 9))

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(np.full_like(myarr, 99))

⑨np.empty(shape)和 np.empty_like(otherArray)

  • 创建值全为空的数组,但是用这种方法容易有问题
  • 另一种方法是用np.full(shape, np.nan)
python 复制代码
print("用np.empty()方法,不推荐")
print(np.empty((2,3)))

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(np.empty_like(myarr))


print("用np.full()方法,推荐")
print(np.full((2,3), np.nan))

matrix = [[1, 2, 3, 4], [5, 6.1, 7, 8]]
myarr = np.array(matrix)
print(np.full_like(myarr, np.nan))

⑩np.eye(N)或 np.identity(N)

创建一个单位矩阵形式的数组。

help(np.eye)重要参数:

  • N:行数
  • M:列数。默认等于N。
  • k:k 默认为 0,表示数值为 1 的只有主对角线。k 为正整数时,表示主对角线上面的第几条对角线为 1;k 为负整数时,表示主对角线下面的第几条对角线为 1。
python 复制代码
print(np.eye(5))
# [[1. 0. 0. 0. 0.]
#  [0. 1. 0. 0. 0.]
#  [0. 0. 1. 0. 0.]
#  [0. 0. 0. 1. 0.]
#  [0. 0. 0. 0. 1.]]

print(np.eye(5, M = 4)) 
# [[1. 0. 0. 0.]
#  [0. 1. 0. 0.]
#  [0. 0. 1. 0.]
#  [0. 0. 0. 1.]
#  [0. 0. 0. 0.]]

print(np.eye(5, k = 1))
# [[0. 1. 0. 0. 0.]
#  [0. 0. 1. 0. 0.]
#  [0. 0. 0. 1. 0.]
#  [0. 0. 0. 0. 1.]
#  [0. 0. 0. 0. 0.]]

print(np.eye(5, k = -1))
# [[0. 0. 0. 0. 0.]
#  [1. 0. 0. 0. 0.]
#  [0. 1. 0. 0. 0.]
#  [0. 0. 1. 0. 0.]
#  [0. 0. 0. 1. 0.]]

(2)数组属性

1.查看shape、dtype、ndim

python 复制代码
data = np.random.randn(2, 3, 1)
print(data.shape) # (2, 3, 1)
print(data.dtype) # float64
print(data.ndim)  # 3,表示3个维度

2.shape 转化

①arr.reshape()

reshape,顾名思义,调整排列形状,比如4行6列调整为3行8列

  • reshape时先取数,再填充,取数和填充方向是一致,取决于参数order
  • 参数order默认为'C',表示横着取数,横着填充,还可以是'F',表示竖着取数,竖着填充
python 复制代码
arr = np.arange(12)
print(arr)
# [ 0  1  2  3  4  5  6  7  8  9 10 11]

arr2 = arr.reshape(3, 4)
arr2 = arr.reshape(3, 4, order = "C") # 默认横着取数,横着填充
print(arr2)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]


arr3 = arr.reshape(3, 4, order = "F")  # 竖着取数,竖着填充
print(arr3)
# [[ 0  3  6  9]
#  [ 1  4  7 10]
#  [ 2  5  8 11]]


arr4 = arr2.reshape(2,6)
print(arr4)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]]


arr5 = arr4.reshape(3,4, order = 'F')
print(arr5)
# [[ 0  7  3 10]
#  [ 6  2  9  5]
#  [ 1  8  4 11]]

②reshape中的-1

-1 表示该维度的大小由数据本身推断而来,比如原数据是4行5列,共20个数,则shape(5,-1)表示5行4列,这里4=20/5得来,注意"20/5" 必须要为整数

python 复制代码
arr = np.arange(15)
print(arr)
print(arr.reshape((5,-1)))
'''
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]]
'''

③arr.flatten()和arr.ravel()

  • 扁平化:多维数组变为一维数组
  • 区别在于ravel 是视图,flatten 是拷贝
python 复制代码
arr = np.arange(15).reshape((5, 3)) 
print(arr.flatten()) 
print(arr.ravel())
print(arr.reshape(-1))
'''
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]
'''

3.dtype 设置与转换

①创建时设置 dtype

python 复制代码
import numpy as np

arr1 = np.array([1,2,3], dtype = np.float64)
arr2 = np.array([1,2,3], dtype = np.int32)
print(arr1.dtype) # float64
print(arr2.dtype) # int32

②转换已有数组的 dtype

arr.astype(np.dtype)

python 复制代码
# np在创建数组时会自动判断dtype
arr = np.array([1,2,3,4,5])
print(arr.dtype)  # int32 


# 如果输入数据里各种类型都有,则dtype = object
arr2 = np.array(["数据", 2.6, [9,99], 4,5])
print(arr2.dtype)  # object


newarr = arr.astype(np.float64)
print(newarr.dtype) # float64


arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
print(arr.astype(np.int32)) 
#[ 3 -1 -2  0 12 10] # 浮点数转换成整数,小数部分将会被截取删除


arr = np.array(['1.25', '-9.6', '42'], dtype = np.string_)
print(arr.astype(np.float64)) 

# print(arr.astype(np.int32)) 
# 这句会报错,类似于 int 函数接字符串输入时,只能是整数字符串

③常用dtype

|---------------|------------------------------------------|
| 类型 | 说明 |
| int8, uint8 | 有符号和无符号的8位(一个字节)整形 |
| int16, uint16 | 有符号和无符号的16位(一个字节)整形 |
| int32, uint32 | 有符号和无符号的32位(一个字节)整形 |
| int64, uint64 | 有符号和无符号的64位(一个字节)整形 |
| float16 | 半精度浮点数 |
| float32 | 单精度浮点数。与C的float兼容 |
| float64 | 双精度浮点数。与C的double和python的float兼容。 |
| float128 | 扩展精度浮点数 |
| complex64 | 用两个32位浮点数表示的复数 |
| complex128 | 用两个64位浮点数表示的复数 |
| complex256 | 用两个128位浮点数表示的复数 |
| bool | 存储True和False值的布尔类型 |
| object | python对象类型 |
| string_ | 固定长度的字符串(每个字符一个字节)。如果要创建长度为10的字符串,应使用S10 |
| unicode_ | 固定长度的unicode类型(字节数由平台决定)。跟字符串一样,如U10。 |

(3)数组的索引与切片

1.普通索引

python 复制代码
# 两种等价的索引方式 
arr2d = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(arr2d[0][2]) # 3
print(arr2d[0, 2]) # 3  # 常用第二种

维度与其所在元素理解:

  • 第0维元素就是指[1,2,3]、 [4,5,6]、[7,8,9]这些列表,对应的维度标识框是最外面的那个[]
  • 第1维元素就是指1,2,3,4,5,6,7,8,9这些数,对应的维度框是第二层的维度框,比如[1,2,3]的框,[4,5,6]的框,[7,8,9]的框

2.切片(注意返回结果的维度数)

前面普通索引中,每个维度只取一个数,而现在切片就是某个维度取元素时不是取一个,而是取一段范围。

二维数组为例

python 复制代码
#二维数组:轴0和轴1
arr2d = np.array([[1,2,3], [4,5,6], [7,8,9]])

# 第0维就是指[1,2,3]、 [4,5,6]、[7,8,9]这些列表
# 比如取第0维度的第1个元素
print(arr2d[0])  # [1 2 3]

# 第1维元素就是指"1,2,3,4,5,6,7,8,9这些数
# 每个第0维元素有三个第1维元素
# 取第0维度中第一个元素,取这个元素中第三个第1维度元素
print(arr2d[0][2]) # 3

# 现在切片:第0维度时不是只取一个元素,比如取全部元素
# 第1维度取第1个元素
print(arr2d[:, 0])  # [1 4 7]

# 再来一个例子,第0维度取前2个元素,第1维度取前2个元素
print(arr2d[:2, :2]) 
# [[1 2]
#  [4 5]]


arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(arr2d)
print(arr2d[1, :2]) # [4 5]
print(arr2d[:2, 2]) # [3 6]

三维数组举例说明

python 复制代码
# 三维数组,则有轴 0,轴 1 和轴 2(axis = 0,axis = 1,axis = 2)
arr3d = np.array([[[1, 2, 3], [4, 5, 6]],
                  [[7, 8, 9], [10, 11, 12]]])
print(arr3d.shape) # (2, 2, 3)
# 第0维有两个元素,[[1, 2, 3], [4, 5, 6]]和[[7, 8, 9], [10, 11, 12]]
# 每个第0维元素有两个第1维元素
# 比如[[1, 2, 3], [4, 5, 6]]有两个:[1, 2, 3]和[4, 5, 6]
# 每个第1维元素有三个第2维元素,比如[4, 5, 6]有4、5、6这三个第2维元素

print(arr3d[0,1]) # [4 5 6]
print(arr3d[0,1,:]) # [4 5 6] # 省略等价于冒号
print(arr3d[0, 1, 2]) # 6
print(arr3d[0, 1, 1:2]) # [5]

print(arr3d[0, 0:2, 1:2])
# [[2]
#  [5]]

注意,返回结果是一个几维元素受到有没有切片影响,比如下面这个例子本质上取的数范围一样,但返回结果的维度数却不一样

python 复制代码
arr3d = np.array([[[1, 2, 3], [4, 5, 6]],
                  [[7, 8, 9], [10, 11, 12]]])
                  
print(arr3d[0, 0:2, 1:2]) # 返回结果是二维
'''
# [[2]
#  [5]]
'''

print(arr3d[0, 0:2, 1])  # 返回结果是一维
'''
[2 5]
'''

直接放结论:返回结果中,哪个维度有切片或者选取了至少两项,则那个维度的 [] 保留。

比如arr3d[0],第0个维度不用切片,只取了第一个元素,则返回[[1, 2, 3], [4, 5, 6]]。而如果是arr3d[0:1],则会返回[[[1, 2, 3], [4, 5, 6]]]

python 复制代码
arr3d = np.array([[[1, 2, 3], [4, 5, 6]],
                  [[7, 8, 9], [10, 11, 12]]])
print(arr3d[0])
'''
[[1 2 3]
 [4 5 6]]
'''
print(arr3d[0:1])
'''
[[[1 2 3]
  [4 5 6]]]
'''

再去理解前面arr3d[0, 0:2, 1:2]和arr3d[0, 0:2, 1]这个例子就很容易了。

最后,可以明显推算出,每有一个维度取切片或者选取了至少两项,则返回结果就会多一个维度,表现出来就是多一个 [] 。特殊情况,每个维度都不用切片且只选取了一项,则返回结果是一个值,没有[]。

3.数组的改值

python 复制代码
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(arr2d)
# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]

arr2d[:2, 1:] = 0
print(arr2d)
# [[1 0 0]
#  [4 0 0]
#  [7 8 9]]

4.布尔型索引

①等于、不等于、或、且

python 复制代码
import numpy as np

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.arange(28)
data = data.reshape(7, 4)
print(data)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]
 [24 25 26 27]]
'''

# 等于
ret = names == 'Bob'
print(ret)  # [ True False False True False False False]

print(data[ret])  # 对data第0个维度进行筛选
'''
[[ 0  1  2  3]
 [12 13 14 15]]
 '''

print(data[ret, 2:])  # 对data第0个维度按ret筛选,第1个维度按切片筛选
'''
[[ 2  3]
 [14 15]]
'''

# 不等于
print(names != 'Bob')
print(data[~(names == 'Bob')])

# 条件的或
mask1 = (names == 'Bob') | (names == 'Will')

# 条件的且
mask2 = (names == 'Bob') & (names == 'Will') 

print(data[mask1])
print(data[mask2])

布尔索引 + 标量赋值

python 复制代码
print(data)
data[data < 0] = 0
print(data) 

5.花式索引

花式索引:按指定顺序的整数列表或 ndarray 进行索引

比如第0维度我们想取第1个元素、第3元素,第7个元素。就可以用data[ [1, 3, 7] ]

注意:

①data[ [1, 3, 7] ]是花式索引,它和data[ 1, 3, 7 ]是有区别的,前者第0维度取第1个元素、第3元素,第7个元素,后面每个维度的元素全取,而data[ 1, 3, 7 ]是第0维度取第1个元素,第1维度取第3个元素,第2维度取第7个元素

②data[ [1, 3, 7] ]和data[ [3, 1, 7] ]这两个花式索引是有区别的,在于取数顺序

python 复制代码
arr = np.random.rand(3, 3)
print(arr)
# [[0.13242055 0.76648581 0.07674224]
#  [0.33104382 0.67985159 0.50921308]
#  [0.65514614 0.60212036 0.71905456]]

print("第0个维度选取第1和第0个数(二维数组情况下就是选取第1行和第0行)")
print(arr[[1, 0]]) 
# [[0.33104382 0.67985159 0.50921308]
#  [0.13242055 0.76648581 0.07674224]]


print("交换第 1 行和第 0 行")
arr[:2] = arr[[1,0]] 
print(arr)
# [[0.33104382 0.67985159 0.50921308]
#  [0.13242055 0.76648581 0.07674224]
#  [0.65514614 0.60212036 0.71905456]]

多个维度都使用花式索引时,会有两种情况,以下例子说明

python 复制代码
arr = np.arange(32).reshape(8,4)

print("选取交点与区域")
print("选取的是元素(1,0)、(5,3)、(7,1)和(2,2)")
print(arr[[1,5,7,2],[0,3,1,2]]) 
# [ 4 23 29 10]


print("选取的是矩阵的子区域")
print(arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]) 
# [[ 4  7  5  6]
#  [20 23 21 22]
#  [28 31 29 30]
#  [ 8 11  9 10]]

6.数组转置与轴的交换

  • 数组转置:ndarray.T 或 ndarray.transpose((1,0))
  • 轴的交换:ndarray.swapaxes(axis_i, axis_j)
python 复制代码
# 数组转置:ndarray.T 或者 ndarray.transpose((1,0))
arr = np.arange(15).reshape((3,5))
print(arr)

print('-'*20)
print(arr.T)

print('-'*20)
print(arr.transpose((1,0)))



# ndarray.swapaxes(axis_i, axis_j):轴 i 和轴 j 对换
arr = np.arange(16).reshape((2, 2, 4))

print('-'*20)
print(arr)

print('-'*20)
arr = arr.swapaxes(1, 2)
print(arr)

7.视图与副本

视图就是与原对象共享内存地址,如果有元素变动会同时变动。

哪些是视图,哪些是副本:

  • 普通索引、切片、转置和轴对换是视图
  • 布尔型索引和花式索引是副本

切片是视图,要用 copy 方法获取副本

python 复制代码
import numpy as np
arr = np.arange(10) * 2
print(arr)
print(arr[5])

arr_tmp = arr[5:8]
print(arr_tmp)

arr_tmp[0] = 100
print(arr_tmp)
print(arr) # 说明切片是视图

newarr = arr[5:8].copy() # 用 copy 方法获取副本
print(newarr)

newarr[0] = 99
print(newarr)
print(arr)

(4)数组的元素级函数

元素级函数,就是对每个元素施加一个函数操作

比如对每个元素进行平方操作

python 复制代码
import numpy as np

data = np.arange(6)
data = data.reshape(2, 3)

data2 = np.square(data)
print(data2)
'''
[[ 0  1  4]
 [ 9 16 25]]
'''

1.常用一元和二元函数

一元函数就是函数参数只有一个数组,对单个数组的元素进行运算得到新数组

二元函数就是函数参数有两个数组,将两个数组元素之间进行运算得到新数组

|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 一元函数 | |
| np.abs(arr) np.fabs(arr) | 计算整数、浮点数、复数的绝对值(模)。 对于非复数值,fabs更快。 |
| np.sqrt(arr) | 平方根。等价于arr**0.5 |
| np.square(arr) | 平方。等价于arr**2 |
| np.exp(arr) | [e^{x}](#一元函数 np.abs(arr) np.fabs(arr) 计算整数、浮点数、复数的绝对值(模)。 对于非复数值,fabs更快。 np.sqrt(arr) 平方根。等价于arr0.5 np.square(arr) 平方。等价于arr2 np.exp(arr) e^{x} np.log(arr) np.log10(arr) np.log2(arr) np.log1p(arr) 自然底数的log 底数为10的log 底数为2的log log(1+x) np.sign(arr) 计算元素的正负号:1(正数)、0(零)、-1(负数) np.ceil(arr) 大于等于该值的最小整数(向上取整) np.floor(arr) 小于等于该值的最小整数(向下取整) np.arccos(arr)、np.arccosh(arr) np.arcsin(arr)、np.arcsinh(arr) np.arctan(arr)、np.arctanh(arr) 反三角函数 np.logical_not(arr) 计算各元素非x的真值,相当于-arr np.modf(arr) 返回(整数部分,小数部分)这样一个元组 二元函数 np.add(arr1, arr2) arr1+arr2 np.subtract(arr1, arr2) arr1-arr2 np.multiply(arr1, arr2) arr1*arr2 np.divide(arr1, arr2) arr1/arr2 np.floor_divide(arr1, arr2) arr1//arr2 np.mod(arr1, arr2) 除法的余数,相当于arr1 - (arr1//arr2) * arr2 np.power(arr1, arr2) arr1**arr2 np.maximum(arr1,arr2) np.fmax(arr1,arr2) 每个元素作比较的较大值,空值与任何比较返回空值 用fmax时,空值不参与比较,返回另一个数值 np.minimum(arr1,arr2) np.fmin(arr1,arr2) 每个元素作比较的较小值,空值与任何比较返回空值 用fmin时,空值不参与比较,返回另一个数值 np.copysign(arr1,arr2) 将第二个数组中值的符号复制给第一个数组中的值 相当于(arr2 / np.abs(arr2)) * np.abs(arr1)) |
| np.log(arr) np.log10(arr) np.log2(arr) np.log1p(arr) | 自然底数的log 底数为10的log 底数为2的log log(1+x) |
| np.sign(arr) | 计算元素的正负号:1(正数)、0(零)、-1(负数) |
| np.ceil(arr) | 大于等于该值的最小整数(向上取整) |
| np.floor(arr) | 小于等于该值的最小整数(向下取整) |
| np.arccos(arr)、np.arccosh(arr) np.arcsin(arr)、np.arcsinh(arr) np.arctan(arr)、np.arctanh(arr) | 反三角函数 |
| np.logical_not(arr) | 计算各元素非x的真值,相当于-arr |
| np.modf(arr) | 返回(整数部分,小数部分)这样一个元组 |
| | |
| 二元函数 | |
| np.add(arr1, arr2) | arr1+arr2 |
| np.subtract(arr1, arr2) | arr1-arr2 |
| np.multiply(arr1, arr2) | arr1*arr2 |
| np.divide(arr1, arr2) | arr1/arr2 |
| np.floor_divide(arr1, arr2) | arr1//arr2 |
| np.mod(arr1, arr2) | 除法的余数,相当于arr1 - (arr1//arr2) * arr2 |
| np.power(arr1, arr2) | arr1**arr2 |
| np.maximum(arr1,arr2) np.fmax(arr1,arr2) | 每个元素作比较的较大值,空值与任何比较返回空值 用fmax时,空值不参与比较,返回另一个数值 |
| np.minimum(arr1,arr2) np.fmin(arr1,arr2) | 每个元素作比较的较小值,空值与任何比较返回空值 用fmin时,空值不参与比较,返回另一个数值 |
| np.copysign(arr1,arr2) | 将第二个数组中值的符号复制给第一个数组中的值 相当于(arr2 / np.abs(arr2)) * np.abs(arr1) |

2.用out参数将运算结果输出到另一个数组

python 复制代码
import numpy as np

x = np.arange(5)
y = np.empty(5)
np.multiply(x, 10, out = y)
print(y) # [ 0. 10. 20. 30. 40.] 

z = np.zeros(10)
np.power(2, x, out = z[::2]) 
# 注意 a:b:k 的含义,a 和 b 表示范围,k 表示步长
print(z) # [ 1.  0.  2.  0.  4.  0.  8.  0. 16.  0.]

(5)数组的统计方法

统计与前面元素级函数的区别,统计是对某一行或者某一列或者某一维度进行函数操作,或者对全部元素操作,而元素级函数是对每一个元素进行某个函数操作

1.常用统计方法

在统计时,按轴0或者轴1进行统计的区别:轴0运算就是行与行之间运算,轴1就列与列之间运算。 以二维数组即矩阵为例,在轴0上求平均,就是将不同行的值进行平均,也就是返回每一列的平均值。

|----------------------------------------------------------------------|---------------|-------------------------------------------------------------------------------|
| 模块方法 | 对象方法 | 含义 |
| np.sum(arr) np.sum(arr, axis = 0) np.sum(arr, axis = 1) | arr.sum() | 对数组全部元素求和 对数组的轴0进行求和 对数组的轴1进行求和 |
| np.mean(arr) np.mean(arr, axis = 0) np.mean(arr, axis = 1) | arr.mean() | 平均值 |
| np.std(arr) np.std(arr, axis = 0) np.std(arr, axis = 1) | arr.std() | 标准差 |
| ndarray.std(axis=None, dtype=None, out=None, ddof=0, keepdims=False) | | 用ddof设置标准差的自由度,自由度为 n - ddof。默认 ddof 为 0,即自由度为 n |
| np.var(arr) np.var(arr, axis = 0) np.var(arr, axis = 1) | arr.var() | 方差 |
| np.max(arr) np.max(arr, axis = 0) np.max(arr, axis = 1) | arr.max() | 最大值 |
| np.min(arr) np.min(arr, axis = 0) np.min(arr, axis = 1) | arr.min() | 最小值 |
| ①np.argmax(arr) ②np.argmax(arr, axis = 0) ③np.argmax(arr, axis = 1) | arr.argmax() | ①最大值的索引。按每行从左到右,索引值依次为0,1,...,N-1,N为数组中数的个数 ②就是每一列的最大值所在的行索引 ③就是每一行的最大值所在的列索引 |
| np.argmin(arr) np.argmin(arr, axis = 0) np.argmin(arr, axis = 1) | arr.argmin() | 最小值的索引 |
| ①np.cumsum(arr) np.cumsum(arr, axis = 0) np.cumsum(arr, axis = 1) | arr.cumsum() | ①累积求和。按每行从左到右依次累积求和 |
| np.cumprod(arr) np.cumprod(arr, axis = 0) np.cumprod(arr, axis = 1) | arr.cumprod() | 累积求积 |

2.获取百分位数原理详解

python 复制代码
a = np.array([[1,2,3], [4,5,6], [7,8,9]])

print(np.percentile(a, 50)) # 50%分位数
# 5.0

print(np.percentile(a, 50, axis=0))
# [4. 5. 6.]

print(np.percentile(a, 50, axis=1))
# [2. 5. 8.]

print(np.percentile(a,30))
# 3.4

最后的计算 30 的百分位数 3.4 是怎样得到的呢?

计算公式:①(n−1)∗p=i+j;②result = (1−j)∗arr[i]+j∗arr[i+1]

n:数组的个数:1, 2, 3, 4, 5, 6, 7, 8, 9 ,总共 9 个,n=9;

p: 需要计算的百分位数,这里是 30%;

i:是计算后的数值的整数部分,这里计算左边(9-1)∗ 0.3 = 2.4, i = 2;

j:是计算后的小数部分,j = 0.4;

所以最后的结果为:

result = (1−j)∗arr[i]+j∗arr[i+1] = (1 - 0.4)× arr[2] + 0.4 x arr[2+1]

= 0.6 x 3 + 0.4 x 4

= 3.4

3.布尔型数组的统计方法

python 复制代码
import numpy as np

arr = np.random.randn(10)
print(arr)
print((arr > 0).sum()) 
# 布尔值会被强制转换为 1(True)和 0(False) 
# 这里相当于统计了正数的个数


arr = np.array([False, False, True, False])

# 布尔 array 的 any 方法:至少存在一个 True,则返回 True # True
print(arr.any()) 

# 布尔 array 的 all 方法:全部为 True,则返回 True # False
print(arr.all())

(6)数组的排序

1.arr.sort()

python 复制代码
print("①默认升序")
arr = np.arange(10,0,-1)
print(arr)  # [10  9  8  7  6  5  4  3  2  1]

arr.sort()
print(arr)  # [ 1  2  3  4  5  6  7  8  9 10]


print("②多维数组时,默认对最后一个轴进行排序,也就是列与列之间排序")
data = [
    [1, 3, 4],
    [5, 2, 7],
    [2, 1, 100]
]

data2 = np.array(data)
data2.sort()
print(data2)

data2.sort(axis=-1)
print(data2)

data2.sort(axis=1)
print(data2)

'''
[[  1   3   4]
 [  2   5   7]
 [  1   2 100]]
'''

print("③对轴0进行排序,也就是行与行之间排序")
data2.sort(axis=0)
print(data2)
'''
[[  1   2   4]
 [  1   3   7]
 [  2   5 100]]
'''

2.np.sort(arr)

arr.sort()对原对象进行修改

np.sort(arr)产生新的副本

python 复制代码
print("arr.sort()对原对象进行修改")
arr = np.random.randn(5)
print(arr)

print('-'*20)
arr.sort()          
print(arr)


print("np.sort(arr)产生新的副本")
arr = np.random.randn(5)
print(arr)

newarr = np.sort(arr) 
print('-'*20)
print(newarr)

print('-'*20)
print(arr)

(7)数组的集合运算

np.unique(ndarray):数组去重

去重后再按升序排序

python 复制代码
names = np.array([ 'Will','Bob', 'Joe', 'Will', 'Bob', 'Joe', 'Joe'])
print(np.unique(names)) # ['Bob' 'Joe' 'Will']

np.intersect1d(x, y):交集

python 复制代码
arr1 = np.array([ 'Will','Bob', 'Joe', 'Will', 'Bob', 'Joe', 'Joe'])
arr2 = np.array([ 'xxx','yyy', 'Joe', 'Will', 'zzz', 'Joe', 'Joe'])
result = np.intersect1d(arr1, arr2)
print(result) # ['Joe' 'Will']

np.union1d(x, y):并集

python 复制代码
arr1 = np.array([ 'Will','Bob', 'Joe', 'Will', 'Bob', 'Joe', 'Joe'])
arr2 = np.array([ 'xxx','yyy', 'Joe', 'Will', 'zzz', 'Joe', 'Joe'])
result = np.union1d(arr1, arr2)
print(result) # ['Bob' 'Joe' 'Will' 'xxx' 'yyy' 'zzz']

np.setdiff1d(x, y):集合的差

排除x里面在y中也存在的元素

python 复制代码
arr1 = np.array([ 'Will','Bob', 'Joe', 'Will', 'Bob', 'Joe', 'Joe'])
arr2 = np.array([ 'xxx','yyy', 'Joe', 'Will', 'zzz', 'Joe', 'Joe'])
result = np.setdiff1d(arr1, arr2)
print(result) # ['Bob']

np.setxor1d(x, y):集合的对称差

即存在于一个数组中,但不同时存在于两个数组中的元素

python 复制代码
arr1 = np.array([ 'Will','Bob', 'Joe', 'Will', 'Bob', 'Joe', 'Joe'])
arr2 = np.array([ 'xxx','yyy', 'Joe', 'Will', 'zzz', 'Joe', 'Joe'])
result = np.setxor1d(arr1, arr2)
print(result) # ['Bob' 'xxx' 'yyy' 'zzz']

np.in1d(ndarray, 序列对象):判断成员资格

python 复制代码
peoples = np.array([6, 0, 0, 3, 2, 5, 6])
vip = np.array([2, 3, 6])

print(np.in1d(peoples, [2,3,6])) 
# [ True False False True True False True]

print(np.in1d(peoples, vip)) 
# [ True False False True True False True]

(8)数组的合并和拆分

1.数组合并

注意:纵向合并时,两个arr各自的列数必须相等;横向合并时,两个arr各自的行数必须相等

①np.concatenate([arr1, arr2,...], axis = 0)

python 复制代码
arr1 = np.array([[1, 2, 3],
                 [4, 5, 6]])
arr2 = np.array([[7, 8, 9],
                 [10, 11, 12]])

# 默认 axis = 0,在行与行之间合并,也就是纵向合并
print(np.concatenate([arr1, arr2]))
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]

# axis = 1 表示横向合并
print(np.concatenate([arr1, arr2], axis = 1)) 
# [[ 1  2  3  7  8  9]
#  [ 4  5  6 10 11 12]]

②np.vstack()和 np.hstack()

python 复制代码
arr1 = np.array([[1, 2, 3],
                 [4, 5, 6]])
arr2 = np.array([[7, 8, 9],
                 [10, 11, 12]])

print(np.vstack((arr1, arr2))) # 纵向合并
print(np.hstack((arr1, arr2))) # 横向合并

③np.c_[arr1,arr2]和 np.r_[arr1,arr2]

python 复制代码
a = np.array([[1,2,3], 
              [4,5,6]])
b = np.array([[10,20,30], 
              [40,50,60]])

print(np.c_[a, b]) # 列与列之间合并 → 横向合并

print(np.r_[a, b]) # 行与行之间合并 → 纵向合并 

④np.column_stack( )和np.row_stack( )

python 复制代码
arr1 = np.array([[1, 2, 3], 
                 [4, 5, 6]])
arr2 = np.array([[7, 8, 9], 
                 [10,11,12]])

# 列与列之间合并 → 横向合并
print(np.column_stack([arr1, arr2]))


# 行与行之间合并 → 纵向合并
print(np.row_stack([arr1, arr2]))

2.数组拆分

np.split(arr, [1,2,4], axis=0)

  • axis默认为0,表示按行与行之间拆分
  • 1,2,4表示第1行,2行,4行为分割点
  • 拆分后就[第0行,第1行)、[第1行,第2行)、[第2行,第4行),[第4行,最后一行)四部分
  • 返回结果为列表,列表元素为拆分后的数组
python 复制代码
arr = np.arange(30).reshape(5,-1)
print(arr)

print("按行拆分")
result = np.split(arr, [1,2,4])
print(result)


print("按列拆分")
result = np.split(arr, [1,2,4], axis = 1)
print(result)

(9)数组的聚合

1.np二元函数的 reduce 方法

累积运算,聚合在终点

python 复制代码
x = np.arange(1, 6)
print(x)  # [1 2 3 4 5]

# 将第 1 个元素和第 2 个元素进行函数运算,将其与第 3 个运算,
# 再将结果与第 4 个计算,直到所有
print(np.add.reduce(x))  # 15
print(np.multiply.reduce(x))  # 120

2.np二元函数的 accumulate 方法

累积运算,逐步聚合

python 复制代码
x = np.arange(1, 6)
print(x)  # [1 2 3 4 5]

# 保存第一个元素
# 然后将第 1 个元素和第 2 个元素进行函数运算,得到结果,并保存结果
# 然后将其与第 3 个运算,得到结果,并保存结果
# ...
# 直到所有

print(np.add.accumulate(x))  # [ 1  3  6 10 15]
print(np.multiply.accumulate(x))  # [  1   2   6  24 120]

3.np.meshgrid(arr1, arr2) 网格平铺

np.meshgrid(arr1, arr2):作用是"网格化",假设arr1长度为m,arr2长度为n,函数会返回由两个矩阵元素组成的元组(x, y),x是由n行arr1组成的矩阵,y是有m列arr2组成矩阵。

例子1

python 复制代码
points1 = np.arange(5)
points2 = np.array([6, 7, 8, 9])

a, b = np.meshgrid(points1, points2)
print(a)
# [[0 1 2 3 4]
#  [0 1 2 3 4]
#  [0 1 2 3 4]
#  [0 1 2 3 4]]

print(b)
# [[6 6 6 6 6]
#  [7 7 7 7 7]
#  [8 8 8 8 8]
#  [9 9 9 9 9]]

例子2

python 复制代码
points = np.arange(5)
print(points)
# [0 1 2 3 4]

a, b = np.meshgrid(points, points)
print(a)
# [[0 1 2 3 4]
#  [0 1 2 3 4]
#  [0 1 2 3 4]
#  [0 1 2 3 4]
#  [0 1 2 3 4]]

print(b)
# [[0 0 0 0 0]
#  [1 1 1 1 1]
#  [2 2 2 2 2]
#  [3 3 3 3 3]
#  [4 4 4 4 4]]


z = np.sqrt(b ** 2 + a **2) 
# 由 x 坐标和 y 坐标组成所有的(x, y)对,计算 x**2 + y**2,返回二维矩阵
print(z)
# [[0.         1.         2.         3.         4.        ]
#  [1.         1.41421356 2.23606798 3.16227766 4.12310563]
#  [2.         2.23606798 2.82842712 3.60555128 4.47213595]
#  [3.         3.16227766 3.60555128 4.24264069 5.        ]
#  [4.         4.12310563 4.47213595 5.         5.65685425]]

4.np.where(cond, xarr, yarr) 三元表达式

numpy.where 函数是三元表达式 x if condition else y 的矢量化版本

python 复制代码
print("例子1")
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])

result1 = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)] # 列表
print(result1) # [1.1, 2.2, 1.3, 1.4, 2.5]

result2 = np.where(cond, xarr, yarr) # ndarray
print(result2) # [1.1 2.2 1.3 1.4 2.5]


print("例子2")
arr = np.random.randn(4, 4)
print(arr)
arr = np.where(arr > 0, 99, arr) # 将所有的正值替换为 99
print(arr)

5.np.argwhere(条件) 返回满足指定条件的索引

python 复制代码
x = np.arange(6).reshape(2,3)
print(x)
# [[0 1 2]
#  [3 4 5]]


print(np.argwhere(x>1))
# [[0 2]
#  [1 0]
#  [1 1]
#  [1 2]]

(10)广播

1.含义

含义 :对两个数组进行运算时,如果维度有所不同,则会自动将维度小的那个数组扩展以进行运算,这个就是广播。不过并不是每种情况都能广播,也是有条件的

步骤

  • step1:如果两个数组的维度数不相同,那么小维度数组的形状将会在最左边补 1 ,使得与高维度数在维度个数上保持一致。
    • 比如arr1的维度是(2,3,5),arr2的维度是(4,5),则arr2在最左边补1成为(1,4,5)
  • step2:如果两个数组存在不匹配的维度,且其中一方维度的长度为 1,那么为 1 的一方在当前维度上拓展匹配另一方。比如(1,3)和(2,3)运算,会拓展为(2,3)和(2,3)运算,再比如(1,3)和(3,1)运算,会拓展为(3,3)和(3,3)运算。
    • 两个数组都可能进行拓展操作,只要某个维度满足条件。
    • (2,3,5)与(1,4,5)比较,【2和1】不同,【3和4】不同,但只有【2和1】有1,则arr2拓展为(2,4,5)
  • step3:运算。如果两个数组拓展后存在不匹配的维度,则抛出异常。
    • 比如这里(2,3,5)和(2,4,5)运算会出错。
    • 但如果是(2,3,5)和(3,5)进行运算则不会出错,(3,5)补1后就是(1,3,5),(1,3,5)然后拓展为(2,3,5),这样(2,3,5)和(2,3,5)运算是没问题的
    • 再比如(2,3,5)和(5,)运算,(5,)拓展为(1,1,5),然后(2,3,5),然后也可以运算

例子

python 复制代码
a = np.arange(3).reshape((3,1))
b = np.arange(3)
print(a + b) # 能广播成功
# 因为(3,1)和(3,) → (3,1)和(1,3) → (3,3)和(3,3)可以运算


x = np.ones((3,2))
y = np.arange(3)
print(x + y) # 不能广播成功
# 因为(3,2)和(3,) → (3,2)和(1,3) → (3,2)和(3,3),这两个不可以运算

2.用 reshape实现广播

用 reshape 方法可以将一些不能广播的实现广播

比如前面的(3,2)和(3,)无法进行广播,那我们将(3,)变成(3,1),而(3,2)和(3,1)是可以进行广播的

python 复制代码
x = np.ones((3,2))
y = np.arange(3).reshape(3,1) 

print(x + y)

3.用 np.newaxis插入新轴实现广播

用 np.newaxis 插入一个新轴,来为广播打基础,前面的reshape(3,1) 相当于在最后面又加了1维,也就是np.newaxis方法的一种特殊情况。例子如下:

python 复制代码
print("例子①")
arr = np.zeros((4, 4))
print(arr)
# [[0. 0. 0. 0.]
#  [0. 0. 0. 0.]
#  [0. 0. 0. 0.]
#  [0. 0. 0. 0.]]

arr_3d = arr[:, np.newaxis, :] # 在第0维后插入一个轴
print(arr_3d) # 会将第0维的每个元素加上1个[],这样第0维的元素就由
'''
[[[0. 0. 0. 0.]]

 [[0. 0. 0. 0.]]

 [[0. 0. 0. 0.]]

 [[0. 0. 0. 0.]]]
'''
# 可以看到在第0维后插入一个轴后, 会将第0维的每个元素加上1个[]
# 这样第0维的元素就由[0. 0. 0. 0.]变成了[[0. 0. 0. 0.]]
# 第1维的元素就是[0. 0. 0. 0.]
# 第2维元素就是0. 0. 0. 0.这些数了
print(arr_3d.shape) # (4, 1, 4)  # 在轴 1 插入一个轴,长度为 1


print("例子②")
arr_1d = np.arange(3)
print(arr_1d)  # [0 1 2]

print(arr_1d[:, np.newaxis]) # 在轴 1 插入一个轴,长度为 1
# [[0]
#  [1]
#  [2]]

print(arr_1d[np.newaxis, :]) # 在轴 0 插入一个轴,长度为 1
# [[0 1 2]]


print("③一种等价的方式")
print(arr_1d.reshape((1,-1)))
# [[0 1 2]]

4.用广播来替换值

python 复制代码
import numpy as np

print("①全部替换")
arr = np.zeros((4, 3))
arr[:] = 5
print(arr)


print("②与列进行广播替换")
col = np.array([1.28, -0.42, 0.44, 1.6])
print(col[:, np.newaxis])  # shape为(4,1)就是4行1列

arr[:] = col[:, np.newaxis]
print(arr)


print("③与数进行广播替换")
arr[:2] = [[-1.27], [0.509]]  # 第 0 行全部替换为-1.27,第 1 行全部换为 0.509
print(arr)

5.多维数组对某一维取平均

  • 三维数组,比如长宽高,想象一个立体三维空间,在某一维度取平均就是在固定其它维度时这个维度不同值的平均值,比如对高这个维度求平均,就是在同一长和宽时,不同高的平均值
  • 二维数组,想象一个平面,对轴0求平均,就是在同一列下,对不同行与行之间值求平均
python 复制代码
arr = np.random.randn(3, 4, 5)
print(arr)

print('-'*50)

# 在相同轴 0 和轴 1 时,不同轴 2 之间的平均值
# depth_means = arr.mean(axis = 2)
depth_means = arr.mean(2)
print(depth_means)


# 原数减去平均数
print('-'*50)
demeaned = arr - depth_means[:, :, np.newaxis]
print(demeaned)

(11)numpy中的空值

numpy的空值

numpy.nan表示空值,数据类型是float类型

python 复制代码
import numpy as np

print(type(np.nan))  # float

任何数字和nan运算都为空值

python 复制代码
import numpy as np

print(np.nan + 1)   # nan
print(np.nan + 0)   # nan
print(np.nan - np.nan)   # nan

nan表示空值,两个nan是不相等的。

python 复制代码
import numpy as np

print(np.nan == np.nan)  # False
print(np.nan != np.nan)  # True

由于两个nan不是相等的,因此空值NaN的判断不能直接使用==表达式,bool表达式,以及不可直接使用if语句判断

python 复制代码
import numpy as np

data = np.nan

# 下面会打印"nan 不是空值",显然是不符合逻辑的
if data != np.nan:
    print(data, "不是空值")

# 也不能用于bool函数,因为会返回True
print(bool(np.nan))  # True

# 也不能用于if真假判断
if np.nan:
    print('np.nan 为真')

需要使用Numpy自带的方法np.isnan(),is表达式,in表达式进行判断

python 复制代码
import numpy as np

np.nan is np.nan # True
np.isnan(np.nan) # True
np.nan in [np.nan] # True

注意None、NaN、空字符串的区别

python 复制代码
import numpy as np

# None是Python的特殊类型
# NoneType对象,它只有一个值None
print(type(None))  # NoneType
print(None is None)   # True
print(None is np.nan)  # False

# 空字符串''
print('' == np.nan)  # False

因此如果不仅需要筛选np.nan,还需要筛选None,以及'' ",需要多加判断

python 复制代码
import numpy as np

filter_list = [np.nan, '', None]
data = [np.nan, 99, "我爱中国", '', 3, 6, "None"]
print(data)

for i in range(len(data)):
    if data[i] in filter_list:
        print(f"过滤:data[{i}]", )
    else:
        print(f"保留:data[{i}]", )

(12)一些应用知识

1.巧妙插入数字

在数组[1, 2, 3, 4, 5]中相邻两个数字中间插入两个0

产生新数组[1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5]

python 复制代码
import numpy as np

arr = np.array([1, 2, 3, 4, 5])
k = 2
arr0 = np.zeros(len(arr) + (len(arr) - 1) * k)
arr0[:: k + 1] = arr
print(arr0)

2.用numpy处理图片

python 复制代码
import numpy as np
import matplotlib.pylab as plt

# 画图的辅助函数
def plti(im, **kwargs):
    plt.imshow(im, interpolation = "none", **kwargs)
    plt.axis('off') # 去掉坐标轴
    plt.show() # 显示图像


# 加载图像
imagepath = r'd:\PythonData\Images\myLogo.jpg'
im = plt.imread(imagepath) # 图片的本质是三维数组
print(im.shape) # 输出图像尺寸    # (110, 383, 3), 100表示高度,383表示长度,3表示RGB
print(type(im))
plti(im)

# 剪切图片(左上角)
plti(im[:im.shape[0]//2, :im.shape[1]//2, :])

# 剪切图片(左下角)
plti(im[im.shape[0]//2:, :im.shape[1]//2, :])

# 图片垂直翻转
plti(im[::-1, :, :])

# 图片水平翻转
plti(im[::, ::-1, :])

# 图片填充
imagepath = r'd:\PythonDataImages\myLogo.jpg'
im = plt.imread(imagepath) # 加载图片
startx = im.shape[1]//4
starty = im.shape[0]//4
width = im.shape[1]//2
height = im.shape[0]//2

# 图片复制
bakim = im.copy()

# 颜色填充
bakim[starty: height + starty, startx: width + startx, :] = [0, 255, 255]  # (R,G,B)
plti(bakim)

3.K个最近邻

查找K个最近邻:随机生成10个点,找出第0个点的k个最近的点。

可能用到的函数:np.random.rand()、plt.scatter()、np.sum()、np.newaxis、np.argpartition()

np.argpartition(arr, k),对数组进行快排,并返回索引数组,第二参数位置的索引找到后就停止算法,故不保证全部有序,第二参数可以是一个值或list。

以下代码在Jupyter Notebook操作

python 复制代码
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import seaborn
seaborn.set()
plt.scatter(x[:,0], x[:,1], c='r', s = 100)
python 复制代码
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import seaborn

# 找到k个近邻的函数,返回颜色数组,用颜色区分哪些点是近邻点
def getColors(points, k):
    # 生成第0个点到所有点的距离数组
    distances = np.sqrt(np.sum(np.square(points - points[0]), axis = 1))
    print(distances)
    
    # 找到距离排在第k(从小到大的排序,0,1,2,3,...n-1)的索引值
    print( np.argpartition(distances, k))
    index_k = np.argpartition(distances, k)[k]
    print(index_k)
    
    # 获取排在第k的距离
    distance_k = distances[index_k]
    
    # 生成颜色数组,第0个点为红色,k个近邻点为绿色,其他蓝色
    colors = np.array(['b'] * len(points))
    colors[distances <= distance_k] = "g"
    colors[0] = 'r'
    
    return colors

if __name__ == "__main__":
    n = 10     # 点的个数
    k = 4      # k个近邻点
    a,b = 1,5  # 数的大小范围
    x = a + np.random.rand(n, 2) * (b - a)
    print(x)
    colors = getColors(x, k)
    
    seaborn.set()
    plt.scatter(x[:,0], x[:,1], c = colors, s = 100)

4.在txt文件中存放和取用序列化对象

(1)将数组数据保存在txt中

python 复制代码
import numpy as np

data = [[1,2,3],
        [4,5,6],
        [7,8,9]
        ]
# data = np.array(data) # 有无这个都可以,只要传入序列化对象即可
np.savetxt("data1.txt", data, fmt='%d') # fmt='%.6f'

(2)从txt中读取数据,变成数组

python 复制代码
a = np.loadtxt("data1.txt")
print(a)

b = np.loadtxt("data1.txt", dtype=int)
print(b)

5.npy文件存放和取用python对象

npy文件是什么?是numpy专用的二进制文件。可以将数组等对象,以及python中其它像字典等对象存放在其中的文件。

np.load和np.save是读写磁盘数组数据的两个主要函数,默认情况下,以未压缩的原始二进制格式保存在扩展名为.npy的文件中。

示例如下:

python 复制代码
import numpy as np

# 将数组以二进制格式保存到磁盘
a = np.arange(5)
np.save('test.npy', a)


# 将test.npy文件中的数据读出来
data = np.load('test.npy', encoding="latin1")  # 加载文件
print(type(data))  # numpy.ndarray
print(data)

还可以存放和取用字典

python 复制代码
import numpy as np

# 存放字典数据在npy文件
data = {"node": 1, "value": 12}
np.save('test.npy', data)  

# 从npy文件中读取数据
test = np.load('test.npy', allow_pickle=True)  # 加载数据
print(type(test))  # 注意这里是numpy.ndarray
print(test)  # {'node': 1, 'value': 12}


# 还需要用item方法取出相应数据
data = test.item()
print(type(data))  # <class 'dict'>
print(data)  # {'node': 1, 'value': 12}

这个知识点的一个作用就是可以将节点数据保存下来,程序中断后可以知道在哪个节点出了问题,重新运行程序时能从指定的节点起开始运行。


end

相关推荐
星释1 小时前
Mac Python 安装依赖出错 error: externally-managed-environment
开发语言·python·macos
小迅先生2 小时前
AI开发 | Web API框架选型-FastAPI
开发语言·python·fastapi
Takina~2 小时前
python打卡day35
python·深度学习·机器学习
程序员秘密基地2 小时前
基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统
python·web安全·机器学习·网络安全·scikit-learn
赶紧去巡山3 小时前
pyhton基础【2】基本语法
python
Ma_si3 小时前
PyLink 使用指南
网络·python·嵌入式硬件
非小号4 小时前
PaddleX 使用案例
人工智能·pytorch·python·机器学习·scikit-learn
PWRJOY4 小时前
Flask 会话管理:从原理到实战,深度解析 session 机制
后端·python·flask
患得患失9494 小时前
【Django Serializer】一篇文章详解 Django 序列化器
python·django·sqlite
烧烤店小蚂蚁5 小时前
打卡day35
python