Python——numpy库使用

本文详细介绍了NumPy库,包括ndarray的高效运算、与Python原生list的性能对比、数组属性和类型、数组生成、索引切片、形状更改、类型转换、去重方法、逻辑和统计运算、以及矩阵操作。强调了NumPy在科学计算中的优势,如并行化运算和广播机制,展示了如何利用NumPy进行高效的数组操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

部分资料整理来自互联网,如有侵权,请联系删除!

1 Numpy介绍

Numpy(Numerical Python)是一个开源的Python科学计算库,用于快速处理任意维度的数组
Numpy支持常见的数组和矩阵操作。对于同样的数值计算任务,使用Numpy比直接使用Python要简洁的多。
Numpy使用ndarray对象来处理多维数组,该对象是一个快速而灵活的大数据容器。

NumPy提供了一个N维数组类型ndarray,它描述了相同类型的“items”的集合。

2 ndarray与Python原生list运算效率对比

import random
import time
import numpy as np

a = []
for i in range(100000000):
    a.append(random.random())
b = np.array(a)

tis1 = time.perf_counter()
sum1 = sum(a)
tis2 = time.perf_counter()
print(tis2 - tis1)		# 0.5100450999999993 s

tis3 = time.perf_counter()
sum2 = np.sum(b)
tis4 = time.perf_counter()
print(tis4 - tis3)		# 0.10293670000000077 s

从上述结果可以看出ndarray的计算速度要比原生list快很多,节约了时间。
Numpy专门针对ndarray的操作和运算进行了设计,所以数组的存储效率和输入输出性能远优于Python中的嵌套列表,数组越大,Numpy的优势就越明显。

ndarray与Python的内存区别

在这里插入图片描述
从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。

这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。

ndarray支持并行化运算(向量化运算)

numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算

效率远高于纯Python代码

Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。

3 N维数组-ndarray的属性、类型

数组属性反映了数组本身固有的信息。

属性名字属性解释
ndarray.shape数组维度的元组
ndarray.ndim数组维数
ndarray.size数组中的元素数量
ndarray.itemsize一个数组元素的长度(字节)
ndarray.dtype数组元素的类型

dtype是numpy.dtype类型,先看看对于数组来说都有哪些类型

名称描述简写
np.bool用一个字节存储的布尔类型(True或False)‘b’
np.int8一个字节大小,-128 至 127‘i’
np.int16整数,-32768 至 32767‘i2’
np.int32整数,-2^31​ 至 2^32 -1‘i4’
np.int64整数,-2^63 至 2^63 - 1‘i8’
np.uint8无符号整数,0 至 255‘u’
np.uint16无符号整数,0 至 65535‘u2’
np.uint32无符号整数,0 至 2^32 - 1‘u4’
np.uint64无符号整数,0 至 2^64 - 1‘u8’
np.float16半精度浮点数:16位,正负号1位,指数5位,精度10位‘f2’
np.float32单精度浮点数:32位,正负号1位,指数8位,精度23位‘f4’
np.float64双精度浮点数:64位,正负号1位,指数11位,精度52位‘f8’
np.complex64复数,分别用两个32位浮点数表示实部和虚部‘c8’
np.complex128复数,分别用两个64位浮点数表示实部和虚部‘c16’
np.object_python对象‘O’
np.string_字符串‘S’
np.unicode_unicode类型‘U’
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)
print(type(a.dtype))
b = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
print(type(b.dtype))
c = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint64)
print(type(c.dtype))
arr = np.array(['python', 'tensorflow', 'scikit-learn', 'numpy'], dtype=np.string_)
print(type(arr.dtype))

打印结果

<class 'numpy.dtype[int32]'>
<class 'numpy.dtype[float32]'>
<class 'numpy.dtype[uint64]'>
<class 'numpy.dtype[bytes_]'>

4 基本操作

4.1 生成数组的方法

4.1.1 生成0和1的数组

  • np.ones(shape, dtype)
  • np.ones_like(a, dtype)
  • np.zeros(shape, dtype)
  • np.zeros_like(a, dtype)
import numpy as np

ones = np.ones([4, 8])
print(ones)
print(type(ones.dtype))

输出结果;

[[1. 1. 1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1. 1. 1. 1.]]
<class 'numpy.dtype[float64]'>
arr0 = np.zeros_like(ones)
print(arr0)

输出结果:

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

4.1.2 从现有数组创建

  • np.array(object, dtype)
  • np.asarray(a, dtype)
a = np.array([[1,2,3],[4,5,6]])
# 从现有的数组当中创建
a1 = np.array(a)
# 相当于索引的形式,并没有真正的创建一个新的
a2 = np.asarray(a)

4.1.3 生成固定范围的数组

  1. np.linspace (start, stop, num, endpoint)
  • 创建等差数组 — 指定数量
  • 参数:
    • start:序列的起始值
    • stop:序列的终止值
    • num:要生成的等间隔样例数量,默认为50
    • endpoint:序列中是否包含stop值,默认为ture
# 生成等间隔的数组
arr = np.linspace(0, 100, 11)
print(arr)
print(type(arr.dtype))

输出结果:

[  0.  10.  20.  30.  40.  50.  60.  70.  80.  90. 100.]
<class 'numpy.dtype[float64]'>
  1. np.arange(start,stop, step, dtype)
  • 创建等差数组 — 指定步长
  • 参数
    • step:步长,默认值为1
import numpy as np

arr = np.arange(10, 50, 2)
print(arr)
print(type(arr.dtype))

输出结果:

[10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48]
  1. np.logspace(start,stop, num)
  • 创建等比数列
  • 参数:
    • num:要生成的等比数列数量,默认为50
import numpy as np

# 生成10^x
arr = np.logspace(0, 2, 3)
print(arr)

输出结果:

[  1.  10. 100.]

4.2 生成随机数组

4.2.1 正态分布数组的创建

np.random.normal(loc=0.0, scale=1.0, size=None)

  • loc:float
    ​ 此概率分布的均值(对应着整个分布的中心centre)
  • scale:float
    ​ 此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)
  • size:int or tuple of ints
    ​ 输出的shape,默认为None,只输出一个值

np.random.standard_normal(size=None)
返回指定形状的标准正态分布的数组。
举例1:生成均值为1.75,标准差为1的正态分布数据,100000000个

import numpy as np
import matplotlib.pyplot as plt

# 生成均匀分布的随机数
x1 = np.random.normal(1.75, 1, 100000000)

# 画图看分布状况
# 1)创建画布
plt.figure(figsize=(20, 10), dpi=100)

# 2)绘制直方图
plt.hist(x1, 1000)

plt.savefig('正态分布')
plt.show()

在这里插入图片描述
举例2:随机生成4支股票1周的交易日涨幅数据
4支股票,一周(5天)的涨跌幅数据,如何获取?
随机生成涨跌幅在某个正态分布内,比如均值0,方差1

import numpy as np
import matplotlib.pyplot as plt

# 创建符合正态分布的4只股票5天的涨跌幅数据
stock_change = np.random.normal(0, 1, (4, 5))
print(stock_change)

输出结果:

[[ 1.22734959 -0.41777309  0.04959992  1.5641782   0.43955707]
 [-0.49038968  0.78217284 -1.21057746  0.39667994  1.72735159]
 [-1.73632401  1.35846879 -0.08518953  1.55987208 -2.17242078]
 [-0.0388011   0.81747545  1.63337823 -0.45251437 -2.06338529]]

4.2.1 均匀分布数组的创建

np.random.rand(d0, d1, …, dn)

  • 返回[0.0,1.0)内的一组均匀分布的数。

np.random.uniform(low=0.0, high=1.0, size=None)

  • 功能:从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high.
  • 参数介绍:
    • low: 采样下界,float类型,默认值为0;
    • high: 采样上界,float类型,默认值为1;
    • size: 输出样本数目,为int或元组(tuple)类型,例如,size=(m,n,k), 则输出mnk个样本,缺省时输出1个值。
  • 返回值:ndarray类型,其形状和参数size中描述一致。

np.random.randint(low, high=None, size=None, dtype=‘l’)

  • 从一个均匀分布中随机采样,生成一个整数或N维整数数组,
  • 取数范围:若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数。
    在这里插入图片描述

4.3 数组的索引、切片

一维、二维、三维的数组如何索引?

  • 直接进行索引,切片
  • 对象[:, :] – 先行后列

二维数组索引方式:

  • 举例:获取第一个股票的前3个交易日的涨跌幅数据
import numpy as np
import matplotlib.pyplot as plt

# 创建符合正态分布的4只股票5天的涨跌幅数据
stock_change = np.random.normal(0, 1, (4, 5))
print(stock_change)
# 二维的数组,两个维度
print('----------------------')
print(stock_change[0, 0:3])

输出结果:

[[ 0.05022887  0.92500764 -1.58576621 -0.57955611 -0.16145544]
 [ 2.12628075  0.58135125  1.44841144  0.0024432  -1.39830066]
 [ 0.05838038 -0.15133336 -0.59098923 -1.07909054 -0.90791572]
 [-1.13899116  0.02915346 -1.15171836  0.39317151 -1.21559745]]
----------------------
[ 0.05022887  0.92500764 -1.58576621]

4.4 形状更改

4.4.1 ndarray.reshape(shape, order)

4.4.2 ndarray.resize(new_shape)

  • 修改数组本身的形状(需要保持元素个数前后相同)
  • 行、列不进行互换
stock_change.resize([5, 4])

4.4.3 ndarray.T

  • 数组的转置
  • 将数组的行、列进行互换
stock_change.T

4.5 类型修改

4.5.1 ndarray.astype(type)

  • 返回修改了类型之后的数组
stock_change.astype(np.int32)

4.5.2 ndarray.tostring([order])或

4.5.2 ndarray.tobytes([order])

  • 构造包含数组中原始数据字节的Python字节
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[12, 3, 34], [5, 6, 7]]])
arr.tostring()

4.6 数组的去重

4.6.1 np.unique()

temp = np.array([[1, 2, 3, 4],[3, 4, 5, 6]])
>>> np.unique(temp)
array([1, 2, 3, 4, 5, 6])

4.7 数组的运算

4.7.1 逻辑运算

# 生成10名同学,5门功课的数据
>>> score = np.random.randint(40, 100, (10, 5))

# 取出最后4名同学的成绩,用于逻辑判断
>>> test_score = score[6:, 0:5]

# 逻辑判断, 如果成绩大于60就标记为True 否则为False
>>> test_score > 60
array([[ True,  True,  True, False,  True],
       [ True,  True,  True, False,  True],
       [ True,  True, False, False,  True],
       [False,  True,  True,  True,  True]])

# BOOL赋值, 将满足条件的设置为指定的值-布尔索引
>>> test_score[test_score > 60] = 1
>>> test_score
array([[ 1,  1,  1, 52,  1],
       [ 1,  1,  1, 59,  1],
       [ 1,  1, 44, 44,  1],
       [59,  1,  1,  1,  1]])

4.7.2 通用判断函数

np.all()

# 判断前两名同学的成绩[0:2, :]是否全及格
>>> np.all(score[0:2, :] > 60)
False

np.any()

# 判断前两名同学的成绩[0:2, :]是否有大于90分的
>>> np.any(score[0:2, :] > 80)
True

4.7.3 np.where(三元运算符)

通过使用np.where能够进行更加复杂的运算

  • np.where()
# 判断前四名学生,前四门课程中,成绩中大于60的置为1,否则为0
temp = score[:4, :4]
np.where(temp > 60, 1, 0)

复合逻辑需要结合np.logical_and和np.logical_or使用

# 判断前四名学生,前四门课程中,成绩中大于60且小于90的换为1,否则为0
np.where(np.logical_and(temp > 60, temp < 90), 1, 0)

# 判断前四名学生,前四门课程中,成绩中大于90或小于60的换为1,否则为0
np.where(np.logical_or(temp > 90, temp < 60), 1, 0)

4.7.4 统计运算

如果想要知道学生成绩最大的分数,或者做小分数应该怎么做?

4.7.4.1 统计指标

在数据挖掘/机器学习领域,统计指标的值也是我们分析问题的一种方式。常用的指标如下:

  • min(a, axis)
    • Return the minimum of an array or minimum along an axis.
  • max(a, axis])
    • Return the maximum of an array or maximum along an axis.
  • median(a, axis)
    • Compute the median along the specified axis.
  • mean(a, axis, dtype)
    • Compute the arithmetic mean along the specified axis.
  • std(a, axis, dtype)
    • Compute the standard deviation along the specified axis.
  • var(a, axis, dtype)
    • Compute the variance along the specified axis.
4.7.4.2 案例:学生成绩统计运算

进行统计的时候,axis 轴的取值并不一定,Numpy中不同的API轴的值都不一样,在这里,axis 0代表列, axis 1代表行去进行统计

# 接下来对于前四名学生,进行一些统计运算
# 指定列 去统计
temp = score[:4, 0:5]
print("前四名学生,各科成绩的最大分:{}".format(np.max(temp, axis=0)))
print("前四名学生,各科成绩的最小分:{}".format(np.min(temp, axis=0)))
print("前四名学生,各科成绩波动情况:{}".format(np.std(temp, axis=0)))
print("前四名学生,各科成绩的平均分:{}".format(np.mean(temp, axis=0)))

结果:

前四名学生,各科成绩的最大分:[96 97 72 98 89]
前四名学生,各科成绩的最小分:[55 57 45 76 77]
前四名学生,各科成绩波动情况:[16.25576821 14.92271758 10.40432602  8.0311892   4.32290412]
前四名学生,各科成绩的平均分:[78.5  75.75 62.5  85.   82.25]

如果需要统计出某科最高分对应的是哪个同学?

  • np.argmax(temp, axis=)
  • np.argmin(temp, axis=)
print("前四名学生,各科成绩最高分对应的学生下标:{}".format(np.argmax(temp, axis=0)))

结果:

前四名学生,各科成绩最高分对应的学生下标:[0 2 0 0 1]

4.8 数组间的运算

4.8.1 数组与数的运算

import numpy as np

arr = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
print(arr + 1)
print(arr / 2)

# 可以对比python列表的运算,看出区别
a = [1, 2, 3, 4, 5]
print(a * 3)

结果:

[[2 3 4 3 2 5]
 [6 7 2 3 4 2]]
[[0.5 1.  1.5 1.  0.5 2. ]
 [2.5 3.  0.5 1.  1.5 0.5]]
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

4.8.2 数组与数组的运算

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

上面这个能进行运算吗,结果是不行的!

4.8.2.1 广播机制

数组在进行矢量化运算时,要求数组的形状是相等的。当形状不相等的数组执行算术运算的时候,就会出现广播机制,该机制会对数组进行扩展,使数组的shape属性值一样,这样,就可以进行矢量化运算了。下面通过一个例子进行说明:

arr1 = np.array([[0],[1],[2],[3]])
arr1.shape
# (4, 1)

arr2 = np.array([1,2,3])
arr2.shape
# (3,)

arr1+arr2
# 结果是:
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 6]])

上述代码中,数组arr1是4行1列,arr2是1行3列。这两个数组要进行相加,按照广播机制会对数组arr1和arr2都进行扩展,使得数组arr1和arr2都变成4行3列。

下面通过一张图来描述广播机制扩展数组的过程:
在这里插入图片描述
这句话乃是理解广播的核心。广播主要发生在两种情况,一种是两个数组的维数不相等,但是它们的后缘维度的轴长相符,另外一种是有一方的长度为1。

  • 广播机制实现了时两个或两个以上数组的运算,即使这些数组的shape不是完全相同的,只需要满足如下任意一个条件即可。
    • 如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符,
    • 或其中的一方的长度为1。

广播会在缺失和(或)长度为1的维度上进行。

广播机制需要扩展维度小的数组,使得它与维度最大的数组的shape值相同,以便使用元素级函数或者运算符进行运算。

4.9 矩阵

4.9.1 加法和标量乘法

矩阵的加法:行列数相等的可以加。
例:
在这里插入图片描述

矩阵的乘法:每个元素都要乘。
例:
在这里插入图片描述

4.9.2 矩阵向量乘法

矩阵和向量的乘法如图:m×n 的矩阵乘以 n×1 的向量,得到的是 m×1 的向量
例:
在这里插入图片描述

4.9.3 矩阵乘法

矩阵乘法:

m×n 矩阵乘以 n×o 矩阵,变成 m×o 矩阵。

举例:比如说现在有两个矩阵 A 和 B,那 么它们的乘积就可以表示为图中所示的形式。
在这里插入图片描述

4.9.4 逆、转置

4.9.5 矩阵乘法api

  • np.matmul
  • np.dot
>>> a = np.array([[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])
>>> b = np.array([[0.7], [0.3]])

>>> np.matmul(a, b)
array([[81.8],
       [81.4],
       [82.9],
       [90. ],
       [84.8],
       [84.4],
       [78.6],
       [92.6]])

>>> np.dot(a,b)
array([[81.8],
       [81.4],
       [82.9],
       [90. ],
       [84.8],
       [84.4],
       [78.6],
       [92.6]])

np.matmul和np.dot的区别:
二者都是矩阵乘法。 np.matmul中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中,np.matmul与np.dot没有区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值