硬核王同学 发表于 2024-8-1 11:53

一起读《机器学习算法与实现 —— Python编程与应用实例》- 第3章 Python常用库

<div class='showpostmsg'> 本帖最后由 硬核王同学 于 2024-8-1 12:03 编辑

<p>使用Python进行机器学习编程时,数值计算必不可少,如果只依靠Python内置的列表等数据结构,那么计算效率很低。要同时获得高开发效率和高执行效率,就需要使用第三方库来实现这个看似矛盾的需求。核心思想是底层的计算使用C/C++/Fortran等语言实现,高层的调用等则使用Python来实现,这样即可保证开发的便携性,又可保证较高的执行效率。本章主要介绍Numpy和Matplotlib库。</p>

<p>&nbsp;</p>

<h1>一、Numpy数值计算库</h1>

<p>Numpy主要用于Python的数值计算,为Python提供高性能向量、矩阵和高维数组的计算。Numpy是用C和Fortran语言实现的,因此计算向量化数据时的性能非常好。Numpy是Python中用于科学计算的非常基础的库,可以进行线性代数与高维函数计算、傅里叶变换,以及产生伪随机数等。</p>

<p>&nbsp;</p>

<h2>加载Numpy库</h2>

<p>首先下载numpy 库</p>

<pre>
<code>conda install numpy

pip install numpy</code></pre>

<p>要使用Numpy模块,可按以下所示的方法加载它。</p>

<pre>
<code>from numpy import * # 不建议用这种方式导入库
import numpy as np # 建议使用这种方式</code></pre>

<p>建议使用上面的第二种导入方法:不仅方便跟踪代码,而且能够避免名称空间污染。</p>

<p>在Numpy模块中,用于向量、矩阵和高维数据集的数据结构是数组,下面介绍对数组的各种操作。</p>

<p>&nbsp;</p>

<h2>创建Numpy数组</h2>

<p>初始化新Numpy数组的方法有多种,如下所示。</p>

<ul start="1">
        <li data-list="bullet">
        <p>由列表创建数组。</p>
        </li>
        <li data-list="bullet">
        <p>使用函数生成数组,例如<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">arange</span>,<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">linspace</span>等。</p>
        </li>
        <li data-list="bullet">
        <p>从文件中读取数据形成数组。</p>
        </li>
</ul>

<p>&nbsp;</p>

<h3>1.由列表创建数组</h3>

<p><strong>创建数组</strong></p>

<p>可以使用np.array()函数由Python列表创建新的向量或矩阵。如以下代码所示:</p>

<pre>
<code>import numpy as np
a =
print(a)

# a vector: the argument to the array function is a Python list
v = np.array(a)
print(v)</code></pre>

<p>输出为:</p>

<pre>
<code>
</code></pre>

<p>&nbsp;</p>

<p><strong>生成二维数组</strong></p>

<pre>
<code># 矩阵:数组函数的参数是一个嵌套的Python列表
a = [, , ]
M = np.array(a)
print(M.shape)</code></pre>

<p>&nbsp;</p>

<p><strong>Numpy数组的类型和尺寸</strong></p>

<p>v和M两个都是属于numpy模块提供的ndarray类型。</p>

<pre>
<code>print(type(v), type(M))</code></pre>

<p>输出为:(numpy.ndarray, numpy.ndarray)</p>

<pre>
<code>(numpy.ndarray, numpy.ndarray)</code></pre>

<p>v和M之间的区别仅在于他们的形状。我们可以用属性函数ndarray.shape得到数组形状的信息。</p>

<p>&nbsp;</p>

<p><strong>Numpy数组中的元素个数</strong></p>

<p>通过属性函数<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">ndarray.size</span>我们可以得到数组中元素的个数</p>

<pre>
<code>M.size</code></pre>

<p>输出为:</p>

<pre>
<code>6</code></pre>

<p>&nbsp;</p>

<p><strong>Numpy数组的形状和元素个数</strong></p>

<p>使用函数<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">np.shape()</span>和<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">np.size()</span>也可得到数组的形状和元素个数</p>

<pre>
<code>print(np.shape(M)) print(np.size(M))</code></pre>

<p>输出为:</p>

<pre>
<code>(3,2)
6</code></pre>

<p>&nbsp;</p>

<p>到目前为止<span style="background-color: rgb(250, 250, 250); color: rgb(56, 58, 66); font-family: &quot;Source Code Pro&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Ubuntu Mono&quot;, &quot;Anonymous Pro&quot;, &quot;Droid Sans Mono&quot;, Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; font-size: 12px;">numpy.ndarray</span>看起来非常像Python列表(或嵌套列表)。为什么不简单地使用Python列表来进行计算,而不是创建一个新的数组类型?</p>

<p>下面有几个原因:</p>

<ul start="1">
        <li data-list="bullet">
        <p>Python列表非常普遍。它们可以包含任何类型的对象。它们是动态类型的。它们不支持矩阵和点乘等数学函数。由于动态类型的关系,为Python列表实现这类函数的效率不是很高。</p>
        </li>
        <li data-list="bullet">
        <p>Numpy数组是静态类型的和同构的。元素的类型是在创建数组时确定的。</p>
        </li>
        <li data-list="bullet">
        <p>Numpy数组是内存高效的。</p>
        </li>
        <li data-list="bullet">
        <p>由于是静态类型,数学函数的快速实现,比如&ldquo;numpy&rdquo;数组的乘法和加法可以用编译语言实现(使用C和Fortran).</p>
        </li>
</ul>

<p>&nbsp;</p>

<p><strong>Numpy数组的数据类型</strong></p>

<p>利用ndarray的属性函数dtype(数据类型),可以得出数组的数据类型</p>

<pre>
<code>M.dtype</code></pre>

<p>输出为:</p>

<pre>
<code>dtype('int64')</code></pre>

<p>&nbsp;</p>

<p><strong>Numpy数组的错误类型复制</strong></p>

<pre>
<code>M = "Hello"</code></pre>

<p>输出为:</p>

<pre>
<code>---------------------------------------------------------------------------
ValueError                              Traceback (most recent call last)
Cell In, line 1
----&gt; 1 M = "Hello"

ValueError: invalid literal for int() with base 10: 'Hello'</code></pre>

<p>&nbsp;</p>

<p><strong>Numpy数组的指定类型赋值</strong></p>

<p>要设定数组的数据类型,可用dtype关键字显式地定义创建的数组数据类型</p>

<pre>
<code>M = np.array([, ], dtype=complex)
print(M)</code></pre>

<p>输出为:</p>

<pre>
<code>[
]</code></pre>

<p>dtype常用的数据类型包括int、float、complex、bool、object等,也可显式地定义数据类型的位数,如int64、int16、float128、compl128等。</p>

<p>&nbsp;</p>

<h3>2.使用函数生成数组</h3>

<p>对于较大的数组,使用显式的Python列表人为地初始化数据效率比较低。生成有规律的数组,可以使用下面的函数:</p>

<p><strong>arange()函数</strong></p>

<p>arange()函数的作用是创建等差数组,和Python内置的range函数不同,arange函数还支持浮点数输入。</p>

<p>&nbsp;</p>

<p><strong>linspace() 函数和 logspace()函数</strong></p>

<p>linspace()函数用于创建一个等差数列的一维数组,所创建数组元素的数据格式是浮点型的,一般有三个参数:起始值、终止值(默认包含这个数值)、数的个数。</p>

<p>logspace()函数用于创建等比数列,参数也包含起始值、终止值和数的个数,这里的起始值和终止值是10的幂(默认基数是10)。如果要修改基数,可以通过添加参数base来实现。</p>

<p>&nbsp;</p>

<p><strong>mgrid()函数</strong></p>

<p>mgrid()函数用于返回多维数组,它的三个参数分别是起点、终点和步长。函数左边的返回值按列展开,右边的返回值按行展开。步长是一个隐藏参数,默认为实数1,当步长为实数时,表示按间隔划分,例如0.1表示从起点按0.1递增(左闭右开递增)。</p>

<p>&nbsp;</p>

<p><strong>random()函数</strong></p>

<p>random()函数用于生成随机数组,也可以生成正态分布的随机数。</p>

<p>&nbsp;</p>

<p><strong>zeros()函数和ones()函数</strong></p>

<p>zeros()函数用于生成一个全为0的多维数组,ones()函数用于生成一个全为1的多维数组。</p>

<p>&nbsp;</p>

<h2>访问数组元素</h2>

<h3>1.索引</h3>

<p><strong>下标索引</strong></p>

<p>可以用方括号和下标索引访问特定的元素,如下所示</p>

<pre>
<code>M = np.arry(,,)
print(M)
printf(M)

#如果省略其他索引,则返回整行,或者返回一个N-1维的数组
print(M)

#除了使用索引,还可以使用:来实现相同的效果
print(M) #行1</code></pre>

<p>输出为</p>

<pre>
<code>3
3

</code></pre>

<p>&nbsp;</p>

<p><strong>下标访问</strong></p>

<p>采用索引可给数组中的元素赋新值,如下所示</p>

<pre>
<code>M = 10
M = 0
print(M)</code></pre>

<p>输出为</p>

<pre>
<code>[

]</code></pre>

<p>&nbsp;</p>

<h3>2.切片索引</h3>

<p>切片索引是语法的技术名称,用于访问数组中的部分元素,如表示从下标为1的元素取到下标3的前一个元素。步长参数决定切片的间隔。</p>

<pre>
<code>A = np.array()
print(A)</code></pre>

<p>输出为</p>

<pre>
<code>array()</code></pre>

<p>切片索引是可变的,若为它们分配了新值,则从中提取切片的原始数组将被修改。</p>

<p>在实际使用中,可以省略中任意的零个、一个、两个甚至三个值,而使用默认值。</p>

<p>索引切片工作方式对多维数组的操作与对一维数组的操作类似。</p>

<p>&nbsp;</p>

<h3>3.花式索引</h3>

<p>花式索引利用整数数组作为下标进行索引。与切片索引不同,它将获得的数据复制到新数组中,改变新数组中的值,原数组不变。</p>

<p>还可使用索引掩码进行索引。掩码是布尔数据类型的Numpy数组,一个元素是被选择(True)还是不被选择(False)取决于索引掩码在每个元素位置的布尔值。</p>

<p>这个特性在需要有条件地从数组中选择元素时非常有用。例如,使用比较运算符可以方便地选择特定的元素。</p>

<p>使用where()函数可将索引掩码转换为位置索引。注意,where()函数的输入不同时,返回的输出也不同:若输入是一个一维数组,则返回一个索引数组;若输入是一个二维数组,则返回两个索引数组,这两个索引数组表示所有满足条件的元素的位置。</p>

<p>&nbsp;</p>

<h3>4.遍历数组元素</h3>

<p>通常情况下,应尽可能避免遍历数组元素等操作,因为在Python这样的解释语言中,迭代操作要比向量化操作慢很多。然而,有时程序会不可避免地进行一些迭代操作。对于这种情况,Python的for循环是最方便的遍历数组的方法。</p>

<p>当需要遍历一个数组的每个元素并修改数组的元素时,使用enumerate()函数可以方便地在for循环中获得元素及其索引。</p>

<p>&nbsp;</p>

<h2>文件读写</h2>

<p>在实际开发中,经常需要从文件中读取数据进行处理。Numpy中提供一系列读写文件的方法,下面依次介绍下。</p>

<h3>1.逗号分隔值(CSV)文件</h3>

<p>逗号分隔值文件是一种常见的数据文件格式,要从这些文件中将数据读入Numpy数组,可以使用genfromtxt()函数。genfromtxt()函数用于创建数组表格数据,它先将文件的每行转换成字符串序列,后将每个字符串序列转换成相应的数据类型。</p>

<p>使用NumPy加载CSV文件的方式</p>

<pre>
<code>import numpy as np
data = np.genfromtxt('stockholm_td_adj.dat')
print(data.shape)</code></pre>

<p>输出为</p>

<pre>
<code>(77431,7)</code></pre>

<p>使用np.savetxt()函数可以按照CSV格式来保存NumPy数组。np.savetxt()函数将数据保存至本地,它有两个参数:一个是保存的文件名,另一个是需要保存的数组名;另外,还可以通过添加格式参数来确定想要保存的数据的格式。</p>

<p>&nbsp;</p>

<h3>2.Numpy数据文件</h3>

<p>如果不需要和用其他编程语言编写的程序交互数据,就可将数据保存为NumPy数据文件,np.save()函数用于将文件保存至本地,np.load()用于加载NumPy数组文件。</p>

<p>&nbsp;</p>

<h2>线性代数函数</h2>

<p>向量化计算是使用Python/NumPy编写高效计算程序的关键,这意味着要尽可多地使用矩阵和向量运算来表示计算程序,如矩阵&mdash;&mdash;矩阵乘法。本届介绍NumPy支持的线性代数运算。</p>

<h3>1.标量数组的四则运算</h3>

<p>常用的算术运算符可用来对标量数组进行四则运算</p>

<pre>
<code>v1 = np.arange(0,5)
print(v1 * 2)
print(v1 + 2)</code></pre>

<p>输出为</p>

<pre>
<code>
</code></pre>

<p>&nbsp;</p>

<h3>2.数组间的元素运算</h3>

<p>对数组进行四则运算时,默认是逐元素运算的。</p>

<p>&nbsp;</p>

<h3>3.矩阵代数</h3>

<p>矩阵的乘法可以使用dot()函数,他的两个参数可以计算矩阵-矩阵、矩阵-向量和向量-向量相乘。使用dot()函数对两个一维数组进行计算时,结果为两个数组的内积;对两个二维数组进行时,结果为两个二维数组所对应的矩阵乘积。</p>

<p>另外,可将数组对象转换成矩阵,这将改变标准算数运算符+、-、*的操作而变成矩阵代数。矩阵是NumPy函数库中不同于数组的数据类型,它可直接对矩阵数据进行计算,还提供基本的统计功能,如转置、求逆等。矩阵是数组的分支,很多时候是通用的,不同的是,矩阵可以使用简单的运算符号,而数组更灵活。</p>

<p>&nbsp;</p>

<h3>4.矩阵求逆</h3>

<p>调用np.linalg.inv()函数可以求矩阵的逆。</p>

<p>&nbsp;</p>

<h2>数据统计</h2>

<p>将数据集存储在NumPy数组中通常是非常有用的。</p>

<h3>1.统一函数的用法</h3>

<p>NumPy函数库提供了许多用于对数组中的数据集进行统计的函数,常用的函数主要包括如下几种:</p>

<ul start="1">
        <li data-list="bullet">
        <p>mean():计算平均值</p>
        </li>
        <li data-list="bullet">
        <p>std():计算标准差</p>
        </li>
        <li data-list="bullet">
        <p>var():计算方差</p>
        </li>
        <li data-list="bullet">
        <p>max():取最大值</p>
        </li>
        <li data-list="bullet">
        <p>min():取最小值</p>
        </li>
        <li data-list="bullet">
        <p>sum():计算各个元素之和</p>
        </li>
        <li data-list="bullet">
        <p>prod():计算所有元素的乘积</p>
        </li>
        <li data-list="bullet">
        <p>trace():计算对角线元素的和</p>
        </li>
</ul>

<p>&nbsp;</p>

<h3>2.数组子集的统计</h3>

<p>为了计算部分数据的统计值,可以使用索引、花式索引或者从其他数组中提取所关心的数据,并计算统计值。</p>

<p>&nbsp;</p>

<h3>3.高维数组的维度</h3>

<p>对高维数组应用min()、max()等函数时,是对整个数组进行计算的。但在很多情况下,需要计算某个维度的数据统计值,而使用axis参数可以根据行或列来决定函数的具体表现。</p>

<p>许多适用于数组和矩阵的函数与方法可以接受相同的关键字参数axis。</p>

<p>&nbsp;</p>

<h2>数组的操作</h2>

<h3>1.数组变形、大小调整和堆叠</h3>

<p>NumPy数组的形状确定后就不需要复制底层数据,这就使得即使是对大型数组,计算机也能进行较快的操作。</p>

<p>&nbsp;</p>

<h3>2.添加、删除维度</h3>

<p>对矩阵进行乘法运算时,两个矩阵对应的维度保持一致才能正确执行。如果两个矩阵的维度不一致,那么可以使用newaxis()函数来增加一个新维度,例如将一个向量转换为列矩阵或行矩阵。</p>

<p>某些情况下,需要删除长度为1的维度,这时可以使用np.squeeze()函数。</p>

<p>&nbsp;</p>

<h3>3.叠加和重复数组</h3>

<p>利用函数repeat()、vstack()、hstack()和concatenate(),可以用较小的向量和矩阵来创建更大的向量和矩阵。repeat()函数用于重复数组中的元素,tile()函数用于横向和纵向地复制元矩阵。</p>

<p>&nbsp;</p>

<h3>4.数组的复制和&ldquo;深度复制&rdquo;</h3>

<p>为了获得高性能,NumPy中的赋值通常不复制底层数据。例如,在函数之间传递对象时,复制数组通常可以避免产生大量不必要的内存复制。</p>

<p>&nbsp;</p>

<h3>5.类型转换</h3>

<p>NumPy数组是静态类型的,而数组的类型一旦创建就不会改变。然而,使用astype()函数[参见类似的asarray()函数]可以显式地将一个数组的类型转换为其他类型,进而创建一个新类型的数组。</p>

<p>&nbsp;</p>

<h1>二、Matplotlib绘图库</h1>

<p>Matplotlib是Python的绘图库,它与Numpy一起使用,提供了有效的MATLAB开源替代方案。它也可与图形工具包一起使用,如PyQt和wxPython,以让自己开发的程序支持图形绘制。Matplotlib库可通过pip或Conda直接安装,十分方便。</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h2>Pyplot</h2>

<p><code>matplotlib.pyplot是一组命令风格的函数,它们使matplotlib的工作方式类似于MATLAB。每个pyplot函数都对图形进行一些更改:例如,创建图形,在图形中创建绘图区域,在绘图区域中绘制一些线,用标签装饰绘图,等等。</code></p>

<h3>1.基本绘图实例:</h3>

<pre>
<code>import numpy as np
import matplotlib.pyplot as plt

#设置x轴的数据和y轴的数据,'x-b'配置绘制的类型和颜色
plt.plot(,, 'x-b')
plt.ylabel('some numbers')
plt.xlabel('variable')
plt.show()</code></pre>

<p>所绘的一条直线如下图所示,折线图中的x和y由plt.plot()函数的前两个参数给出,类型由第三个参数给出。对每对x,y参数,都有一个可选的第三个参数,它是表示图形颜色和线条类型的格式字符串。</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h3>2.<strong>Pyplot支持的绘图样式</strong></h3>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h2>多子图绘制</h2>

<p>类似于MATLAB,Pyplot也有当前图的概念,所有的绘图命令都适用于当前图。例如plt.subplot(nrows,ncols,index)将绘图区域分成nrows行和ncols列,并在第index个子图下绘制。下面代码演示了如何绘制两个子图。</p>

<pre>
<code>import numpy as np
import matplotlib.pyplot as plt

def f(t):
    return np.exp(-t) * np.cos(2*np.pi*t)

t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)

plt.figure(1)
plt.subplot(2,1,1)
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')

plt.subplot(2,1,2)
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
plt.show()</code></pre>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h2>图像处理</h2>

<p>在后面的学习中我们会使用pyplot.imshow()函数显示图像。</p>

<pre>
<code>import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

# 加载图片
img=mpimg.imread('example.png')

imgplot = plt.imshow(img)</code></pre>

<p> &nbsp;</p>

<p>pyplot.imshow()函数函数有一个参数cmap,它提供多种类型的颜色映射。使用时指定cmap参数,可为图像添加一些效果。如以下图像,应用伪彩色方案进行图像绘图。</p>

<pre>
<code>lum_img = img[:,:,0]
plt.imshow(lum_img)</code></pre>

<p> &nbsp;</p>

<pre>
<code># 运用你'hot'彩色地图
plt.imshow(lum_img, cmap="hot")
plt.colorbar()</code></pre>

<p> &nbsp;</p>

<p>&nbsp;</p>

<h1>总结</h1>

<p>本章讲述了Python库的一些基础用法,通过学习,初步掌握了Numpy、Matplotlib库,除此之外,还有很多第三方库可以供我们学习。我们暂时对Python的库学习到这步,下章我们一起学习机器学习的一种基本分类方法&mdash;&mdash;k最近邻算法!</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2024-8-2 07:25

<p>Python常用库还是挺强大的</p>
页: [1]
查看完整版本: 一起读《机器学习算法与实现 —— Python编程与应用实例》- 第3章 Python常用库