最后大图可点开保存
文章目录
- 3.1.1Numpy介绍
- 3.1.2 ndarray介绍
- 3.1.3 ndarray与Python原生list运算效率对比
- 3.1.4 ndarray的优势
- 3.2 认识N维数组 -ndarray属性
- 3.3 基本操作
- 3.3.1 生成数组的方法
- 案例:随机生成8只股票2周的交易日涨幅数据
- 3.3.4 类型修改
- 3. 3. 5 数组的去重
- 3.3.6 小结
- 3.4 ndarray运算
- 3.4.1逻辑运算
- 3.4.2 通用判断函数
- 3.4.3 np.where (三元运算符)
- 3.4.4 统计指标
- 3.5 数组间的运算
- 3.5.1 应用场景
- 3.5.2 数组与数的运算
- 3.5.3 数组与数组的运算
- 3.5.4 广播机制
- 3.5.5 矩阵运算
- 3.6合并、分割的用处
- 3.6.1 合并
- 3.6.2 分割
- 3.7 IO操作与数据处理
- 3.7.1 Numgy读取
- 3.7.2 如何处理缺失值
- 3.8总结
学习目标
- 目标
- 了解Numpy运算速度上的优势
- 知道Numpy的数组内存块风格
- 知道Numpy的并行优化运算
- 应用
- 机器学习,深度学习各种框架的基础库
- 内容预览
- 3.1.1 Numpy介绍
- 3.1.2 ndarray介绍
- 3.1.3 ndarray与python原生list运算效率对比
- 3.1.4 ndarray的优势
3.1.1Numpy介绍
num - numerical
py - python
numpy - numerical python
Numpy是一个开源的Python科学计算库,用于快速处理任意维度的数组。
Numpy使用ndarray对象来处理多维数组,该对象是一个快速而灵活的大数据容器
ndarray:
n - 任意个
d - dimension 维度
array - 数组
3.1.2 ndarray介绍
Numpy提供了一个N维数组类型ndarray,它描述了相同类型的"items"的集合。
使用ndarray进行存储:
import numpy as np
# 创建ndarray
score = np.array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])
使用Python列表可以存储一维数组,通过列表的嵌套可以实现多维数组,那么为什么还需要使用Numpy的ndarray呢?
3.1.3 ndarray与Python原生list运算效率对比
import random
import time
import numpy as np
a = []
for i in range(100000000): # 随机生成一亿个数字
a.append(random.random())
t1 = time.time()
sum1 = sum(a)
t2 = time.time()
b = np.array(a)
t4 = time.time()
sum2 = np.sum(b)
t5 = time.time()
print(t2-t1, t5-t4)
# 0.9411723613739014 0.18763375282287598
从中我们可以看出ndarray的计算速度要快很多,节约了时间。
机器学习的最大特点:就是大量的数据运算,那么如果没有一个快速的解决方案,那可能现在python也在机器学习领域达不到好的效果。
3.1.4 ndarray的优势
- 内存块存储风格
ndarray ; 元素相同类型 ; 通用性不强, 元素在内存中连续。
list ; 元素不同类型 ; 通用性很强, 元素在内存中不一定连续,如列表中还有个字典
- 并行化运算(向量化运算)
不需要循环,直接向量化运算,同时计算。
- 底层语言
Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,效率远高于纯Python代码。
3.2 认识N维数组 -ndarray属性
3.2.1 ndarray的属性
数组属性反映了数组本身固有的信息:
属性名字 | 属性解释 |
---|---|
ndarray.shape | 数组维度的元组 |
ndarray.ndim | 数组维数 |
ndarray.size | 数组中的元素数量 |
ndarray.dtype | 数组元素的类型 |
ndarray.itemsize | 一个数组元素的长度(字节) |
最重要的两个属性是shape
和dtype
:
当我们知道了形状shap即维度
的时候,我们就可以知道维数ndim
、数组的元素个数(数组大小)size
;
当我们知道数组中的元素的类型的时候,我们就可以知道一个数组元素的长度itemsize
,因为不同类型的元素在内存中的占用是固定的。
示例:
score = np.array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])
# 整个数组
print(score.shape) # (8, 5)
print(score.ndim) # 2 二维
print(score.size) # 40 数组元素个数
# 单个元素
print(score.dtype) # int32 元素的类型
print(score.itemsize) # 4 元素大小
3.2.2 ndarray的形状
a = np.array([[1, 2, 3], [4, 5, 6]])
a.shape # (2, 3)
b = np.array([1, 2, 3, 4])
b.shape # (4, )
c = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
c.shape # (2, 2, 3)
# shape先看第一个中括号内几个部分,再看第二个中括号....
3.2.3 ndarray元素类型
- 默认:
- 整数 int64
- 小数 float64
- 创建数组的时候指定类型
np.array([1.1, 1.2, 1.3], dtype="float32")
np.array([1.1, 1.2, 1.3], dtype=float32)
# 两种方式是等价的
3.3 基本操作
学习目标
- 目标
- 理解数组的各种生成方法;
- 应用数组的索引机制实现数组的切片获取
- 应用维度变换实现数组的形状改变
- 应用类型变换实现数组类型改变
- 应用数组的转换
- 应用
- 应用正态分布实现模拟股票的涨跌幅数据操作
- 内容预览
- 3.3.1 生成数组的方法
- 1 生成0和1的数组
- 2 从现有数组生成
- 3 生成固定范围的数组
- 4 生成随机数组
- 3.3.2 数组的索引、切片
- 3.3.3 形状修改
- 3.3.4 类型修改
- 3.3.5 数组的去重
- 3.3.1 生成数组的方法
3.3.1 生成数组的方法
1 生成0和1的数组
生成这样的数组的方式有很多,没有必要全都记住,这里推荐ones方法和zeros方法:
np.zeros(shape=(3, 4), dtype="float32")
np.ones(shape=[2, 3], dtype=int32)
# 列表和元素表示都可以
2从现有数组中生成
有array、asarray、copy几种方法:
score = np.array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])
data1 = np.array(score)
print(data1)
'''array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])'''
data2 = np.asarray(score)
print(data2)
'''array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])'''
data2 = np.copy(score)
print(data2)
'''array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 84],
[86, 85, 83, 67, 80]])'''
但是这三个是有区别的:array和copy是深拷贝; asarray是浅拷贝。
3生成固定范围的数组
有np.linspace()和np.arange()方法;
- np.linspace(0, 10, 100)
生成[0, 10]等距离的100个
data = np.linspace(0, 10, 6) # 等分生成6个
print(data)
# [ 0. 2. 4. 6. 8. 10.]
- np.arange(a, b, c)
和range是一样的
data2 = np.arange(0, 10, 6) # 步长是6
print(data2) # [0, 6]
生成随机数
- np.random
- np.random.uniform(low=0, high=1, size=None)
- 均匀分布(Uniform Distribution)
是概率论统计中的重要分布之一。顾名思义,均匀,表示可能性相等的含义。均匀分布在自然情况下极为罕见,而人工栽培的有一定株行距的植物群落是均匀分布。
# 生成均匀分布的随机数
x1 = np.random.uniform(-1, 1, 1000)
# 返回结果
print(x1)
[ 0.56347276 -0.94591979 -0.23197083 ... -0.79391627 -0.32959637]
# 这里用直方图来表示这个均匀分布
import matplotlib.pyplot as plt
# 1. 创建画布
plt.figure(figseze=(20, 8), dpi=80)
# 2. 绘制直方图
plt.hist(x1, 1000)
# 3. 显示图像
plt.show()
画出的直方图:
- 正态分布
是具有两个参数μ和σ的连续型随机变量的分布,第一参数μ是服从正态分布的随机变量的均值,第二个参数σ是此随机变量的标准差,所以正态分布记作N(μ, σ).
σ 幅度、波动程度、集中程度、稳定性
μ决定图像的位置
f(x) = (1 / σ(2π)0.5 ) e^((x-μ)**2) / 2 σ**2^
方差:
标准差是s
方差越小越稳定
np.random.normal(loc=0.0, scale=1.0, size=None)
loc是均值, scale是标准差,对应图像的宽度
data2 = np.random.normal(loc=1.75, scale=0.1, size=10000)
print(data2)
[1.55345983 1.73792734 1.62380419 ... 1.80401868 1.90379977 1.69976006]
# 这里用直方图来表示这个正态分布
import matplotlib.pyplot as plt
# 1. 创建画布
plt.figure(figseze=(20, 8), dpi=80)
# 2. 绘制直方图
plt.hist(data2, 10000)
# 3. 显示图像
plt.show()
案例:随机生成8只股票2周的交易日涨幅数据
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
数组的索引、切片
- 获取第一支股票的前3个交易日的涨跌幅数据
# 二维数组,两个维度
stock_change[0, 0:3]
形状修改
- 需求:让刚才的股票行、日期列反过来,变成日期行、股票列
stock_change.reshape(10, 8) # 我们发现只是对数据进行了重新分割,并没有反转
stock_change.resize(10, 8) # in-place, 没返回,并没有反转
stock_change.T # 转置,行变成列, 列变成行,有返回
3.3.4 类型修改
- ndarray.astype(type)
如果想要序列化到本地,先要转成bytes类型
stock_change.astype("int32")
stock_change.tostring() # bytes类型
扩展:
jupyter对输出的字节数有限制,需要去修改配置文件, 但是不建议
3. 3. 5 数组的去重
temp = np.array([1, 2, 3, 4], [3, 4, 5, 6])
np.unique(temp) # 返回array[1, 2, 3, 4, 5, 6]
temp.flatten() # 扁平化
set(temp)
3.3.6 小结
- 创建数组
- 均匀
- 随机(正态分布)
- 正太分布
- 数组索引
- 数组形状改变
- 数组类型
- reshape
- resize
- 数组转换
- T
- tostring
- unique
3.4 ndarray运算
学习目标
- 目标
- 应用数组的通用判断函数
- 应用np.where实现数组的三元运算
- 应用
- 股票涨跌幅数据逻辑运算
- 内容预览
- 3.4.1逻辑运算
- 3.4.2通用判断函数
- 3.4.3np.where(三元运算符)
- 3.4.4统计运算
问题
如果想要操作符合某一条件的数据,应该怎么做?
3.4.1逻辑运算
# 重新生成8只股票10个交易日的涨跌幅数据
stock_change = np.random.normal(0, 1, (8, 10)) # loc=0, 方差=1, 8行10列
stock_change = stock_change[0:5, 0:5] # 获取前五行的前五列
# 逻辑判断,如果涨幅大于0.5就标记为True 否则为False
stock_changes > 0.5 # 返回新的,bool
stock_changes[stock_changes > 0.5] = 1.1 # 满足条件的统一处理
3.4.2 通用判断函数
- np.all()
只有全是True才会返回True
判断stock_changes[0:2, 0:5]是否全是上涨的
np.all(stock_changes[0:2, 0:5] > 0)
false
- np.any()
只要有一个True就会返回True
# 判断前5只股票这段时间是否有上涨
np.any(stock_changes[0:5, :] > 0)
True
3.4.3 np.where (三元运算符)
通过使用np.where能够进行更加复杂的运算
- np.where()
# 判断前四只股票前四天的涨跌幅 大于0的置为1, 否则为0
temp = stock_changes[:4, :4]
np.where(temp > 0, 1, 0)
- 复合逻辑需要结合np.logical_and和logical_or使用
# 判断前四个股票前四天的涨跌幅 大于0.5并且小于1的, 换为1, 否则0
# 判断前四个股票前四天的涨跌幅 大于0.5或者小于-0.5的, 换为1, 否则为0
np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0)
np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0)
3.4.4 统计指标
使用方法:np.函数名 ; ndarray.方法名
-
np.min(a[, axis, out, keepdims])
-
np.max(a[, axis, out, keepdims])
-
np.median(a[, axis, out, overwrite_input, keeepdims])
-
np.mean(a[, axis, dtype, out, keepdims])
-
np.std(a[, axis, dtype, out, ddof, keepdims])
-
np.var(a[, axis, dtype, out, ddof, keepdims])
进行统计的时候,axis轴的取值并不一定,Numpy中不同的API轴的值不一样,在这里,axis 0 代表列, axis 1 代表行进行统计
print("前四只股票前四天的最大涨幅{}".format(np.max(temp, axis=1)))
print("前四只股票前四天的最大跌幅{}".format(np.min(temp, axis=1)))
print("前四只股票前四天的波动程度{}".format(np.std(temp, axis=1)))
print("前四只股票前四天的平均涨跌幅{}".format(np.mean(temp, axis=1)))
np.argmax(temp, axis=1) # 返回的是索引
3.5 数组间的运算
3.5.1 应用场景
3.5.2 数组与数的运算
arr = np.array([1, 2, 3, 4], [2, 3, 4, 5])
arr + 1 # 每个元素加1 - 、 *、 / 都是可以的
3.5.3 数组与数组的运算
3.5.4 广播机制
执行broadcast的前提在于, 两个ndarray执行的是element-wise的运算,Broadcast机制的功能是为了方便不同形状的ndarray进行数学运算。
当操作两个数组时,numpy会逐个比较他们的shape(构成的元组tuple), 只有在下述情况下,两个数组才能够进行数组与数组的运算。
- 维度相等
- shape(其中相对应的一个地方为1)
3.5.5 矩阵运算
1 矩阵存储
两种方法存储矩阵:
- matrix
- ndarray
data = np.array([1, 2], [2, 4], [5, 6])
data1 = np.mat([1, 2], [2, 4], [5, 6])
2 矩阵乘法运算
形状改变:
m行n列 * n行任l列 = m行l 列
矩阵乘法api
- np.matmul
mat是matrix; mul是multiply - np.dot
np.matmul(a, b)
np.dot(a, b)
ndarray要用这两个进行乘法;如果是matrix直接 * 就可以了
ndarray也可以用 @,ndarray * ndarray是检查广播机制
3.6合并、分割的用处
3.6.1 合并
np.hstack(tup)
np.vstack(tup)
np.concatenate((a1, a2, …), axis=0) 0是竖直拼接; 1是水平拼接
3.6.2 分割
np.split(ary, indices_or_sections, axis=0)
3.7 IO操作与数据处理
学习目标
- 目标
- 知道Numpy文件的读取
- 应用
- 无
- 内容预览
- 3.7.1 Numpy读取
- 3.7.2 如何处理缺失值
- 1 什么是缺失值
- 2 缺失值处理
问题
大多数数据并不是我们自己创造的, 而是存在文件当中,需要我们用工具获取。
但是Numpy其实并不适合用来读取和处理数据,因此我们这里了解相关API,以及Numpy不方便的地方即可。
3.7.1 Numgy读取
test = np.genfromtxt("test.csv", delimiter=",")
3.7.2 如何处理缺失值
1.什么是缺失值
什么时候numpy中会出现nan:当我们读取本地的文件为float的时候,nan
2 如何处理缺失值
两种思路:
- 直接删除
- 替换/插补