数据处理三剑客——Numpy

NumPy(Numerical Python)是Python科学计算的基石,提供高性能多维数组对象ndarray及数学运算函数库。其核心优势在于:

  1. 高效存储:同类型数据连续存储,减少内存占用。
  2. 向量化运算:无需显式循环即可完成批量操作。
  3. 广播机制:支持不同形状数组间的自动扩展计算。

一、NumPy库的安装

使用pip安装Nunpy库的安装命令代码如下所示:

#pip方式安装Numpy库

#默认安装最新版本

pip install numpy

#安装指定的版本

pip install numpy==1.18.5

#使用国内镜像源进行安装

pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

目前国内常用的一些Python第三方库镜像源如下所示:

  1. 清华大学镜像源:https://pypi.tuna.tsinghua.edu.cn/simple/。
  2. 阿里云镜像源:Simple Index
  3. 华为云镜像源:https://mirrors.huaweicloud.com/repository/pypi/simple/
  4. 网易镜像源:https://mirrors.163.com/pypi/simple/
  5. 豆瓣镜像源:https://pypi.douban.com/simple/
  6. 百度云镜像源:https://mirror.baidu.com/pypi/simple/
  7. 中国科技大学镜像源:Verifying - USTC Mirrors

二、列表与数组的区别

Numpy模块最重要的特征是ndarray对象,是一个N维数组。数组的概念在C++、Java等编程语言中存在,但是在Python内置的数据类型中没有数组这种对象,不过存在一个比较相似的列表对象。数组与列表的差异主要体现在以下几个方面:

  1. 列表中可以存放任意数据类型的元素。
  2. ndarray数组中仅能存放相同数据类型的元素。
  3. 列表在内存中占用的空间较大,因为需要为每个元素存储额外的信息(元素引用、元素类型等)。并且由于列表的灵活性,其内存分配不是连续的,会影响对元素的访问速度。
  4. ndarray对象由于所有元素类型相同,且内存分配连续,因此访问速度非常快。在内存中采用紧凑的存储方式,减少了内存占用。此外,ndarray底层使用C语言编写,进一步提高了运算性能(C语言是公认的运行效率最高的语言,大多数情况下需要较高运行效率的底层设计都是通过C语言编写的)。
  5. ndarray对象支持高效的元素级运算,包括与标量的运算和数组之间的矢量化运算。此外,ndarray还支持广播机制,允许不同维度的数组进行运算。
  6. 列表支持基本的元素级运算,但通常需要通过循环结构逐个处理元素,对于大规模数据处理效率较低。列表之间的“相加”操作实际上是连接两个列表,而非元素对元素的相加。

三、数组的构建

1numpy.array()方式创建数组:

# 导入numpy模块
import numpy as np

# 创建一个Python列表
py_list=[1,20,3,25,7,33]
# numpy.array()方式创建数组 将列表转化为数组
np_array=np.array(py_list)

print(f"这是一个Python列表,类型为{type(py_list)},列表为{py_list}")
print(f"这是一个ndarray数组,类型为{type(np_array)},数组为{np_array}") 

2)创建特殊值数组:

1.创建填充值全为0的数组

# 一维零数组

zeros_1d = np.zeros(5)  # [0., 0., 0., 0., 0.]

# 二维零矩阵

zeros_2d = np.zeros((3, 4))  # 3行4列

# 指定数据类型

zeros_int = np.zeros(5, dtype=np.int32)  # [0, 0, 0, 0, 0]# 填充特殊值

2.创建填充值全为1的数组

# 一维全1数组

ones_1d = np.ones(4)  # [1., 1., 1., 1.]

# 三维全1数组 (2x3x4)

ones_3d = np.ones((2, 3, 4))

3.创建填充特定值的数组

# 创建填充特定值的数组

full_arr = np.full((2, 3), 7)  # 2x3数组填充7

# 结构为 [[7, 7, 7],[7, 7, 7]]
# 填充特殊值

nan_arr = np.full((3, 2), np.nan)  # 填充NaN

inf_arr = np.full((2, 2), np.inf)   # 填充正无穷

3.创建单位矩阵

# 3x3单位矩阵

eye_matrix = np.eye(3)

# 结构为 [[1., 0., 0.],[0., 1., 0.],[0., 0., 1.]]
# 偏移对角线

eye_k = np.eye(4, k=1)  # 主对角线向上偏移1位

# 输出 [[0., 1., 0., 0.],[0., 0., 1., 0.],[0., 0., 0., 1.],[0., 0., 0., 0.]]

4.创建空数组

# 创建未初始化的数组(内容为内存中的随机值)

empty_arr = np.empty((2, 3))

# 可能输出:

# [[6.23042070e-307, 4.67296746e-307, 1.69121096e-306],

#  [1.33511562e-306, 1.89146896e-307, 1.78022342e-306]]

四、数组的切片与索引

1)基础索引:

在对数组进行索引操作时,不同维度的数组所需的索引值数量是不同的。简单来讲,每个维度都需要一个对应的索引值来定位数组中的元素。

import numpy as np



# 创建一个一维数组

np_array_1d=np.arange(10)

# 一维数组索引

print(f"数组的正索引,数组{np_array_1d}中的第一个元素是:{np_array_1d[0]}")

print(f"数组的负索引,数组{np_array_1d}中的最后一个元素:{np_array_1d[-1]}")

# 一维数组的切片

# 通过[]方式进行数组的切片

print(f"普通[]方式进行数组的切片,数组{np_array_1d}的一个切片是:{np_array_1d[2:6:2]}")

# 通过内置的slice()函数创建切片对象

section=slice(2,8,2)

print(f"内置函数slice()函数方式进行数组切片,数组{np_array_1d}的一个切片是:{np_array_1d[section]}")



# 创建一个多维数组

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

# 多维数组的索引:

print("___多维数组的索引操作___")

print(f"获取多维数组\n{multi_array_2d}\n中的单个子数组是:\n{multi_array_2d[0]}")

print(f"获取多维数组\n{multi_array_2d}\n中的第二个子数组中的第二个元素:\n{multi_array_2d[1,1]}")

print (f"获取多维数组\n{multi_array_2d}\n中的第二列的元素:\n{multi_array_2d[...,1]}")   # 第2列元素

print (f"获取多维数组\n{multi_array_2d}\n中的第二行的元素:\n{multi_array_2d[1,...]}")   # 第2行元素



# 多维数组的切片:

print("___多维数组的切片操作___")

# 获取多维数组中第一行与第二行中的第二列与第三列的子矩阵

print(f"获取多维数组\n{multi_array_2d}\n中的指定的子矩阵是:\n{multi_array_2d[0:2,1:]}")

# 获取多维数组中所有行的第一列与第二列的子矩阵

print(f"获取多维数组\n{multi_array_2d}\n中所有行的第二列与第三列的子矩阵:\n{multi_array_2d[:,1:]}")

# 获取第一行与第二行中的所有列的子矩阵

print (f"获取多维数组\n{multi_array_2d}\n中第一行与第二行的所有列的子矩阵:\n{multi_array_2d[:2,:]}")

# 获取所行的第一第二列的子矩阵

print (f"获取多维数组\n{multi_array_2d}\n中所有行的所有列的子矩阵:\n{multi_array_2d[...,:]}")

(2)高级索引:

1.整数数组索引

# 整数数组索引
int_array_row=[0,1,2]
int_array_column=[0,1,2]
#获取数组中第一行第一列的元素、第二行第二列的元素、第三行第三列的元素
print(f"通过整数数组索引来访问数组\n{multi_array}\n的元素是
{multi_array[int_array_row,int_array_column]}")

2.花式索引

# 创建一个多维数组
multi_array=np.arange(32).reshape((8,4))#将数组转化为指定形状的数组
# 花式索引  获取第4,2,1,3行的数据
fancy_array=multi_array[[4,2,1,3]]
print(f"通过花式索引来访问数组\n{multi_array}\n的元素是\n{fancy_array}")

3.布尔索引

# 创建一个多维数组
multi_array=np.arange(12).reshape((3,4))#将数组转化为指定形状的数组
# 布尔索引  获取数组中大于5的元素
bool_array=multi_array[multi_array>5]
print(f"通过布尔索引来访问数组\n{multi_array}\n的元素是\n{bool_array}")

五、NumPy库的数组操作与广播机制

(1)数组拼接(Concatenation:

数组拼接的核心思想就是沿着指定的轴(axis)将多个数组连接起来。不同的拼接方向对应不同的axis参数,从而实现按行、按列、按深度等不同维度的组合。

在NumPy中数组的“维度”与“轴”(Axis)如下所示:

  1. 一维数组:shape = (n,) →轴axis=0
  2. 二维数组:shape = (m, n) → axis=0(行),axis=1(列)
  3. 三维数组:shape = (d, m, n) → axis=0(深度块),axis=1(行),axis=2(列)
a = np.array([[1, 2], [3, 4]])

b = np.array([[5, 6]])



# 垂直拼接 沿 axis=0 拼接(垂直方向,增加行数)

v_stack = np.vstack([a, b])

# 输出 [[1 2][3 4][5 6]]



# 水平拼接 沿 axis=1 拼接(水平方向,增加列数)

h_stack = np.hstack([a, a])

# 输出 [[1 2 1 2][3 4 3 4]]



# 深度拼接 沿 axis=2 拼接(深度方向,增加“通道”或“层”)

d_stack = np.dstack([a, a])

# 输出 [[[1 1][2 2]][[3 3][4 4]]]



# 通用拼接

concat = np.concatenate([a, b], axis=0)  # 同vstack

(2)数组变形(Reshaping:

# 创建初始数组
arr = np.array([[1, 2, 3],[4, 5, 6]])

arr_reshaped = arr.reshape((3, 2))
print(arr_reshaped)
# [[1 2][3 4][5 6]]

# 使用 -1 自动推断维度
a.reshape((2, -1))  # → (2,3),-1 表示自动计算
a.reshape((-1,))    # 展平为一维 → (6,)

(3)数组转置(Transpose:

1.使用.T

.T是最简单的转置方式,适用于所有维度的数组,但默认情况下仅对二维数组有效(即简单地交换第一和第二轴)。

# 创建一个 2x3 矩阵

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

print(a.T)

# 输出:

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

2.使用np.transpose()函数

np.transpose()提供了更灵活的方式进行转置操作,允许你指定新的维度顺序。

# 创建二维数组

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

transposed = np.transpose(a)

print(transposed)

# 创建一个 3D 数组 (2, 3, 4)

a_3d = np.arange(24).reshape((2, 3, 4))

print("Original shape:", a_3d.shape)  # (2, 3, 4)

# 转置: 交换第一个和第三个维度

transposed_3d = np.transpose(a_3d, (2, 1, 0))

print("Transposed shape:", transposed_3d.shape)  # (4, 3, 2)

3.使用swapaxes()方法

np.swapaxes()方法用于交换两个特定的轴,这对于快速调整某些维度特别有用。

# 创建一个 3D 数组 (2, 3, 4)

a_3d = np.arange(24).reshape((2, 3, 4))

print("Original shape:", a_3d.shape)  # (2, 3, 4)

swapped = np.swapaxes(a_3d, 0, 2)

print("Swapped axes shape:", swapped.shape)  # (4, 3, 2)

(4)广播机制

广播是NumPy中的一种强大机制,在进行数组间的操作时,可以自动适配不同形状的数组,实现数组之间元素级别的操作。这种机制的出现,可以避免循环操作与显示的扩展数组维度的冗长代码,使数组的操作更加方便,代码更加简洁;广播操作是在数组的内部完成的,要比普通的循环操作执行效率更高;广播可以在不改变原始数组形状的情况下,实行对数组更为复杂的操作,能够有效提升代码的灵活性。

广播的本质是说如果有a、b两个数组形状满足a.shape==b.shape,那么这两个数组进行元素级操作时,例如,a*b的操作结果就是a与b两个数组中对应位置的元素相乘(这里要求两个数组的维度相同,并且每个维度的长度相同)。出于这个限制,如果两个形状不同的数组进行广播操作时,会在自动进行形状的处理,是两个数组的形状保持一致,一般是将低纬度的数组,或者将维度中长度较短的数组进行拉伸至维度中长度最长的数组。

不同数组之间进行广播操作时需要满足以下规则:

  1. 不同数组进行广播时,所有数组都向其中形状最长的数组看齐,形状不足的部分都通过在前面(左侧)补1。例如,a数组是一个二维数组,其形状为a.shape=(3,3);b数组是一个一维数组,其形状为b.shape=(3),这两个数组进行广播操作(例如,a+b),就会按照形状最大的a数组,来补足b数组的形状,使b数组变成一个二维数组结构b.shape=(1,3),然后按照a数组中对应维度长度,来复制b数组保证在这一维度上长度保持一致。这里a数组中对应的维度是行其长度为3,则b数组需要复制的次数为3/1=3次。
  2. 如果两个数组的形状在任何维度上均不匹配,但是其中某一个数组中的某一维度为1,则该维度中形状为1的数组将被拉伸到与另一个数组对应维度的形状相匹配。例如,数组a的形状为a.shape=(3,1),数组b的形状为b.shape=(1,3),这两个数组进行广播操作时,数组a、b的形状会被分别拉伸为a.shape(3,3)与b.shape(3,3)。
  3. 如果两个数组的形状在任何维度上均不匹配,且均没有等于1的维度,那么这两个数组在进行广播操作时无法正确转换,会导致出错。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值