IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> NumPy 基础(数组与向量化计算)——《利用Python进行数据分析》第四章阅读笔记 -> 正文阅读

[人工智能]NumPy 基础(数组与向量化计算)——《利用Python进行数据分析》第四章阅读笔记

NumPy 基础(数组与向量化计算)——《利用Python进行数据分析》第四章阅读笔记

前言

上一次总结了该书第三章的内容,这次带来第四章,也就是NumPy 的基础部分,有关Numpy的历史发展等相关知识点,读者可直接参考该书的87、88页。从这两页,我们知道Numpy主要是在数组部分,其算法库是采用C编写,数据存储在连续内存块上,这一特性,使得Numpy数组方法在性能上要远优于传统的Python方法。

环境依旧是 Pycharm 2020.2.4 社区版, Anconda3

一 NumPy ndarray: 多维数组对象

作为NumPy的核心特征之一,ndarray即N维数组对象,是Python中一个快速、灵活的大型数据集容器。

用下面的随机NumPy数组代码,来感受一下

import numpy as np

# 生成随机数组
data = np.random.randn(2, 3)
print(data)
# 对numpy 数组进行数组操作
print(data * 10)
print(data + data)
# 描述数组每一维度的数量
print(data.shape)
# 描述数组的数据类型————ndarray 所有元素的数据类型相同
print(data.dtype)

1. 生成 ndarray

几个示例代码可以参考一下

import numpy as np

data1 = [6, 7.5, 8, 0, 1]
# 将任意序列类型转换成 ndarray对象, 数据类型自动转换(低变高)
arr1 = np.array(data1)
print(arr1, arr1.dtype)
# 嵌套序列自动转化成 高维数组
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
print(arr2, arr2.dtype)
# 查看数组维度
print(arr2.ndim, arr1.ndim)
print(arr2.shape)
# 其他生成数组函数
# 生成全0
print(np.zeros((3, 6)))
# 生成未初始化数组
print(np.empty((2, 3, 2)))
# range 的数组版
print(np.arange(12))

更多的数组生成函数可以参考该书的 表4-1

2. ndarray 的数据类型

数据类型,即dtype,是一个特殊对象,它包含了ndarray 需要为某一种类型数据申明的内存块信息(也称为元数据,即表示数据的数据)

import numpy as np

arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
print(arr1.dtype)
print(arr2.dtype)

更多数组类型请参考该书的 表4-2

import numpy as np

arr1 = np.array([1, 2, 3], dtype=np.float64)
# 使用astype方法显示转换数据类型
arr1 = arr1.astype(np.int32)
print(arr1.dtype)
numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
numeric_strings = numeric_strings.astype(np.float64)
print(numeric_strings)

# 可以使用类型代码来传入数据类型
empty_unit32 = np.empty(8, dtype='u4')
print(empty_unit32, empty_unit32.dtype)

使用 astype时 会生成一个新的数组,即使你传入的dtype 与之前一样。

3. NumPy 数组算术

数组之所以重要,是因为它允许进行批量操作而无须进行任何 for 循环。这一特性 也称为 向量化。

import numpy as np

arr = np.array([[1., 2., 3.], [4., 5., 6.]])
print(arr * arr)
print(arr - arr)
# 带有标量的算术操作也适用
print(1 / arr)
print(arr ** 0.5)
# 同尺寸数组之间的比较,会产生一个布尔值数组
arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
print(arr2 > arr)

4. 基础索引与切片

NumPy 数组索引 方式有很多种

import numpy as np

arr = np.arange(10)
print(arr)
# 单个索引
print(arr[5])
# 数组切片
print(arr[5:8])
# 对切片段修改
arr[5:8] = 12
# 不会生成新数组,而是对原数组进行修改
print(arr)

arr_slice = arr[5:8]
# 当arr_slice改变时,变化也会体现在原数组, 这一特性类似于cpp的引用
arr_slice[1] = 12345
print(arr)
# 不写 切片值 的 [:] 将会引用数组的所有值
arr_slice[:] = 13
print(arr)
# 如果需要复制,则需要显示调用复制
copy = arr[5:8].copy()
copy[:] = 0
print(copy)
print(arr)
# 对于 二维数组 每个索引值对应的元素是一个一维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0])
# 单个元素可以通过递归方式获得,也可以传递索引的逗号分隔列表去选择单个元素
print(arr2d[0][2], arr2d[0, 2])
# 需要注意的是上诉通过索引返回的元素都是视图,即引用
arr2d[0][2] = 5
print(arr2d)

4.1 切片索引

其实这种索引方式在上面有所提及,对于高维数组,我们可以使用切片索引获取低维度的切片,并重新赋值

import numpy as np

# 对于 二维数组 每个索引值对应的元素是一个一维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[:2, 2])
arr2d[:2, :1] = 0
print(arr2d)

5. 布尔索引

其实就是bool值去索引, 需注意的是,布尔值数组长度应该和数组轴索引长度一致, 且可能是因为用C编写的原因,and和or关键字对布尔值数组没有用,需要使用 & 和 | 替代。

import numpy as np

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
print(names == 'Bob')
print(data[names == 'Bob'])
print(data[~(names == 'Bob')])
mask = (names == 'Bob') | (names == 'Will')
print(data[mask])
data[data < 0] = 0
print(data)

6. 神奇索引

其实就是用整数数组进行索引

import numpy as np

arr = np.empty((8, 4))
print(arr[[4, 3, 0, -6]])

arr = np.arange(32).reshape((8, 4))
print(arr)
# 得到对应的元素
print(arr[[1, 5, 7, 2], [0, 3, 1, 2]])
# 得到相应的矩形区域
print(arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]])

7. 数组转置和换轴

import numpy as np

arr = np.arange(15).reshape((3, 5))
print(arr)
print(arr.T)
# 计算矩阵内积
print(np.dot(arr, arr.T))
arr1 = np.arange(16).reshape((2, 2, 4))
# 使用 transpose 方法对数组的轴重新排序
print(arr1.transpose((1, 0, 2)))
print(arr1)
# 转置其实就是换轴的一种特殊案例, 使用swapaxes方法对轴进行调整用于重组数据
print(arr1.swapaxes(1, 2))

以上方法,都是返回数据的底层视图,而不生成新的数组,也不对数据进行复制

二 通用函数

通用函数,ufunc,是一种在 ndarray 数据中 进行逐元素操作的函数,某些简单函数接收一个或多个标量差值, 并产生 一个或多个 标量结果, 而通用函数就是对这些函数是对这些简单函数的向量化封装

import numpy as np

arr = np.arange(10)
print(np.sqrt(arr))
print(np.exp(arr))

x = np.random.randn(8)
y = np.random.randn(8)
print(x, y)
# 比较x,y对应元素,返回最大值
print(np.maximum(x, y))
# modf 返回一个浮点数组的小数部分和整数部分
reminder, whole_part = np.modf(x)
print(reminder)
print(whole_part)
arr = np.random.randn(7) * 5
print(arr)

更多的通用函数请参考该书的表 4-3,4-4

三 使用数组进行面向数组编程

使用Numpy数组,可以使用简单的数组表达式代替显示循环的方法, 这种方法称为向量化,向量化的数组操作会比纯Python的等价实现在速度上更快

import numpy as np

points = np.arange(-5, 5, 0.01)
# meshgrid 方法 传入两个一维数组, 并根据两个数组的所有(x,y)对生成一个二维矩阵
xs, ys = np.meshgrid(points, points)
print(ys)
z = np.sqrt(xs ** 2 + ys ** 2)
print(z)

import matplotlib.pyplot as plt
plt.imshow(z, cmap=plt.cm.gray)
plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
plt.show()

1. 将条件逻辑作为数组操作

这里主要讲的是where函数, 其实就是三元表达式 x if condition else y 的向量化版本。如果直接使用三元表达式,其需要解释器解释python完成, 速度会很慢,且对高维数组需要修改代码,无法轻易复用。而使用哪np.where就可以非常简单的完成

import numpy as np

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y)
          for x, y, c in zip(xarr, yarr, cond)]
print(result)

result = np.where(cond, xarr, yarr)
print(result)

arr = np.random.randn(4, 4)
print(arr)
print(arr > 0)
# 标量也可以作为结果,不一定非要使用数组
# 将正值设为2,负值设为-2
print(np.where(arr > 0, 2, -2))
# 只将正值设为2
print(np.where(arr > 0, 2, arr))

传递给 np.where 的数组既可以是同等大小的数组,也可以是标量

2. 数学和统计方法

import numpy as np

arr = np.random.randn(5, 4)
print(arr)
print(arr.mean())
# mean 表示平均数
print(np.mean(arr))
# 像mean,sum等函数,可以接受一个可选参数axis,可用于计算给定轴向上的统计值
# mean(1) 计算每一行的平均值
print(arr.mean(1))
# sum(0) 计算每一行的和
print(arr.sum(axis=0))

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
print(arr.cumsum())
# 对于高维数组,可以在指定轴向根据较低维度的切片进行部分聚合
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
print(arr.cumsum(axis=0))
print(arr.cumprod(axis=1))

更多地请参考该书的表4-5,然后提一句,该书在该页有一个问题,axis=0 是表示每一行,axis=1 表示每一列

3. 布尔值数组的方法

布尔值会被强制为 1(True)和 0(False)

import numpy as np

arr = np.random.randn(100)
print((arr > 0).sum())

bools = np.array([False, False, True, True])
# any 检查数组中是否至少有一个True
print(bools.any())
# all 检查是否每个值都是 True
print(bools.all())

这些方法也适用非布尔值数组,所有非0的元素都按 True 处理

4. 排序

import numpy as np

arr = np.random.randn(6)
print(arr)
arr.sort()
print(arr)
# 对于高维数组可以使用参数指定轴进行排序
arr = np.random.randn(5, 3)
print(arr)
arr.sort(1)
print(arr)

顶层的 np.sort 方法 返回的是已经排序好的数组拷贝,而不是对原数组继续拷贝

5. 唯一值与其他集合逻辑

NumPy 包含一些针对一维nadarray 的基础集合操作,一个常用的方法是 np.unique,返回的是数组中唯一值排序后形成的数组

import numpy as np

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
print(np.unique(names))
ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
print(np.unique(ints))

另一个函数, np.in1d, 可以检查一个数组中的值是否存在另外一个数组中,并返回一个布尔值数组

import numpy as np

values = np.array([6, 0, 0, 3, 2, 5, 6])
print(np.in1d(values, [2, 3, 6]))

更多的ndarray数组的集合操作,请参考表 4-6

四 使用数组进行文件输入和输出

import numpy as np

arr = np.arange(10)
np.save('som_array', arr)
print(np.load('som_array.npy'))
# 数据未压缩存储
np.savez('array_archive.npz', a=arr, b=arr)
arch = np.load('array_archive.npz')
print(arch['b'])
# 数据已经压缩存储
np.savez_compressed('array_compressed.npz', a=arr, b=arr)
print(np.load('array_compressed.npz'))

五 线性代数

这部分函数大多集合在了numpy的linalg中

import numpy as np
x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])
print(x.dot(y))
#  x.dot(y) 等价于 np.dot(x, y)
print(np.dot(x, y))
#  @ 也作为 中缀操作符, 用于点乘操作
print(x @ y)

# 求逆和qr分解
from  numpy.linalg import inv, qr
X = np.random.randn(5, 5)
mat = X.T.dot(X)
print(inv(mat))
print(mat.dot(inv(mat)))
q, r = qr(mat)
print(r)

更多的线性代数操作方法,请参考表4-7

六 伪随机数生成

import numpy as np

samples = np.random.normal(size=(4, 4))
print(samples)
# 改变随机种子
np.random.seed(1234)
# 创建一个随机数生成器
rng = np.random.RandomState(1234)
print(rng.randn(10))

其他numpy.random 中的部分函数列表参考表 4-8

?

七 示例:随机漫步

一个简单的随机漫步

import matplotlib.pyplot as plt
import numpy as np
import random

# 偏python基础语法的实现形式
position = 0
walk = [position]
steps = 1000
for i in range(steps):
    step = 1 if random.randint(0, 1) else -1
    position += step
    walk.append(position)

# 偏NumPy形式
nsteps = 1000
draws = np.random.randint(0, 2, size =nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum()
# 在漫步轨道提取 最大值和最小值
print(walk.min(), walk.max())
# 返回第一次走了 10 步或 -10 步的位置
print((np.abs(walk) >= 10).argmax())
# 随机漫步的前100步
plt.plot(walk[:100])
plt.show()

1. 一次性模拟多次随机漫步

import matplotlib.pyplot as plt
import numpy as np
import random

nwalks = 5000
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks, nsteps))  # 0 或 1
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1)
print(walks)
# 这些随机步的最大值和最小值
print(walks.max(), walks.min())
# 采用 any 方法检查 最小穿越时间
hits30 = (np.abs(walks) >= 30).any(1)
print(hits30)
print(hits30.sum())     # 达到30 或 -30 的数字
# 使用布尔值数组来 选出绝对步数超过 30步所在的行
crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1)
print(crossing_times)
print(crossing_times.mean())

小结

本书接下来的部分将会集中在打造 pandas 数据处理技能上,继续在基于数组的风格下处理数据

终于写完了,最近的效率真的低下

_

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-02-06 13:50:16  更:2022-02-06 13:51:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 19:26:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码