NumPy基础
title: NumPy基础
id: 4b08c353-8924-48d0-acbb-b6dddc8c0bfa
date: 2024-11-03 19:26:36
auther: spike
cover:
excerpt:
permalink: /archives/numpyji-chu
categories:
tags:
1.0 安装 NumPy
!pip install numpy
The history saving thread hit an unexpected error (OperationalError('attempt to write a readonly database')).History will not be written to the database.
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: numpy in /root/anaconda3/envs/pyspark/lib/python3.8/site-packages (1.24.4)
[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable.It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.[0m[33m
[0m
2.0 基础知识
2.1 数组
2.1.1 创建NumPy ndarray 对象
NumPy 用于处理数组 , NumPy中的数组对象称为 ndarray
我们可以使用 array() 函数创建一个NumPy ndarray() 对象
import numpy as np
arr = np.array([1,2,3,4,5])
print(arr)
print(type(arr))
[1 2 3 4 5]
<class 'numpy.ndarray'>
type(): 这个内置的Python函数告诉我们传递给它的对象的类型。像上面的代码一样,它表明arr是 numpy.ndarray类型。
要创建ndarray,我们可以将列表、元组或任何类似数组的对象传递给array()方法,然后它将被转换为ndarray:
任何可以迭代的对象都可以转为ndarray对象
# 使用元组创建 NumPy 数组
arr = np.array((1,3,2,4,5,6,7))
print(arr)
[1 3 2 4 5 6 7]
2.1.2 数组中的维
数组中的维是数组深度 (嵌套的数组)的一个级别
嵌套数组:指的是将数组作为元素的数组
2.1.2.1 0-D数组
0-D 数组 , 或标量(Scalars) , 是数组中的元素。数组中的每个值都是一个0-D数组。
# 用值61创建0-D数组:
arr = np.array(61)
print(arr)
61
2.1.2.2 1-D数组
其中元素为0-D数组的数组 , 称为一维数组 或 1-D数组
这是最常见的基础数组
# 创建包含值 1,2,3,4,5,6 的 1-D 数组:
arr = np.array([1,2,3,4,5,6])
print(arr)
[1 2 3 4 5 6]
2.1.2.3 2-D数组
其元素为1-D数组的数组,称为2-D数组
它们通常用于表示矩阵或二阶张量。
NumPy有一个专门用于矩阵运算的完整子模块numpy.mat
# 创建包含值 1,2,3 和 4,5,6i两个数组的 2-D 数组
arr = np.array([[1,2,3],[4,5,6]])
print(arr)
[[1 2 3]
[4 5 6]]
2.1.2.4 3-D数组
其元素为2-D数组的数组,称为3-D数组
arr = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])
print(arr)
[[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]]
2.1.2.5 检查数组维度
NumPy 数组提供了ndim 属性 , 该属性返回一个整数 , 改整数会告诉我们数组有多少维。
# 检查维度
a = np.array(24)
b = np.array([1,2,3,4,5,6])
c = np.array([[1,2,3],[4,5,6]])
d = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])
e = np.array([[[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]],[[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]]])
print('a`D is', a.ndim, '|', \
'b`D is', b.ndim, '|', \
'c`D is', c.ndim, '|', \
'd`D is', d.ndim, '|', \
'e`D is', e.ndim, \
)
a`D is 0 | b`D is 1 | c`D is 2 | d`D is 3 | e`D is 4
2.1.2.6 更高维的数组
数组可以拥有任意数量的维
创建ndarray 的时候可以加上ndmin参数定义维度
# 创建一个有5维度的数组,并验证它拥有5个维度:
arr = np.array([1,2,3,4],ndmin = 5)
print(arr , '\n' , 'arr.ndim is ',arr.ndim)
[[[[[1 2 3 4]]]]]
arr.ndim is 5
2.1.3 数组索引
2.1.3.1 访问数组元素
数组索引等同于访问数组元素。
您可以通过引用其索引号来访问数组元素。
NumPy数组中的索引以0开头,这意味着第一个元素的索引为0,第二个元素的索引为1,以此类推。
arr = np.array([1,2,3,4])
# 获取元素
print(arr[0] , arr[1] , arr[2]+arr[3])
1 2 7
2.1.3.2 多维数组
在访问使用 逗号 , 去分割元素的维度和索引
例如:[1,2,3] 第一维中的第二个元素 , 第二维中的第二个元素 , 第三维中的第三个元素
arr = np.array([[[[1,1,1],[4,4,4]],[[2,2,2],[5,5,5]]],
# arr[1]
[[[3,3,3],[6,6,6]],
# arr[1,1]
[[7,7,7],
# arr[1,1,1]
[8,8,8]]]])
print('arr[1,1,1] = ' , arr[1,1,1],'\n')
print(arr)
arr[1,1,1] = [8 8 8]
[[[[1 1 1]
[4 4 4]]
[[2 2 2]
[5 5 5]]]
[[[3 3 3]
[6 6 6]]
[[7 7 7]
[8 8 8]]]]
2.1.3.3 负索引
使用负索引从后往前访问数组
arr = np.array([[[[1,1,1],[4,4,4]],[[2,2,2],[5,5,5]]], [[[3,3,3],[6,6,6]], [[7,7,7], [8,6,7]]]])
print('arr[1,1,1,-1] = ' , arr[1,1,1,-1],'\n')
print('arr[1,1,1,1] = ' , arr[1,1,1,1])
arr[1,1,1,-1] = 7
arr[1,1,1,1] = 6
2.1.4 数组裁切
2.1.4.1 裁切数组
python 中裁切的意思是将元素从一个给定的索引带到另一个给定的索引。
我们像这样传递切片而不是索引:[start:end]。
我们还可以定义步长,如下所示:[start: end: step]。
如果我们不传递start,则将其视为0。
如果我们不传递end,则视为该维度内数组的长度。
如果我们不传递step,则视为1.
arr = np.array([1,2,3,4,5,6,7])
# 1~5 step = 1
print(arr[1:5])
# 4~end step = 1
print(arr[4:])
# start~4 step = 1
print(arr[:4])
# 1~5 step = 2
print(arr[1:5:2])
[2 3 4 5]
[5 6 7]
[1 2 3 4]
[2 4]
2.1.4.2 负裁切 和 Step
使用方式和python可迭代对象一样
arr = np.array([1,2,3,4,5,6,7])
# 2~-1(end) step = 1
print(arr[2:-1])
'''
-1(end)~2 step = 1
观察到[](空)输出 , 在step 为正的时候
start > end 区间不是闭合的
区间会被认为什么元素都没有
'''
# -1(end)~2 step = 1
print(arr[-1:2])
'''
当step = -1时候
会从start开始从右向左取值了
会产生一个封闭区间
'''
# -1(end)~2 step = -1
print(arr[-1:2:-1])
[3 4 5 6]
[]
[7 6 5 4]
2.1.4.3 多维数组的 裁切和Step
arr = np.array([[[[1,1,1],[4,4,4]],[[2,2,2],[5,5,5]]], [[[3,3,3],[6,6,6]], [[7,7,7], [8,6,7]]]])
print('arr[1,1,1,::-1] = ' , arr[1,1,1,::-1],'\n')
print('arr[1,1,::-1] = ' , arr[1,1,::-1],'\n')
print('arr[1,1,1,::-1] = ' , arr[1,1,1,::2],'\n')
arr[1,1,1,::-1] = [7 6 8]
arr[1,1,::-1] = [[8 6 7]
[7 7 7]]
arr[1,1,1,::-1] = [8 7]
2.2 数据类型
2.2.1 NumPy数据类型
2.2.1.1 Python 中的数据类型
默认情况下,Python拥有以下数据类型:
- strings -用于表示文本数据,文本用引号引起来。例如"ABCD”.
- integer -用于表示整数。例如-1.-2,-3。
- float-用于表示实数。例如1.2,42.42。
- boolean -用于表示True 或False.
- complex -用于表示复平面中的数字。例如1.0+2.0j,1.5+2.5j。
2.2.1.2 NumPy中的数据类型
NumPy有一些额外的数据类型,并通过一个字符引用数据类型,例如1代表整数,U代表无符号整数等。以下是NumPy中所有数据类型的列表以及用于表示它们的字符。
- i-整数
- b-布尔
- u-无符号整数
- f-浮点
- C-复合浮点数
- m- timedelta
- M - datetime0-对象
- S-字符串
- U-uicode 字符串
- V-固定的其他类型的内存块(void)
- object 兼容所有数据
2.2.1.3 检查数组的数据类型
NumPy数组对象有一个名为dtype的属性 , 该属性返回数组的数据类型:
import numpy as np
arr = np.array([1,2,3,4])
print(arr.dtype)
int64
arr = np.array(['apple','apples'])
# Un n是字符串数组中的maxlen元素的长度
def getmaxlen(arr:list) ->int:
ans = 0
for i in arr:
ans = max(len(i) ,ans)
return ans
print('<U%d'%getmaxlen(arr) ,end = '|')
print(arr.dtype)
<U6|<U6
2.2.1.4 用已定义的数据类型来创建数组
在创建ndarray对象的时候 , 加入参数dtype , 设置元素的预选类型
arr = np.array([1,2,3,40] , dtype = 'S')
# 数据类型其实被封装后的字节数据
print(type(arr[0]))
print(arr)
# |Sn n依旧是显示数组中最长元素的长度
print(arr.dtype)
<class 'numpy.bytes_'>
[b'1' b'2' b'3' b'40']
|S2
2.2.1.5 数组dtype的强类型属性
不同的属性在同一数组中会显示ValueError
arr = np.array(['1',{1}])
# numpy 代理对象的时候 , 会将对象序列化为一个兼容的对象
print(type(arr[1]))
print(type(arr[0]))
print(arr.dtype)
<class 'set'>
<class 'str'>
object
# 指定dtype为numpy的基础数据类型的话会将数据全部转为 字节数据存储
arr = np.array([1,2.123,'ccc'] , dtype = 'S')
print(type(arr[0]))
print(type(arr[1]))
print(type(arr[2]))
print(arr.dtype)
<class 'numpy.bytes_'>
<class 'numpy.bytes_'>
<class 'numpy.bytes_'>
|S5
这种转换在指定dtype , 不会再推断数据类型 , 会依照dtype强转 , 如何无法转换会直接报错
arr = np.array([1,2.123,'ccc'] , dtype = 'i')
print(arr)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[66], line 1
----> 1 arr = np.array([1,2.123,'ccc'] , dtype = 'i')
2 print(arr)
ValueError: invalid literal for int() with base 10: 'ccc'
2.2.1.6 转换已有数组的数据类型
更改现有数组的数据类型的最佳方法,是使用astype()方法复制该数组。
astype()函数创建数组的副本,并允许您将数据类型指定为参数。
数据类型可以使用字符串指定,例如'f'表示浮点数,'i'表示整数等。或者您也可以直接使用数据类型,例如float 表示浮点数,int表示整数。
# 通过使用 ‘i’ 作为参数值 , 将数据类型从浮点数更改为整数
arr = np.array([1.1,2.1,3.1])
coparr = arr.astype('i')
print(coparr)
print(coparr.dtype)
[1 2 3]
int32
# 通过使用 int 作为参数值 , 将数据类型从浮点数更改为整数
arr = np.array([1.1,2.1,3.1])
coparr = arr.astype(int)
print(coparr)
print(coparr.dtype)
[1 2 3]
int64
# 通过使用 bool 作为参数值 , 将数据类型从浮点数更改为bool值
arr = np.array([0,2.1,3.1])
coparr = arr.astype(bool)
print(coparr)
print(coparr.dtype)
[False True True]
bool
2.2.2 NumPy 数组副本vs视图
2.2.2.1 副本和视图之间的区别
副本和数组视图之间的主要区别在于副本是一个新数组,而这个视图只是原始数组的视图。
副本拥有数据,对副本所做的任何更改都不会影响原始数组,对原始数组所做的任何更改也不会影响副本。
视图不拥有数据,对视图所做的任何更改都会影响原始数组,而对原始数组所做的任何更改都会影响视图。
2.2.2.2 副本
arr = np.array([1,2,3,4,5])
x = arr.copy()
arr[0] = 61
print(arr)
print(x)
[61 2 3 4 5]
[1 2 3 4 5]
2.2.2.2 试图
arr = np.array([1,2,3,4,5])
x = arr.view()
arr[0] = 61
print(arr)
print(x)
[61 2 3 4 5]
[61 2 3 4 5]
arr = np.array([1,2,3,4,5])
x = arr.view()
x[0] = 31
print(arr)
print(x)
[31 2 3 4 5]
[31 2 3 4 5]
2.2.2.4 检查数组是否拥有数据
如上所述,副本拥有数据,而视图不拥有数据,但是我们如何检查呢?
每个 NumPy 数组都有一个属性base,如果该数组拥有数据,则这个base属性返回None.
否则,base属性将引用原始对象。
这个base是NumPy的唯一标识或者元数据
arr = np.array([1,2,3,4,5])
x = arr.copy()
y = arr.view()
print(x.base)
print(y.base)
print(arr.base)
# 切片是view , 存储的是逻辑地在
print(arr[::].base)
None
[1 2 3 4 5]
None
[1 2 3 4 5]
2.3 形状
2.3.1 NumPy数组形状
2.3.1.1 数组的形状
数组中的形状是每个维中元素的数量
2.3.1.2 获取数组的形状
NumPy 数组中有一名为shape的属性 , 该属性返回一个元祖 , 每个索引具有相应元素的的数量
import numpy as np
arr = np.array([[1,2,3,4],[5,6,7,8],[5,6,7,8]])
# 返回 (3,4) , 这意味着该数组有2个维
# 第一维有3个元素
# 第二维有4个元素
print(arr.shape)
(3, 4)
arr = np.array([1,2,3,4], ndmin = 5)
print(arr)
print(arr[0,0].shape)
[[[[[1 2 3 4]]]]]
(1, 1, 4)
2.3.2 NumPy数组重塑
2.3.2.1 NumPy数组重塑
重塑意味着更改数组的形状
数组的形状是每个维中元素的数量
通过重塑,我们可以添加或删除维度或更改每个维度中的元素数量
2.3.2.2 从1-D重塑到2-D
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
newarr = arr.reshape(4, 2, 1)
print("Original array:")
print(arr)
print("\nReshaped array:")
print(newarr)
print("\nShape of newarr:", newarr.shape)
print("Number of dimensions of newarr:", newarr.ndim) # 用 ndim 获取维数
Original array:
[1 2 3 4 5 6 7 8]
Reshaped array:
[[[1]
[2]]
[[3]
[4]]
[[5]
[6]]
[[7]
[8]]]
Shape of newarr: (4, 2, 1)
Number of dimensions of newarr: 3
2.3.2.3 重塑形状原则
ndarray.reshape(x1, x2 , …… , xi)
x1 * x2 * …… * xi == arr中0D的元素数量
arr = np.array([[1, 2, 3,4],
[5, 6, 7, 8]])
newarr = arr.reshape(4, 2, 1)
print("Original array:")
print(arr)
print("\nReshaped array:")
print(newarr)
print("\nShape of newarr:", newarr.shape)
print("Number of dimensions of newarr:", newarr.ndim) # 用 ndim 获取维数
Original array:
[[1 2 3 4]
[5 6 7 8]]
Reshaped array:
[[[1]
[2]]
[[3]
[4]]
[[5]
[6]]
[[7]
[8]]]
Shape of newarr: (4, 2, 1)
Number of dimensions of newarr: 3
2.3.2.4 重塑数组是视图
arr = np.array([1,2,3,4,5,6,7,8])
# 返回数组是视图
print(arr.reshape(2,4).base)
[1 2 3 4 5 6 7 8]
2.3.2.5 未知的维
您可以使用一个‘未知’维度
这意味着您不必在reshape方法中为维度之一指定确切的数字
传递 -1 作为值 , NunPy 将为您计算该数字
任意负数都行
arr = np.array([1,2,3,4,5,6,7,8])
```python
newarr = arr.reshape(2,-1,-1)
print(newarr)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[139], line 1
----> 1 newarr = arr.reshape(2,-1,-1)
2 print(newarr)
ValueError: can only specify one unknown dimension
newarr = arr.reshape(2,-1,2)
print(newarr)
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
newarr = arr.reshape(2,1,-3)
print(newarr)
[[[1 2 3 4]]
[[5 6 7 8]]]
2.3.2.7 展开数组
展开数组(Flattening the arrays)是指将多维数组转换1D数组.
我们可以使用reshape(-1)来做到这一点
任意负数都行
arr = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])
newarr = arr.reshape(-1)
print(newarr)
[1 2 3 4 5 6 1 2 3 4 5 6]
2.4 操作(迭代 , 连接 , 拆分 , 排序)
2.4.1 NumPy 数组迭代
2.4.1.1 数组迭代
迭代意味着逐一遍历元素
当我们在numpy 中处理多维数组时,可以使用python 的基本for 循环来完成此操作
如果我们对1-D数组进行迭代,它将逐一遍历每个元素。
import numpy as np
使用基本的迭代方式 for x in arr
arr = np.array([[1,2,3,4],[6,7,8,9]])
for x in arr:
for y in x:
print(y , end = ' ')
1 2 3 4 6 7 8 9
2.4.1.2 使用nditer()迭代数组
函数 nditer() 是一个辅助函数,从非常基本的迭代到非常高级的迭代都可以使用。它解决了我们在迭代中面临的一些基本问题,让我们通过例子进行介绍。
- 迭代每个标量元素
在基本的for循环中,迭代遍历数组的每个标量,我们需要使用n个for循环,对于具有高维数的数组可能很难编写。
arr = np.array([[1,2,3,4],[6,7,8,9]])
for x in np.nditer(arr):
print(x , end = ' ')
1 2 3 4 6 7 8 9
- 迭代不同数据类型的数组
我们可以使用op_dtypes参数,并传递期望的数据类型,以在迭代时更改元素的数据类型。
NumPy 不会就地更改元素的数据类型(元素位于数组中),因此它需要一些其他空间来执行此操作,该额外空间称为buffer,为了在nditer()中启用它,我们传参flags=['buffered']。
arr = np.array([[1,2,3,4],[6,7,8,9]])
for x in np.nditer(arr , flags = ['buffered'] , op_dtypes = ['S']):
print(x , end = ' ')
print()
for x in np.nditer(arr , flags = ['buffered'] , op_dtypes = ['object']):
print(x , end = ' ')
print('\n',arr.dtype)
b'1' b'2' b'3' b'4' b'6' b'7' b'8' b'9'
1 2 3 4 6 7 8 9
int64
2.4.1.3 step步长迭代
arr = np.array([[1,2,3,4],[6,7,8,9]])
for x in np.nditer(arr[::-2]):
print(x , end = ' ')
6 7 8 9
2.4.1.4 使用 ndenumerate()进行枚举迭代
枚举是指逐一提及事物的序号。
有时,我们在迭代时需要元素的相应索引,对于这些用例,可以使用ndenumerate()方法。
- idx is set
- x is object of element
arr = np.array([[1,2,3,4],[6,7,8,9]])
for idx , x in np.ndenumerate(arr):
print(idx,x)
(0, 0) 1
(0, 1) 2
(0, 2) 3
(0, 3) 4
(1, 0) 6
(1, 1) 7
(1, 2) 8
(1, 3) 9