@TOC
引言:numpy的常见注意事项
1 numpy数组是可变数据类型
NumPy 数组(numpy.ndarray
)是 可变数据类型。
以下是一些关键点来解释 NumPy 数组的可变性:
(1). 元素的修改:
-
NumPy 数组中的元素是可以被修改的。你可以直接通过索引来改变数组中的某个值。例如,给定一个数组
arr
,你可以通过arr[0] = 10
来修改数组的第一个元素。import numpy as np arr = np.array([1, 2, 3]) arr[0] = 10 # 修改第一个元素为 10 print(arr) # 输出: [10 2 3]
(2). 数据的视图与切片:
-
NumPy 提供了一种称为视图(view)的机制,通过该机制可以从一个数组创建一个新的数组对象,而不复制数据本身。这意味着通过一个视图修改数组中的元素也会影响到原始数组。
arr = np.array([1, 2, 3, 4]) view = arr[1:3] # 创建一个视图 view[0] = 10 # 修改视图中的元素 print(arr) # 输出: [ 1 10 3 4],原始数组也被修改
(3). 内存共享:
- 多个数组可以共享相同的数据内存。例如,通过
np.copy
创建的数组和通过view
创建的数组都可以共享同一块内存。这种机制增强了数组的可变性,因为一个数组的修改可能会影响到共享同一内存的其他数组。
综上所述,NumPy 数组允许对其内容进行修改,并且这种修改会反映在使用该数组的所有视图中,这表明它是可变的。
2 numpy数组的view视图机制以及与列表的区别
2.1 numpy数组的view机制
NumPy 的视图(view)机制是一种允许多个数组对象共享相同数据内存的方法。通过这种机制,创建一个数组的视图(view)不会复制数据本身,而是创建一个新的数组对象,该对象使用与原始数组相同的内存。因此,对视图的修改会影响原始数组,反之亦然。(简单来说就是numpy数组的赋值操作是共享原内存的。)
2.1.1视图机制的工作原理
视图机制的关键在于 NumPy 数组的设计。每个 numpy.ndarray
对象包括以下几个部分:
- 数据缓冲区:实际存储数组数据的内存区域。
- 形状信息:定义数组的维度和每个维度的大小。
- 步长信息:定义在数组的每个维度上前进一个元素所需跳过的字节数。
视图与原数组共享相同的数据缓冲区,但它们可以拥有不同的形状和步长信息,这使得视图可以表现为不同的数组结构。
2.1.2视图的创建方式
(1). 数组切片(Slicing):
使用切片操作可以创建一个数组的视图。切片操作不会创建数据的副本,而是生成一个新的数组对象,该对象仍然引用原始数据。
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
view = arr[1:4] # 创建视图
view[0] = 10 # 修改视图中的元素
print(arr) # 输出: [ 1 10 3 4 5],原始数组也被修改
print(view) # 输出: [10 3 4]
(2). 数组的变形(Reshape):--- 特别注意这个也是内存共享的在numpy里面没有想到吧
使用 reshape
方法重新定义数组的形状,也会创建一个视图,只要新形状与原数组兼容且没有引入新的内存布局(如展平操作)。
arr = np.array([[1, 2, 3], [4, 5, 6]])
view = arr.reshape(3, 2) # 创建视图
view[0, 0] = 10
print(arr) # 输出: [[10 2 3]
# [ 4 5 6]],原始数组被修改
print(view) # 输出: [[10 2]
# [ 3 4]
# [ 5 6]]
(3). 数组的转换操作(Transpose):
使用 transpose
或 T
属性可以创建一个转置视图。
arr = np.array([[1, 2], [3, 4]])
view = arr.T # 创建转置视图
view[0, 1] = 10
print(arr) # 输出: [[ 1 2]
# [ 10 4]],原始数组被修改
print(view) # 输出: [[ 1 10]
# [2 4]]
总结一下就是,numpy的view机制就是让将原本的赋值给新变量应该是创建一个新内存,但numpy的view视图机制 ---- 就是让赋值操作不改变内存,还是共享原来的内存。
arr = np.array([1, 2, 3, 4])
arr2 = arr
arr2[0] = 100
print(arr) # [100 2 3 4]
print(arr2) # [100 2 3 4]
arr 和arr2的内存是共享的,这就是numpy数组的view视图机制的神奇之处,也是我们需要注意的地方。
【注】:numpy数组变成就是进行的是赋值操作也要想想是不是内存共享的。
2.2 numpy view机制与列表(没有view机制的数据结构)的区别
看下面前先了解列表的浅复制与深复制python列表
NumPy 的视图(view)机制和 Python 列表之间有着显著的差异,尤其在内存管理和数据操作方面。下面我们详细对比 NumPy 数组的视图机制与 Python 列表的特性。
1. 内存管理
NumPy 数组的视图
-
共享内存:
- NumPy 数组的视图和原数组共享相同的内存空间。任何对视图的修改都会直接反映在原数组上,反之亦然。
- 视图(view)是通过操作原数组的元数据(如形状、步长等)而产生的,不涉及数据的复制。
import numpy as np arr = np.array([1, 2, 3, 4]) view = arr[1:3] # 创建一个视图 view[0] = 10 # 修改视图中的值 print(arr) # 输出: [ 1 10 3 4],原始数组被修改 print(view) # 输出: [10 3],视图反映出修改
-
内存连续性:
- NumPy 数组通常是内存连续的,这意味着数据在内存中是按顺序排列的,这对计算效率有很大的提升。
- 视图可以通过步长(strides)和形状信息创建,从而允许非常高效地操作数组的子集或重塑数组。
Python 列表
-
独立内存:
- Python 列表没有视图机制。每个列表元素的引用是独立的,创建子列表时会复制引用(浅拷贝),但不会共享相同的内存空间。即使是子列表,对它的修改不会影响原始列表。
- 深拷贝和浅拷贝的概念在列表中尤为重要。浅拷贝会创建一个新列表,其中的元素是原列表中对象的引用,而深拷贝则会递归地复制整个对象及其子对象。
lst = [1, 2, 3, 4] sub_lst = lst[1:3] # 创建一个子列表(浅拷贝) sub_lst[0] = 10 # 修改子列表中的值 print(lst) # 输出: [1, 2, 3, 4],原始列表未被修改 print(sub_lst) # 输出: [10, 3],子列表显示修改
-
内存分散:
- 列表中的元素是独立存储的引用,存储地址可能不连续。这种非连续性使得某些操作的效率较低,特别是与数值运算相关的操作。
2. 数据操作
NumPy 数组的视图
-
高效的切片与变形:
- NumPy 允许通过视图对数组进行非常高效的切片、重塑和操作,而无需实际的数据复制。可以通过视图进行快速的子数组操作。
arr = np.array([1, 2, 3, 4, 5, 6]) reshaped = arr.reshape((2, 3)) # 重塑数组,不复制数据 print(reshaped) # 输出: [[1 2 3] # [4 5 6]]
-
内存高效性:
- 由于视图共享内存,操作大数据集时无需担心内存的过度使用。许多数值操作可以在原地进行,减少了内存的开销。
Python 列表
-
切片创建新列表:
- 切片操作创建一个新的列表(浅拷贝),这意味着元素的引用被复制了,但实际的数据没有复制。如果原始列表包含的不是简单数据类型,而是对象,修改对象会影响到切片和原列表。
lst = [[1, 2], [3, 4]] sub_lst = lst[:] sub_lst[0][0] = 10 print(lst) # 输出: [[10, 2], [3, 4]],原始列表中的对象被修改 print(sub_lst) # 输出: [[10, 2], [3, 4]],子列表也反映出修改
-
深拷贝:
- 如果需要真正独立的副本,必须使用深拷贝(
copy.deepcopy
),这会递归地复制列表及其包含的所有元素。深拷贝在需要隔离修改时非常重要,但它比视图操作的效率低得多。
import copy lst = [[1, 2], [3, 4]] deep_copy_lst = copy.deepcopy(lst) deep_copy_lst[0][0] = 10 print(lst) # 输出: [[1, 2], [3, 4]],原始列表未受影响 print(deep_copy_lst) # 输出: [[10, 2], [3, 4]],深拷贝反映出修改
- 如果需要真正独立的副本,必须使用深拷贝(
2.3 视图与副本的区别
看下面前先了解列表的浅复制与深复制python列表
视图(view)和副本(copy)的主要区别在于内存共享:
- 视图:多个数组对象共享相同的数据内存,对其中任何一个的修改都会反映在所有视图中。
- 副本:副本是原数据的完全独立的克隆,修改副本不会影响原始数组,反之亦然。
- 在numpy数组里面数据
- 注意,numpy自带的 .copy方法是深复制,和copy模块的copy方法是浅复制不一样
arr = np.array([1, 2, 3, 4])
view = arr[1:3] # 创建视图
copy = arr[1:3].copy() # 创建副本
view[0] = 10
copy[0] = 20
print(arr) # 输出: [ 1 10 3 4],视图的修改影响原数组
print(view) # 输出: [10 3]
print(copy) # 输出: [20 3],副本的修改不影响原数组
二维数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
copy = arr[:,0].copy() # 创建副本,numpy自带的是深复制
print(copy) # 输出: [1 4 7]
copy[0] = 20
print(arr) # 输出: [[1 2 3] [4 5 6] [7 8 9]],副本的修改不影响原数组
print(copy) # 输出: [20 4 7],副本的修改不影响原数组
【注】:在numpy数组中由于有自带的 .copy(深复制)就不要和列表一样用copy模块了。另外由于numpy数组特殊的视图机制,如果用copy模块里面浅复制,两者结合在一起会导致浅复制效果和深复制效果一样。之前列表那套规则完全不适用,就不用管了。
2.4 视图的优势
- 效率:视图避免了数据复制,因此可以显著节省内存和时间,尤其是处理大型数据集时。
- 灵活性:可以通过视图创建不同的数组视图,进行不同的操作,而无需改变原始数组的数据。
NumPy 的视图机制是高效数据操作的核心特性,理解和正确使用它有助于优化数组操作的性能。
一、numpy数组创建
1. np.array(object,dtype)
np.array()
是 NumPy 中用于创建数组的函数,它将输入的数据转换为 NumPy 数组。以下是 np.array()
函数的两个常用参数及其详细说明,其他参数默认值即可:
(1). object
:输入的数据对象,可以是以下类型之一:
- Python 列表或元组:
[1, 2, 3]
,(1, 2, 3)
- 嵌套列表或元组:
[[1, 2], [3, 4]]
,((1, 2), (3, 4))
- 可迭代对象:如 Python 迭代器、生成器等
(2). dtype
:(可选参数)所需的输出数据类型。如果未提供,NumPy 将自动推断数据类型。常见的数据类型包括:
int
,float
,complex
: 整数、浮点数、复数bool
: 布尔值str
: 字符串- 其他数据类型:如
np.int32
,np.float64
等
arr1 = np.array([1,2,3])
print(arr1) # 输出 [1,2,3]
arr2 = np.array([[1,2,3],
[4,5,6]], dtype=np.float64)
print(arr2) # 输出 [[1. 2. 3.]
# [4. 5. 6.]]
2. np.arange(start,stop,step,dtype)
左闭右开
np.arange()
是 NumPy 库中的一个函数,用于创建一个按指定范围和间隔的等差数组。
参数说明:
start
:可选,表示起始值,默认为0。stop
:结束值(不包含在数组内)。step
:可选,表示步长(增量),默认为1。如果未指定步长,会自动使用1。dtype
:可选,返回数组的数据类型。如果未提供,则会根据其他输入推断数据类型。
np.arange()
返回的是一个 NumPy 数组,其中包含从 start
到 stop
(不包含 stop
)之间,以 step
为步长的一系列数值。
arr1 = np.arange(1,10,2,dtype=np.float64)
print(arr1) # [1. 3. 5. 7. 9.]
arr2 = np.arange(10)
print(arr2) # [0 1 2 3 4 5 6 7 8 9]
3 np.linspace(start,stop,num)
默认是左闭右闭
np.linspace()
函数是 NumPy 库中的一个函数,用于创建一个指定范围内的等间隔数组。它的语法如下:
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
参数说明:
start
:表示数组的起始值。stop
:表示数组的结束值(包含在数组内)。num
:可选,表示生成的样本数,默认为50。endpoint
:可选,如果为 True,则在 stop 值包含在数组内,如果为 False,则不包含在数组内。默认为 True。retstep
:可选,如果为 True,则返回 (array, step) 的元组,其中 step 为数组的步长。默认为 False。dtype
:可选,返回数组的数据类型。如果未提供,则会根据其他输入推断数据类型。
np.linspace()
返回的是一个 NumPy 数组,其中包含从 start
到 stop
(包含 stop
)之间,总共 num
个等间隔的数值。
下面是一些示例:
import numpy as np
# 生成一个从0到10,共11个元素的等间隔数组
array1 = np.linspace(0, 10, 11)
print(array1) # 输出: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
# 生成一个从0到2π,共100个元素的等间隔数组
array2 = np.linspace(0, 2*np.pi, 100)
print(array2) # 输出: [0. 0.06346652 0.12693304 ... 6.15625227 6.21971879 6.28318531]
# 生成一个从1到5,共20个元素的等间隔数组,并返回步长
array3, step = np.linspace(1, 5, 20, retstep=True)
print(array3) # 输出: [1. 1.21052632 1.42105263 ... 4.78947368 5. ]
print(step) # 输出: 0.21052631578947367
总之,np.linspace()
函数非常方便,可以快速生成指定范围内等间隔的数组,并且可以选择是否包含结束值以及是否返回步长。
4 np.logspace(start,stop,num)
np.logspace()
函数是 NumPy 库中的一个函数,用于创建一个对数刻度的等比数组。它的语法如下:
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数说明:
start
:表示序列的起始值为 base ** start。stop
:表示序列的结束值为 base ** stop。num
:可选,表示生成的样本数,默认为50。endpoint
:可选,如果为 True,则在 stop 值包含在数组内,如果为 False,则不包含在数组内。默认为 True。base
:可选,对数空间的底数,默认为10。dtype
:可选,返回数组的数据类型。如果未提供,则会根据其他输入推断数据类型。
np.logspace()
返回的是一个 NumPy 数组,其中包含从 base ** start
到 base ** stop
之间,总共 num
个对数刻度上等分(等比均分)(的数值。
下面是一个示例:
import numpy as np
# 生成一个在 10**0=1 到 10**2=100 之间,在对数刻度上均匀分布(等比均分)的 5 个点
array = np.logspace(0, 2, 5)
print(array) # 输出: [ 1. 3.16227766 10. 31.6227766 100. ]
# 10/3.16227766=100/31.6227766=3.16227766
在上述示例中,np.logspace(0, 2, 5)
生成了一个包含 5 个数值的数组,这些数值在对数刻度上均匀分布在 1 到 100 之间。
np.logspace()
函数在需要在对数刻度下生成均匀分布的数值时非常有用,例如在绘制对数坐标图时。
5 创建特殊数组
np.zeros((a,b))---生成0矩阵,a行,b列(a行,b列全0二维数组)
np.ones((a,b))---生成1矩阵,a行,b列(a行,b列全1二维数组)
np.eye(m)---生成m阶单位阵
np.diag([a,b,c,...])---生成对角阵
np.full((a,b),num)---生成用指定num填充的数组
arr = np.full((3, 3), 9)
print(arr) # [[9 9 9]
# [9 9 9]
# [9 9 9]]
np.empty((a,b))----生成二维空数组,只申请空间,不初始化
6 创建与给定数组相同形状的数组
参数:
arr:数组,创建与这个数组相同形状的数组
dtype:数据类型
np.zeros_like(arr,dtype)
np.ones_like(arr,dtype)
np.empty_like(arr.dtype) ---- 函数会返回一个与给定数组形状相同,并且元素为随机值的数组。
import numpy as np
arr = np.array([[1, 2, 3],
[4, 5, 6]])
zero = np.zeros_like(arr)
print(zero) # [[0 0 0]
# [0 0 0]]
one = np.ones_like(arr)
print(one) # [[1 1 1]
# [1 1 1]]
empty = np.empty_like(arr)
print(empty)
np.full_like(arr,num) --- 创建与arr形状相同用num填充的数组
a = np.arange(12).reshape(3,4)
full = np.full_like(a, 10)
print(full) # [[10 10 10 10]
# [10 10 10 10]
# [10 10 10 10]]
二、numpy数组的常用属性与方法
1 numpy数组常用属性
NumPy 数组(也称为 ndarray)是 NumPy 库的核心数据结构,它具有许多属性和方法,用于对数组进行各种操作和计算。以下是一些常用的 NumPy 数组属性:
ndarray.shape:表示数组的维度,返回一个元组,元组的长度就是数组的维数,每个元素的值对应于数组在相应维度上的大小。
ndarray.ndim:表示数组的维数(即数组轴的数量)。
ndarray.size:表示数组中元素的总数。
ndarray.dtype:表示数组中元素的数据类型。
下面是一个示例,演示了如何访问和使用这些属性:
import numpy as np
# 创建一个 2x3 的二维数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("数组的形状(shape):", arr.shape) # 输出: (2, 3)
print("数组的维数(number of dimensions):", arr.ndim) # 输出: 2
print("数组中元素的总数(size):", arr.size) # 输出: 6
print("数组中元素的数据类型(dtype):", arr.dtype) # 输出: int64
这些属性可以帮助你了解和操作 NumPy 数组的特征,例如数组的形状、大小、数据类型等信息。
2 改变numpy数组形状的方法
(1)array.reshape((a,b)) ---- [注]:有返回值(返回一个view),需要一个变量接住,并且是一个view视图
arr1 = np.arange(12).reshape((3,-1))
print(arr1) # [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
唯一需要解释的就是:当 new_shape 中的某个维度值设为 -1 时,NumPy 会根据数组的元素数量和其他维度的大小自动推断出这个特定维度的大小。
reshape 返回的是视图:
arr = np.arange(12)
arr1 = arr.reshape((3,-1))
print(arr1) # [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
arr1[0,0] = 100
print(arr1) # [[100 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(arr) # [100 1 2 3 4 5 6 7 8 9 10 11] reshape方法返回的是原数组的视图,修改视图会改变原数组
(2)array.resize((a,b)) ---- 原地修改
arr = np.arange(12)
arr.resize((3,4))
print(arr) # [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
【注】:resize里面不能用 -1 自动确定维度了
3 改变数组的数据类型
array.astype(np.float64) ---- 有返回值(返回的不是视图,是副本),需要一个变量接住
arr = np.arange(12) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
arr1 = arr.astype(np.float32)
print(arr1) # [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.]
4 numpy数组的扁平化(展开)
(1)array.flatten() --- 有返回值(副本),需要变量接住
order='F' ---- 按列展开
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3],
[4, 5, 6]])
# 使用 flatten() 方法将其转换为一维数组
flattened_arr = arr.flatten() # 默认按行展平
flattened_arr1 = arr.flatten(order='F') # 按列展平
print(flattened_arr) # 输出: [1 2 3 4 5 6]
print(flattened_arr1) # 输出: [1 4 2 5 3 6]
(2)array.arr.ravel() --- 有返回值(返回view视图,共享内存),需要变量接住
order='F' ---- 按列展开
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3],
[4, 5, 6]])
# 使用 ravel() 方法将其转换为一维数组
raveled_arr = arr.ravel() # 默认按行展开
raveled_arr2 = arr.ravel(order='F') # 按列展开
print(raveled_arr) # 输出: [1 2 3 4 5 6]
print(raveled_arr2) # 输出: [1 4 2 5 3 6]
5 numpy数组合并
分割很少用,因此这里只介绍合并了
np.hstack((arr1,arr2)) ----- 数组横向合并
np.vstack((arr1,arr2)) ----- 数组纵向合并
np.concatenate((arr1,arr2),axis = 1)) ----- 数组横向合并
np.concatenate((arr1,arr2),axis = 0)) ------ 数组纵向合并
import numpy as np
# 创建一个二维数组
arr1 = np.array([[1, 1],
[1, 1]])
arr2 = np.array([[2, 2],
[2, 2]])
res1 = np.hstack((arr1, arr2))
print(res1) # [[1 1 2 2]
# [1 1 2 2]]
res2 = np.vstack((arr1, arr2))
print(res2) # [[1 1]
# [1 1]
# [2 2]
# [2 2]]
res3 = np.concatenate((arr1, arr2), axis=0)
print(res3) # [[1 1]
# [1 1]
# [2 2]
# [2 2]]
res4 = np.concatenate((arr1, arr2), axis=1)
print(res4) # [[1 1 2 2]
# [1 1 2 2]]
6 numpy数组的插入、删除、尾部增加
(1)numpy.insert(arr, obj, values, axis=None) --- 指定索引插入
用法有很多,下面只给出机器学习编程最常用的一种示例。具体其他用法可以问GPT。
np.insert
是 NumPy 中用于在数组中插入值的函数。它可以在指定的索引位置插入一个或多个元素,并返回插入后的新数组。下面是 np.insert
的基本用法:
其中:
arr
:要插入值的输入数组。obj
:要插入的索引位置values
:要插入的值。可以是单个数值或与obj
匹配的数组。axis
:可选参数,指定插入的轴。默认为None
,表示输入数组会在插入之前被展开。
import numpy as np
arr = np.array([[1, 2],
[3, 4]])
new_arr = np.insert(arr, 1, [10, 20], axis=0) # 在行的索引位置 1 处插入一整行
print(new_arr)
# 输出:
# [[ 1 2]
# [10 20]
# [ 3 4]]
new_arr = np.insert(arr, 1, [10, 20], axis=1) # 在列的索引位置 1 处插入一整列
print(new_arr)
# 输出:
# [[ 1 10 2]
# [ 3 20 4]]
【注】:机器学习中如果要插入某列特征就是用这个
(2)numpy.append(arr, values, axis=None) --- 尾部增加
用法有很多,下面只给出最常用的一种示例。具体其他用法可以问GPT。
np.append()
是 NumPy 中用于在数组末尾追加值的函数。它可以用于沿指定轴将值添加到数组的末尾,并返回一个新的数组。下面是 np.append()
的基本用法:
其中:
arr
:要追加值的输入数组。values
:要追加的值。可以是单个数值、数组或列表。axis
:可选参数,指定追加的轴。默认为None
,表示输入数组会在追加之前被展开。
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
new_arr = np.append(arr, [[7, 8, 9]], axis=0) # 在行的方向上追加数组
print(new_arr)
# 输出:
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
new_arr = np.append(arr, [[7], [8]], axis=1) # 在列的方向上追加数组
print(new_arr)
# 输出:
# [[1 2 3 7]
# [4 5 6 8]]
【注】:这个对插入的维度要求就很高了。比insert严格
(3)numpy.delete(arr, obj, axis=None) ---- 指定索引删除
np.delete()
是 NumPy 中用于删除数组中指定位置的元素的函数。它可以删除指定索引或沿指定轴删除元素,并返回一个新的数组。下面是 np.delete()
的基本用法:
其中:
arr
:要删除元素的输入数组。obj
:索引位置axis
:可选参数,指定要删除的轴。默认为None
,表示输入数组会在删除之前被展开。
import numpy as np
arr = np.array([[1, 2, 3],
[4, 5, 6]])
new_arr = np.delete(arr, 1, axis=0) # 沿着行的方向删除索引位置 1 处的元素
print(new_arr)
# 输出:
# [[1 2 3]]
new_arr = np.delete(arr, 0, axis=1) # 沿着列的方向删除索引位置 0 处的元素
print(new_arr)
# 输出:
# [[2 3]
# [5 6]]
7 numpy数组random模块
(1)np.random.random((a,b))---- 生成在区间 [0.0, 1.0) 内均匀分布的 随机数
array = np.random.random((3,4))
print(array) # [[0.5488135 0.71518937 0.60276338 0.54488318]
# [0.4236548 0.64589411 0.43758721 0.891773 ]
# [0.96366276 0.38344152 0.79172504 0.52889492]]
# 随机生成一个3行4列的数组
(2) np.random.randint(a,b,(2,3)) ---生成shape=(2.3)数组,各元素为[a,b)间的 整数
array = np.random.randint(1,5,(3,4))
print(array) # [[1 4 3 4]
# [3 3 4 3]
# [4 4 4 3]]
# 随机生成一个3行4列的数组
(3) np.random.rand(a,b) ---生成在 [0.0, 1.0) 区间上均匀分布的随机样本.括号里面的就是形状
array = np.random.rand(3,3)
print(array) # [[0.18190363 0.68358 0.52755396]
# [0.1535464 0.08898371 0.92839724]
# [0.55473887 0.3027213 0.22780086]]
(4) np.random.randn(a,b) --- 生成服从标准正态分布(均值为0,标准差为1)的随机样本.括号里面的就是形状
array = np.random.randn(3,3)
print(array) # [[ 0.0736 -0.9442 -0.7284]
# [-0.9369 -0.2656 0.7485]
# [ 0.585 -0.9626 -0.3999]]
(5)np.random.normal(均值,标准差,(a,b)) ----- 生成服从正态分布(高斯分布)的随机样本
array = np.random.normal(2,5,(3,4))
print(array) # [[ 1.21188957 9.16765522 1.92067158 0.07484142]
# [ 6.92335411 -3.12658469 -3.80600274 1.54660865]
# [ 2.04972396 11.7871042 1.09952282 0.25780966]]
8 numpy获取数组最大最小索引
(1)np.argmax(arr,axis)--- 获取最大索引
一维数组
# 创建一个示例数组
arr = np.array([1, 5, 3, 9, 2])
# 获取数组中最大值的索引
max_index = np.argmax(arr)
print(max_index) # 输出结果为 3,因为最大值 9 在索引位置 3 上
二维数组
arr = np.array([[1, 2, 3],
[4, 5, 6]])
# 沿着第一个轴(行)获取最大值的索引
max_indices_axis_0 = np.argmax(arr, axis=0)
print(max_indices_axis_0) # [1 1 1],因为每一列中最大值的索引分别为 1 1 1
# 沿着第二个轴(列)获取最大值的索引
max_indices_axis_1 = np.argmax(arr, axis=1)
print(max_indices_axis_1) # [2 2],因为每一行中最大值的索引分别为 2 2
(2)np.argmin(arr,axis)--- 获取最大索引
用法和 np.argmin()完全一样
9 numpy数组排序
arr.sort(axis) ---- 原地排序,升序,用axis控制按行排序还是按列排序
a = np.array([[5,2,9],
[1,7,4],
[3,6,8]])
a.sort(axis=1) #横向升序
print(a) # [[2 5 9]
# [1 4 7]
# [3 6 8]]
b = np.array([[5,2,9],
[1,7,4],
[3,6,8]])
b.sort(axis=0) #纵向升序
print(b) # [[1 2 4]
# [3 6 8]
# [5 7 9]]
np.argsort(arr) ---- 获取排序后的索引,返回排序后的索引组成的数组。用axis控制横向还是纵向。
c = np.array([[5,2,9],
[1,7,4],
[3,6,8]])
print(np.argsort(c,axis=0)) #[[1 0 1]
# [2 2 2]
# [0 1 0]] 返回纵向升序的索引数组
10 numpy数组的去重和重复
(1)numpy数组去重
np.unique(arr) --- 返回数组中所有元素唯一值(有点像集合,每个元素只能出现一次);(去重功能)
arr1 = np.array([[1,2,1],
[3,3,5],
[4,4,9]])
print(np.unique(arr1)) # [1 2 3 4 5 9] 重复的元素只保留一个
(2) numpy数组重复
比较冷门的功能在numpy里面算是
np.tile(arr,reps) --- 用于将数组沿指定的轴方向重复。(整块重复功能)
它可以用于在数组中创建重复的模式。(整块重复功能)具体参数含义看下面例子才好理解;
有点像列表用法 [1,2,3]*3 = [1,2,3,1,2,3,1,2,3]
arr2 = np.array([1,2,3])
print(np.tile(arr2,3)) #可以看到直接横向重复了三次 [1,2,3,1,2,3,1,2,3]
arr3 = np.array([[1,2],
[3,4]])
print(np.tile(arr3,(2,3))) #可以看到列重复了3次,行重复了2次 [[1,2,1,2,1,2],
# [3,4,3,4,3,4],
# [1,2,1,2,1,2],
# [3,4,3,4,3,4]]
np.repeat() --- 同样也是重复(单个元素依次重复)
arr4 = np.array([1,2,3])
print(np.repeat(arr4,3)) # 不是上面那种整块重复了 [1,1,1,2,2,2,3,3,3]
arr5 = np.array([[1,2],
[3,4]])
print(np.repeat(arr5,3,axis=0)) # 按行重复 [1,2] 3次,[3,4] 3次
# [[1,2],
# [1,2],
# [1,2],
# [3,4],
# [3,4],
# [3,4]]
三 numpy数组的矩阵运算与统计函数
1 逐点相乘(点乘)---- * 和np.multiply()
【注】:逐点乘的没什么好说的,只有一个广播机制要注意,这个要在编程中不断训练才会逐渐理解。另外逐点的加减乘除广播参考博客广播机制说明(讲的特别好,一看就懂)
arr1*arr2
np.multiply(arr1, arr2)
a = np.array([[1,2],
[3,4]])
b = np.array([[5,6],
[7,8]])
print(a*b)
print(np.multiply(a,b)) # [ [ 5 12]
# [21 32] ]
2 矩阵乘法
【注】:关于矩阵乘法的 dot 和 matmul的用法个人是记官方文档的那几个典型情况。不满足矩阵乘法规律,在高维也能广播机制实现相乘。特别注意这种广播机制和前面的逐点广播机制不一样,通常来说广播机制就是专门指代逐点的加减乘除的运算。在矩阵乘法里面我是没有看见官方文档说明了广播。关于它高维怎么广播的,个人感觉它应该是通过if else实现的,也就是说没有一定的规律,只能通过一个一个if else 记(我猜的,因为官方文档介绍就是if else给出的,也没给一个统一规律)。所以下面几个我也是用if else 用法给出。
np.dot(a,b) --- 主要用于向量内积
主要是计算向量内积,当然也支持矩阵乘法(不过矩阵乘法专业的事情还是交给专门的函数np.matmul()去做)------ 官方文档中有这句话哈哈,我的建议是今后np.dot()仅用来计算向量内积即可。
(1)两个标量
a = np.array(2)
b = np.array(5)
print(type(a))
print(np.dot(a,b),type(np.dot(a,b)))
输出:
(2)两个向量
a = np.array([2,3,4])
b = np.array([5,6,7])
print(np.dot(a,b),type(np.dot(a,b)))
输出:
(3)一个二维矩阵,一个向量
a = np.array([[2,3,4],
[4,5,6]])
b = np.array([5,6,7])
print(np.dot(a,b),type(np.dot(a,b)))
输出:
【注】:如果是向量乘以矩阵,那就要看是否满足数学上的矩阵乘法规则了。
(4)两个二维数组 ---- 正常的矩阵乘法
a = np.array([[2,3],
[4,5]])
b = np.array([[5,6],
[7,8]])
print(np.dot(b,a),type(np.dot(a,b)))
输出:
(5)高维
真要用乖乖看官方文档去吧,数学上也没有这种用法。真正工程上要用到去慢慢研究吧,哈哈哈哈哈哈!
np.matmul() 与 @ ---- 专门的矩阵乘法
向量内积,矩阵乘法,当然主要是矩阵乘法,专业干矩阵乘法的函数。@与其是等价的
(1)两个向量
a = np.array([2,3,4])
b = np.array([2,2,2])
print(np.matmul(b,a),type(np.dot(a,b)))
输出:
(2)一个二维矩阵,一个向量
a = np.array([[2,3,4],
[4,5,6]])
b = np.array([5,6,7])
print(np.matmul(a,b),type(np.dot(a,b)))
输出:
【注】:如果是向量乘以矩阵,那就要看是否满足数学上的矩阵乘法规则了。
(3)两个二维矩阵
a = np.array([[1,2],
[3,4]])
b = np.array([[5,6],
[7,8]])
print(a@b)
print(np.matmul(a,b))
输出:
【注】:专业的事情让专业的来个,np.dot()就专心计算向量内积即可,矩阵乘法交给np.matmul()
(4)高维
乖乖查官方文档去吧
3 转置
arr.T
arr = np.array([[2, 1],
[4, 3]])
print(arr.T) # [[2 4]
# [1 3]]
4 np.linalg模块
(1)np.linalg.inv(arr) --- 求矩阵逆
arr = np.array([[2, 1],
[4, 3]])
print(np.linalg.inv(arr)) # [[1.5 -0.5]
# [ -2. 1. ]]
(2)e, v = np.linalg.eig() -- 计算特征值与特征向量(输入可以是array,也可以是matrix)
--- 特征值 (e): 特征值是一个一维数组,每个元素对应一个特征值。对于实数矩阵,特征值可以是实数或者复数,表示为一个复数,其中实部表示实数部分,虚部为零。
--- 特征向量 (v): 特征向量是一个二维数组,其中每一列对应一个特征向量。特征向量的长度为矩阵的维度,具体向量的数据类型根据矩阵的数据类型而定,可以是整数、浮点数或复数。
A = np.array([[1,-3,3],
[3,-5,3],
[6,-6,4]]) # 这里用np.matrix()生成矩阵也行,e,v返回的还是numpy数组。注意后面验证时运算不同。
e,v = np.linalg.eig(A)
print('特征值:\n',e) # 返回一维数组,每个元素是一个特征值
print('特征向量:\n',v) # 返回二维数组,每一列是一个特征向量
输出:
(3)np.linalg.det(arr) --- 计算行列式的值
(4)求解线性方程组 ax=b
a为n n矩阵,x,b是n 1矩阵 (array,matrix都行)
np.linalg.solve(a,b) --- 返回解x
np.linalg.lstsq(a,b) --- 返回最小二乘解x,余项,a的秩,a的奇异值
a = np.array([[3,1],
[1,2]]) #系数矩阵
b = np.array([[9],
[8]])
print(np.linalg.solve(a,b))
print('-'*100)
print(np.linalg.lstsq(a,b)) #下面出现了警告,一般都是因为Python版本变化引起的,不用管
输出:
(5)计算向量(一维数组)和矩阵的范数
np.linalg.norm(x,ord=None) --- 计算范数,x可以是列表,numpy数组,matrix矩阵,ord指定是 2-范数(向量里面我们熟悉的模长)
向量(一维数组):p-范数
对于 n 维向量 x = (x₁, x₂, …, xₙ),它的 p-范数(记作 ||x||ₚ)可以通过以下公式计算:
$||x||ₚ = (|x₁|^p + |x₂|^p + … + |xₙ|^p)^{1/p}$
其中 |xᵢ| 表示向量 x 的第 i 个元素的绝对值。
m * n 矩阵 F-范数:
矩阵的 F-范数(Frobenius 范数)是一种常见的矩阵范数,它用于衡量矩阵的大小。F-范数的计算方法如下:
对于一个 m × n 的矩阵 A = [aᵢⱼ],它的 F-范数(记作 ||A||ₐₙ𝐸𝑓)可以通过以下公式计算:
||A||ₐₙ𝐸𝑓 = sqrt(∑(∑|aᵢⱼ|²))
其中,∑(∑|aᵢⱼ|²) 表示对矩阵 A 中每个元素绝对值的平方求和,并且最后取平方根。
a = np.array([1,2,3,4])
print(np.linalg.norm(a,ord=3)) # 向量的 3-范数
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 计算 F-范数
F_norm = np.linalg.norm(A, ord='fro') # 注意这里 ord='fro'才是F范数。还有‘nuc’是核范数等
print("F-范数:", F_norm)
输出:
(6)np.linalg.svd(arr) --- 奇异值分解(SVD)--- 看高代书就知道了
# 创建一个示例矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 进行奇异值分解
U, S, Vt = np.linalg.svd(A)
# 输出分解后的结果
print("U矩阵:")
print(U)
print("奇异值:")
print(S)
print("V转置矩阵:")
print(Vt)
输出:
5 np.corrcoef(arr) ---- 计算变量间相关系数矩阵
假设有以下数据:
data = np.array([[170,165,180,160], # 在numpy数组里面每一个[]内储存一个变量的信息。这点与pandas有表头不一样
[65,60,70,55],
[25,35,28,40]])
print(np.corrcoef(data))
输出:
6 numpy中各种统计函数
对axis参数的总结:这里说的是二维数组,一维数组不用这个参数
--- 第一种情况:有行维度或者列维度变化,就按照变化的来;行维度变化:axis=0;列维度变化:axis=1.这里的变化是指行数的增加或者减少
--- 第二种情况:下面的函数都是,二维数组的行数列数都没发生变化。横向:axis=1;纵向:axis=0
np.min()或者arr.min()
np.max()或者arr.max()
np.mean()或者arr.mean() --- 平均值
np.sum()或者arr.sum() --- 求和
np.std()或者arr.std() --- 标准差
np.var(x)或者arr.var() --- 方差 方差(Variance)衡量的是单个随机变量的分散程度。
np.cumsum()或者arr.cumsum() --- 计算所有元素累计和
以上的一维数组没有axis,二维数组:axis=0行维,axis=1列维
np.cov(x,y) --- 协方差 协方差(Covariance)衡量的是两个随机变量之间的关系。
a = np.array([[1,2,1],
[2,3,2],
[3,4,3]])
print(np.max(a,axis = 1)) #横向最大值 [2 3 4]
print(a.max(axis =1)) #横向最大值 [2 3 4]
print(np.max(a,axis = 0)) #纵向最大值 [3 4 3]
print(np.std(a,axis = 1)) #横向标准差 [0.47140452 0.47140452 0.47140452]
print(a.std(axis = 1)) #横向标准差 [0.47140452 0.47140452 0.47140452]
print(np.var(a,axis = 1)) #横向方差 [0.22222222 0.22222222 0.22222222]
print(a.var(axis = 1)) #横向方差 [0.22222222 0.22222222 0.22222222]
print(np.cumsum(a,axis = 1)) #横向累加 [[1 3 4]
# [2 5 7]
# [3 7 10]]
print(a.cumsum(axis = 1)) #横向累加 [[1 3 4]
# [2 5 7]
# [3 7 10]]
四 numpy数组的操作 --- 索引、访问、切片、布尔布尔数组进行索引、整数数组进行索引
1 一维数组的索引访问
arr = np.array([1, 2, 3, 4, 5])
print(arr[0]) # 1
print(arr[2:4]) # [3,4]
2 多维数组的索引访问
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(arr[0]) # [1 2 3]
print(arr[1][2]) # 6
print(arr[0, 1]) # 2
print(arr[:, 1]) # [2 5]
3 使用布尔数组进行索引访问
一维数组
arr = np.array([1, 2, 3, 4, 5])
mask = arr > 2
print(mask) # 输出 [False False True True True]
print(arr[mask]) # 输出大于2的元素 [3 4 5]
多维数组
arr = np.array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]])
mask = arr > 2
print(mask) # 输出 [[False False True True True]
# [False False True True True]]
print(arr[mask]) # 输出大于2的元素 [3 4 5 3 4 5]
4 使用整数数组进行索引访问
一维数组
arr = np.array([1, 2, 3, 4, 5])
index = [0, 1, 4] # 这里也可以换成 np.array([0,1,4])
print(arr[index]) # [1 2 5]
多维数组
arr = np.array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[2, 2, 2, 2, 2]])
print(arr[[0,2]]) # [[1 2 3 4 5]
# [2 2 2 2 2]] 访问第0行和第2行
print(arr[[0,1,2],2]) # [3 3 2] 访问(0,2) (1,2) (2,2) 三个元素
print(arr[[0,1,2],[0,2,4]]) # [1 3 2] 访问(0,0) (1,2) (2,4) 三个元素
5 使用访问修改元素
修改一维数组中的元素值
arr = np.array([1, 2, 3, 4, 5])
arr[2] = 10
print(arr) # [ 1 2 10 4 5]
修改多维数组中的元素值
arr = np.array([[1, 2, 3],
[4, 5, 6]])
arr[1, 2] = 10
print(arr) # [[ 1 2 3]
# [ 4 5 10]]
arr = np.array([[1, 2, 3,4],
[4, 5, 6,7],
[7, 8, 9,1],
[15,23,56,9]])
arr[1:3,2:]=[[99,99],[99,99]] #修改多个元素
print(arr) # [[ 1 2 3 4]
# [ 4 5 99 99]
# [ 7 8 99 99]
# [15 23 56 9]]
使用布尔数组进行条件修改
arr = np.array([1, 2, 3, 4, 5])
mask = arr > 2
arr[mask] = 10 # 将大于2的元素都修改为10
print(arr) # [ 1 2 10 10 10]
arr = np.array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]])
arr[arr > 2] = 0
print(arr) # [[1 2 0 0 0]
# [1 2 0 0 0]]
使用整数数组进行修改
arr = np.array([1, 2, 3, 4, 5])
indices = np.array([0, 2, 4])
arr[indices] = 10 # 将索引为0、2、4的元素都修改为10
print(arr) # [10 2 10 4 10]
五 numpy数组的保存与读取
1 保存成二进制文件和二进制文件的读取
np.save(‘tmp’,arr) --- 将数组以二进制文件形式保存到当前文件夹下
运行后当前文件夹会生成tmp.npy的二进制文件
np.savez('tmp2',arr1,arr2) --- savez函数可以将多个数组保存到一个文件中
将两个数组储存到同一个二进制文件中。运行后再当前文件夹会生成tmp2.npz文件
np.load(‘tmp.扩展名’) --- 可以读取上面存储的二进制文件
存储时可以省略扩展名,但读取时不能省略扩展名。
arr1 = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
arr2 = np.array([[1,1,1],
[2,2,2],
[3,3,3]])
np.save('tmp',arr1)
data1 = np.load('tmp.npy')
print(data1)
print('-'*100)
np.savez('tmp2',arr1,arr2)
data2 = np.load('tmp2.npz')
print(data2) #可以看到多个数组就是一个对象了,要单独访问
print(data2.files) #可以用data.files属性查看保存数组的变量名称。这里可以看到是arr_0,arr_1。一般保存过后的变量名称都会变成这种形式
print(data2['arr_0']) #直接这样访问就可以了
输出:
2 保存成(txt,csv,xlsx等)常见文件和常见数据文件的读取
np.savetxt("test1.txt", arr, delimiter=",")
savetxt函数是将数组写到某种分隔符隔开的文本文件中。
np.loadtxt("arr1.txt",delimiter=",")
loadtxt函数执行的是把文件加载到一个二维数组中。
np.genfromtxt("arr8.txt", delimiter = ",")
genfromtxt也是把文件加载到一个二维数组中,但其可以面向的是结构化数组和缺失数据。
【注】:txt,csv,xlsx等都是用上面三个函数,使用的参数稍微有所不同罢了。
2.1 txt
a = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
np.savetxt('test1.txt',a, delimiter=',')
#这里必须加txt后缀才能保存成txt文件类型;后面那个参数最好加上用逗号分割开。运行后就能在当前文件夹下创建 test1.txt文件了
data1 = np.loadtxt("test1.txt",delimiter=',') #加载刚保存的 test1.txt文件
print(data1)
print(type(data1)) #可以看到数据类型是numpy数组
data1_1 = np.loadtxt("test1.txt",delimiter=',',unpack=True) # unpack 这个参数就是读取的时候转置一下
print(data1_1)
print('-'*100)
data2 = np.genfromtxt("test1.txt", delimiter = ",")
print(data2)
print(type(data2))
print('-'*100)
##其实有函数里面有参数dtype可以控制数组里面元素的数据类型
data1_2 = np.loadtxt("test1.txt",delimiter=',',dtype=np.int32) #版本变化有警告不用管
print(data1_2)
print(type(data1_2))
输出:
2.2 csv
需要注意的是csv文件虽然大多用Excel表格打开,其实本质是文本文件。里面的分隔符:逗号或者空格用Excel变成竖线了而已。所以最好也要加上参数 delimiter = "或者"delimiter = " "
用记事本打开csv文件就能看到csv文件原本的样子
### csv 用逗号分割的例子
a = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
np.savetxt('test2.csv',a, delimiter=',')
#这里必须加csv后缀才能保存成csv文件类型;后面那个参数最好加上用逗号分割开。运行后就能在当前文件夹下创建 test2.csv文件了
data1 = np.loadtxt("test2.csv",delimiter=',') #加载刚保存的 test2.txt文件
print(data1)
print(type(data1)) #可以看到数据类型是numpy数组
print('-'*100)
data2 = np.genfromtxt("test2.csv", delimiter = ",")
print(data2)
print(type(data2))
print('-'*100)
##其实有函数里面有参数dtype可以控制数组里面元素的数据类型
data1_1 = np.loadtxt("test2.csv",delimiter=',',dtype=np.int32) #版本变化有警告不用管
print(data1_1)
print(type(data1_1))
输出:
### csv 用空格分割的例子
a = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
np.savetxt('test2_1.csv',a, delimiter=' ')
data1 = np.loadtxt("test2_1.csv",delimiter=' ') #加载刚保存的 test2_1.txt文件
print(data1)
print(type(data1)) #可以看到数据类型是numpy数组
print('-'*100)
data2 = np.genfromtxt("test2_1.csv", delimiter = " ")
print(data2)
print(type(data2))
print('-'*100)
##其实有函数里面有参数dtype可以控制数组里面元素的数据类型
data1_1 = np.loadtxt("test2_1.csv",delimiter=' ',dtype=np.int32) #版本变化有警告不用管
print(data1_1)
print(type(data1_1))
输出:
2.3 xlsx,xls(老版本的)文件
a = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
np.savetxt('test3.xlsx',a) #xlsx文件分割符就可以不要了
#这里必须加xlsx后缀才能保存成xlsx文件类型;后面那个参数最好加上用逗号分割开。运行后就能在当前文件夹下创建 test3.xlsx文件了
data1 = np.loadtxt("test3.xlsx") #加载刚保存的 test3.xlsx文件
print(data1)
print(type(data1)) #可以看到数据类型是numpy数组
print('-'*100)
data2 = np.genfromtxt("test3.xlsx")
print(data2)
print(type(data2))
print('-'*100)
##其实有函数里面有参数dtype可以控制数组里面元素的数据类型
data1_1 = np.loadtxt("test3.xlsx",dtype=np.int32) #版本变化有警告不用管
print(data1_1)
print(type(data1_1))
输出:
六 numpy统计分析实际案例
练习1:鸢尾花统计案例
data = np.loadtxt("iris_sepal_length.csv") #大部分情况下分隔符参数可以不要。实在要用可以用记事本打开看看。这里每一行只有一个数据,没有分隔符
print(data) #单独一列返回了一个一维numpy数组
print(type(data))
输出:
data.sort() #原地排序
print(data)
输出:
new_data = np.unique(data) #去重
print(new_data)
输出:
print(new_data.sum()) #求和
print(new_data.cumsum()) #累计和
print(new_data.mean())# 均值、
print(new_data.std())# 标准差、
print(new_data.var())# 方差、
print(new_data.min())# 最小值、
print(new_data.max())# 最大值
输出:
练习2:np.nan的认识与处理
在实际数据中经常出现一些空值,0除以0等情况,读取进来会用 nan替代,我们需要进行进一步出来
1 关于np.nan的一些注意事项
2 关于处理np.nan的编程练习
(1)将数组内某些元素修改为nan
### 将数组内某个元素替换成 nan
arr = np.array([[1,2,3],
[4,4,7],
[4,7,9]])
# arr[2,2] = np.nan #报错,cannot convert float NaN to integer;因为 nan 是浮点型数据。
# print(arr)
arr_float = arr.astype(float)
print(arr_float)
arr_float[2,2] = np.nan #这样就可以将最后一个元素替换成 nan了
print(arr_float)
输出:
(2)统计 nan 的个数
np.count_nonzero() ---- 函数用于计算数组中非零元素的个数。它接受一个数组作为参数,并返回非零元素的数量。
np.isnan() --- 函数用于检查数组中的元素是否为 NaN(Not a Number)
## np.count_nonzero() 函数
arr = np.array([[0, 1, 0],
[2, 3, 0],
[0, 0, 4]])
# 计算非零元素的个数
count = np.count_nonzero(arr)
print(count) # 4
## np.nan != np.nan 返回True的用法
print(np.nan != np.nan)
arr = np.array([[0, 1, 0],
[2, 3, 0],
[0, np.nan, 4]],dtype = float)
print(arr != arr) #利用数组的布尔运算;只有 np.nan返回了True
count = np.count_nonzero(arr != arr) #这样就可以统计 nan 的数量了
print(count)
## np.isnan()
rr = np.array([1, np.nan, 3, np.nan, 5])
# 检查数组中的元素是否为 NaN
print(np.isnan(rr)) #返回的是布尔数组
count = np.count_nonzero(np.isnan(rr)) #这样就可以统计 nan 的数量了。两种方法都可以统计nan的数量
print(count)
输出:
(3)案例,将数据中nan用平均值替代(这里写了两个函数)
前面讲了这么多都是为了这个实际操作
将任意数组中的 nan 用平均值替代 --- 数据处理里面的常见操作(这里是numpy里面操作,pandas里面也有类似操作)
关于变量名怎么取:temp --- 当前,临时工(一般用于遍历不断变要的变量名这么取);col(column)表示列的意思;row表示行。以后可以这样取变量名
### 纵向填充均值
def fill_col_ndarry(arr):
## 下面将上述数组里的 nan 用每列的平均值替代
for i in range(arr.shape[1]): #shape属性是一个元组,遍历列数
temp_col = arr[:,i] #取当前列的数组
nan_num = np.count_nonzero(np.isnan(temp_col)) #统计当前列 nan的个数
if nan_num != 0: #说明当前列有 nan
temp_not_nan_col = temp_col[temp_col == temp_col]
#用array布尔运算取出相等的元素。
#由于nan!=nan因此可以去除nan。temp_col == temp_col返回的是一个布尔数组,将布尔数组中True的元素拿出来组成新数组
temp_col[np.isnan(temp_col)]=np.mean(temp_not_nan_col)
#np.isnan(temp_col)返回的是一个布尔数组,再用布尔运算修改元素的值。在array中修改切片视图,同样会修改原数组
return arr
#下面是函数测试代码:
if __name__ == '__main__':
a = np.array([[1,2,3,4],
[5,6,np.nan,9],
[np.nan,5,4,np.nan],
[9,7,6,8]],dtype= np.float32)
print(a)
print(fill_col_ndarry(a))
### 横向填充均值
def fill_row_ndarry(arr):
## 下面将上述数组里的 nan 用每行的平均值替代
for i in range(arr.shape[0]): #shape属性是一个元组,遍历列数
temp_row = arr[i,:] #取当前列行数组
nan_num = np.count_nonzero(np.isnan(temp_row)) #统计当前行 nan的个数
if nan_num != 0: #说明当前行有 nan
temp_not_nan_row = temp_row[temp_row == temp_row]
#用array布尔运算取出相等的元素。
#由于nan!=nan因此可以去除nan。temp_row == temp_row返回的是一个布尔数组,将布尔数组中True的元素拿出来组成新数组
temp_row[np.isnan(temp_row)]=np.mean(temp_not_nan_row)
#np.isnan(temp_row)返回的是一个布尔数组,再用布尔运算修改元素的值。在array中修改切片视图,同样会修改原数组
return arr
#下面是函数测试代码:
if __name__ == '__main__':
a = np.array([[1,2,3,4],
[5,6,np.nan,9],
[np.nan,5,4,np.nan],
[9,7,6,8]],dtype= np.float32)
print(a)
print(fill_row_ndarry(a))
输出:
总结
写的很详细了,关于numpy数组的用法,这里也是作为一个个人的查阅文档记录。