本文已参与「新人创作礼」活动,一起开启掘金创作之路。
🔥 本文由 程序喵正在路上 原创,在稀土掘金首发!
💖 系列专栏:数据挖掘
🌠 首发时间:2022年8月29日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生
一、Numpy优势
1. Numpy简介
Numpy (Numerical Python) 是一个开源的 Python 科学计算库,用于快速处理任意维度的数组
Numpy 支持常见的数组和矩阵操作,对于同样的数值计算任务,使用 Numpy 比直接使用 Pyhon 要简洁得多
Numpy 使用 ndarray 对象来处理多维数组,该对象是一个快速而灵活的大数据容器
2. ndarray介绍
Numpy 提供了一个 N维数组类型 ndarray (N-dimensional array),它描述了相同类型的 "items" 的集合
▷ 用 ndarray 进行存储:
import numpy as np
# 创建ndarray
score = np.array([[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79],
[80, 89, 86, 67, 79]])
score
▷ 运行结果:
使用 Python 列表可以存储一维数组,通过列表的嵌套可以实现多维数组,那么为什么还需要使用 Numpy 的 ndarray 呢?
3. ndarray与Python原生list运算效率对比
在这里我们通过一段代码运行来体会 ndarray 的好处
import random
import time
import numpy as np
a = []
for i in range(10000000):
a.append(random.random())
t1 = time.time()
sum1 = sum(a)
t2 = time.time()
b = np.array(a)
t4 = time.time()
sum3 = np.sum(b)
t5 = time.time()
print(t2-t1, t5-t4)
t2-t1 为使用 Python 自带的求和函数消耗的时间,t5-t4 为使用 Numpy 求和消耗的时间,结果为:
从中我们看到 ndarray 的计算速度要快很多,节约了很多
机器学习的最大特点就是大量的数据运算,那么如果没有一个快速的解决方案,那可能现在 Python 在机器学习领域也达不到好的效果
Numpy 专门针对 ndarray 的操作和运算进行了设计,所以数组的存储效率和输入输出性能远优于 Python 中的嵌套列表,数组越大,Numpy 的优势就越明显
那么,为什么 ndarray 可以这么快呢?
4. ndarray的优势
▷ 1、内存块风格
ndarray 到底跟原生 Python 列表有什么不同呢
ndarray 在存储数据的时候,数据与数据的地址都是连续的,这样就使得批量操作数组元素时速度更快
这是因为 ndarray 中的所有元素的类型都是相同的,而 Python 列表中的元素类型是任意的,所以 ndarray 在存储元素时内存可以连续,而 Python 原生 list 只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面 Numpy 的 ndarray 不及 Python 原生 list,但在科学计算中,Numpy 的 ndarray 就可以省略掉很多循环语句,代码使用方面比 Python 原生 list 简单得多
▷ 2、ndarray支持并行化计算(向量化计算)
▷ 3、Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,效率远高于纯Python代码
二、认识N维数组
1. ndarray的属性
| 属性名字 | 属性解释 |
|---|---|
| ndarray.shape | 数组维度的元组 |
| ndarray.dtype | 数组元素的类型 |
| ndarray.ndim | 数组维数 |
| ndarray.size | 数组中的元素数量 |
| ndarray.itemsize | 一个数组元素的长度(字节) |
2. ndarray的形状
首先创建一些数组
# 创建不同形状的数组
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([1, 2, 3, 4])
c = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
然后分别打印出形状
怎么理解数组的形状?
二维数组:
三维数组:
3. ndarray的类型
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^ 至 z^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' |
常用的类型有 int32、int64、float32、float64、uint8 等等
创建数组的时候可以指定类型
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
a.dtype
b = np.array(['python', 'matplotlib', 'numpy', 'pandas'], dtype=np.string_)
b
三、基本操作
1. 生成数组的方法
▷ 生成0和1的数组
- ones(shape[, dtype, order])
- zeros(shape[, dtype, order])
# 生成0的数组
np.zeros(shape=(3, 4), dtype='float32')
# 生成1的数组
np.ones(shape=(2, 3), dtype=np.int32)
▷ 从现有数组生成
- array(object[, dtype, copy, order, subok, ndmin])
- asarray(a[, dtype, order])
- copy(a[, order])
array 和 asarray 的不同
np.array 和 np.copy 是深拷贝,原数组的改变不会影响到它们
np.asarray 是浅拷贝,会随着原数组的改变而改变
▷ 生成固定范围的数组
- np.linspace(start, stop, num, endpoint, retstep, dtype)
- np.arange(start, stop, step, dtype)
生成等间隔的序列
start:序列的起始值
stop:序列的终止值
如果 endpoint 为 true,该值包含于序列中
num:要生成的等间隔样例数量,默认为50
endpoint:序列中是否包含 stop 值,默认为 true
retstep:如果为 true,返回样例以及连续数字之间的步长
dtype:输出 ndarray 的数据类型
▷ 生成随机数组
np.ramdom模块
均匀分布
- np.random.rand()
返回 [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 或元组类型,例如,size=(m, n, k),则输出 mnk 个样本,,缺省时输出 1 个值
返回值:ndarray 类型,其形状和参数 size 中描述的一致 - np.random.randint(low, high=None, size=None, dtype='')
从一个均匀分布中随机取样,生成一个整数或 N 维整数数组,取数范围:若 high 不为 None 时,取 [low, high] 之间随机整数,否则取值 [0, low] 之间的随机整数
均匀分布(Uniform Distribution)是概率统计中的重要分布之一,顾名思义,均匀,表示可能性相等的含义。均匀分布在自然情况下极为罕见,而人工栽培的有一定株行距的植物群落既是均匀分布
import matplotlib.pyplot as plt
import numpy as np
# 生成均匀分布的随机数
data1 = np.random.uniform(-1, 1, 100000000)
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 绘制直方图
plt.hist(data1, 1000)
# 显示图像
plt.show()
正态分布
- np.ramdom.randn() 功能:从标准正态分布中返回一个或多个样本值
- np.random.normal(loc=0.0, scale=1.0, size=None)
loc:float
此概率分布的均值(对应着整个分布的中心)
scale:float
此概率分布的标准量(对应于分布的宽度,scale 越大越矮胖,越小越瘦高)
size:int or tuple of ints
输出的 shape,默认为 None,只输出一个值 - np.random.standard_normal(size=None)
返回指定形状的标准正态分布的数组
正态分布是一种概率分布,正态分布是具有两个参数 μ 和 σ 的连续型随机变量的分布,第一参数 μ 是服从正态分布的随机变量的均值,第二个参数 σ 是此随机变量的标准差,所以正态分布记作 N(μ, σ²)
正态分布的应用:
生活、生产于科学实验中很多随机变量的概率分布都可以近似地用正态分布来描述
正态分布的特点:
μ 决定了其位置,σ 决定了分布的幅度,当 μ = 0,σ = 1 时的正态分布是标准正态分布
标准差与方差的意义
标准差与方差如何计算便不多说了,这部分属于高中的内容
可以理解成数据的一个离散程度的衡量
下面我们来写一个正态分布
import matplotlib.pyplot as plt
import numpy as np
# 正态分布
data2 = np.random.normal(loc=1.75, scale=0.1, size=1000000)
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 绘制直方图
plt.hist(data2, 1000)
# 显示图像
plt.show()
例如:我们可以模拟生成一组股票的涨跌幅的数据
2. 案例:随机生成股票交易日涨幅数据
比如,8 只股票,在两周内的涨跌幅数据,怎么获取?
- 周末休息,所以交易日为 10 天
- 随机生成涨跌幅在某个正态分布内,比如均值 0,方差 1
股票涨跌幅数据的创建
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
生成数据
数据的索引、切片
- 获取第一个股票的前 3 个交易日的涨跌幅数据
# 二维数组
stock_change[0, 0:3]
- 返回结果:
拓展:三维数组如何索引?
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[11, 22, 33], [44, 55, 66]]])
arr[0, 1, 0:3]
形状修改
需求:让刚才的股票行、日期列反过来,变成日期行、股票列
- ndarray.reshape(shape[, order]) 返回新的 ndarray,原始数据没有改变
# 在转换形状的时候,一定要注意数组的元素匹配
stock_change.reshape([10, 8]) # 只是将形状进行了修改,但并没有将行列进行转换
stock_change.reshape([-1, 20]) # 数组的形状被修改为:(4, 20),-1:表示通过待计算
- ndarray.resize(shape[, order]) 没有返回值,对原始的 ndarray 进行了修改
- ndarray.T 数组的转置 将数组的行、列进行互换
stock_change.T.shape
类型修改
- ndarray.astype(type)
stock_change.astype(np.int32)
- ndarray.tostring([order]) 或者 ndarray.tobytes([order]) 转换成 bytes
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[11, 22, 33], [44, 55, 66]]])
arr.tostring()
数组去重
- ndarray.unique
temp = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
np.unique(temp)