<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Sean Bei - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Sean Bei - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 26 May 2026 16:03:42 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/sean/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 什么是数据分析？如何用 Python、Numpy、Pandas、Matplotlib 和 Seaborn 教程可视化数据 ]]>
                </title>
                <description>
                    <![CDATA[ 原文：What is Data Analysis? How to Visualize Data with Python, Numpy, Pandas, Matplotlib & Seaborn Tutorial [https://www.freecodecamp.org/news/exploratory-data-analysis-with-numpy-pandas-matplotlib-seaborn/] ，作者：Aakash NS [https://www.freecodecamp.org/news/author/aakash-n-s/] 数据分析是一个通过统计测量和可视化，从数据中探索、研究和收集洞见的过程。 数据分析的目标是通过揭示趋势、关系和模式来开发一种对数据的理解。 数据分析既是一门科学，也是一门艺术。一方面，它需要你了解统计、可视化技术和数据分析工具，如 Numpy、Pandas 和 Seaborn。 另一方面，它需要你提出有趣的问题来指导研究，然后解释数字和图表以产生有用的见解。 本数据分析教程涵盖以下主题：  1. 什么是数值计算？Python 和 Nu ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/exploratory-data-analysis-with-numpy-pandas-matplotlib-seaborn/</link>
                <guid isPermaLink="false">6590dcca576bb403fc791414</guid>
                
                    <category>
                        <![CDATA[ 数据分析 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Thu, 18 May 2023 06:12:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2023/12/blog-cover-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/exploratory-data-analysis-with-numpy-pandas-matplotlib-seaborn/">What is Data Analysis? How to Visualize Data with Python, Numpy, Pandas, Matplotlib &amp; Seaborn Tutorial</a>，作者：<a href="https://www.freecodecamp.org/news/author/aakash-n-s/">Aakash NS</a></p><!--kg-card-begin: markdown--><p>数据分析是一个通过统计测量和可视化，从数据中探索、研究和收集洞见的过程。</p>
<p>数据分析的目标是通过揭示趋势、关系和模式来开发一种对数据的理解。</p>
<p>数据分析既是一门科学，也是一门艺术。一方面，它需要你了解统计、可视化技术和数据分析工具，如 Numpy、Pandas 和 Seaborn。</p>
<p>另一方面，它需要你提出有趣的问题来指导研究，然后解释数字和图表以产生有用的见解。</p>
<p>本数据分析教程涵盖以下主题：</p>
<ol>
<li><a href="#what-is-numerical-computation-python-and-numpy-for-beginners">什么是数值计算？Python 和 Numpy 入门</a></li>
<li><a href="#how-to-analyze-tabular-data-using-python-and-pandas">如何使用 Python 和 Pandas 分析表格数据</a></li>
<li><a href="#data-visualization-using-python-matplotlib-and-seaborn">使用 Python、Matplotlib 和 Seaborn 进行数据可视化</a></li>
</ol>
<h2 id="pythonnumpy">什么是数值计算？Python 和 Numpy 入门</h2>
<p><img src="https://i.imgur.com/mg8O3kd.png" alt="mg8O3kd" width="1385" height="480" loading="lazy"></p>
<p>上图来源：<a href="https://github.com/elegant-scipy/elegant-scipy/blob/master/figures/NumPy_ndarrays_v2.png">Elegant Scipy</a>。</p>
<p>你可以跟随教程操作并在此处运行代码：<a href="https://jovian.ai/aakashns/python-numerical-computing-with-numpy">https://jovian.ai/aakashns/python-numerical-computing-with-nump</a>y</p>
<p>本节涵盖以下主题：</p>
<ul>
<li>如何在 Python 中处理数值数据</li>
<li>如何将 Python 列表转换为 Numpy 数组</li>
<li>多维 Numpy 数组及其优点</li>
<li>数组操作、广播、索引和切片</li>
<li>如何使用 Numpy 处理 CSV 数据文件</li>
</ul>
<h3 id="python">如何在 Python 中处理数值数据</h3>
<p><strong>数据分析</strong> 中的“数据”通常是指数值数据，如股票价格、销售数据、传感器测量值、体育得分、数据库表等。</p>
<p><a href="https://jovian.ai/outlink?url=https%3A%2F%2Fnumpy.org">Numpy</a> 库为 Python 中的数值计算提供专门的数据结构、函数和其他工具。让我们通过一个例子来看看为何以及如何使用 Numpy 处理数值数据。</p>
<p>假设我们想使用温度、降雨量和湿度这些气象数据来考察一个区域是否适合种苹果。</p>
<p>一个简单的方法是制定苹果的年产量（每公顷吨）与气候条件之间的线性关系，如平均温度（以华氏度为单位）、降雨量（以毫米为单位）和平均相对湿度（以百分比为单位）。</p>
<p><code>苹果产量 = w1 * 温度 + w2 * 降雨量 + w3 * 湿度</code></p>
<p>我们将苹果的产量表示为温度、降雨量和湿度的加权和。</p>
<p>这个方程是一个近似值，因为实际关系不一定是线性的，可能还涉及其他因素。但像这样的简单线性模型用在练习中效果较好。</p>
<p>基于一些历史数据的统计分析，我们大致可以为权重<code>w1</code>，<code>w2</code> 和 <code>w3</code> 提供合理的值。下面例举了一组值：</p>
<p><code>w1, w2, w3 = 0.3, 0.2, 0.5</code></p>
<p>给定一个地区的一些气候数据，我们就可以预测苹果的产量了。以下是一些示例数据：</p>
<p><img src="https://i.imgur.com/TXPBiqv.png" alt="TXPBiqv" width="846" height="330" loading="lazy"></p>
<p>首先，我们定义一些变量来记录一个地区的气候数据。</p>
<pre><code class="language-python">kanto_temp = 73
kanto_rainfall = 67
kanto_humidity = 43
</code></pre>
<p>然后，我们就可以将这些变量代入线性方程来预测苹果的产量了。</p>
<pre><code class="language-python">kanto_yield_apples = kanto_temp * w1 + kanto_rainfall * w2 + kanto_humidity * w3
kanto_yield_apples
# 56.8

print("The expected yield of apples in Kanto region is {} tons per hectare.".format(kanto_yield_apples))
# Kanto 地区苹果的预期产量为每公顷 56.8 吨。
</code></pre>
<p>为了能更容易地对多个区域执行上述的计算，我们可以将每个区域的气候数据表示为向量，即数字列表。</p>
<pre><code class="language-python">kanto = [73, 67, 43]
johto = [91, 88, 64]
hoenn = [87, 134, 58]
sinnoh = [102, 43, 37]
unova = [69, 96, 70]
</code></pre>
<p>每个向量中的三个数字分别代表温度、降雨量和湿度数据。</p>
<p>我们还可以将公式中使用的权重集表示为一个向量。</p>
<p><code>weights = [w1, w2, w3]</code></p>
<p>现在我们就可以编写一个函数 <code>crop_yield</code>，通过给定的气候数据和相应权重，来计算苹果（或任何其他作物）的产量了。</p>
<pre><code class="language-python">def crop_yield(region, weights):
    result = 0
    for x, w in zip(region, weights):
        result += x * w
    return result
    
crop_yield(kanto, weights)
# 56.8

crop_yield(johto, weights)
# 76.9

crop_yield(unova, weights)
# 74.9
</code></pre>
<h3 id="pythonnumpy">如何将 Python 列表转换为 Numpy 数组</h3>
<p><code>crop_yield</code> 执行的计算（两个向量的元素相乘并对结果求和）也称为 <strong>点积</strong>。从 <a href="https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/dot-cross-products/v/vector-dot-product-and-vector-length">这里</a> 了解更多点积的信息。</p>
<p>Numpy 库提供了一个内置函数来计算两个向量的点积。但是，我们必须先将列表转换为 Numpy 数组才行。</p>
<p>我们使用 <code>pip</code> 包管理器安装 Numpy 库。</p>
<p><code>!pip install numpy --upgrade --quiet</code></p>
<p>接下来，让我们导入 <code>numpy</code> 模块。导入 <code>numpy</code> 时通常使用别名 <code>np</code>。</p>
<p><code>import numpy as np</code></p>
<p>现在，我们可以使用 <code>np.array</code> 函数创建 Numpy 数组。</p>
<pre><code class="language-python">kanto = np.array([73, 67, 43])

kanto
# array([73, 67, 43])

weights = np.array([w1, w2, w3])

weights
# array([0.3, 0.2, 0.5])
</code></pre>
<p>Numpy 数组的类型为 <code>ndarray</code>。</p>
<pre><code class="language-python">type(kanto)
# numpy.ndarray

type(weights)
# numpy.ndarray
</code></pre>
<p>与列表一样，Numpy 数组也支持索引符号 <code>[]</code>。</p>
<pre><code class="language-python">weights[0]
# 0.3

kanto[2]
#43
</code></pre>
<h3 id="numpy">如何操作 Numpy 数组</h3>
<p>我们可以使用 <code>np.dot</code> 函数来计算两个向量的点积。</p>
<pre><code class="language-python">np.dot(kanto, weights)
# 56.8
</code></pre>
<p>我们可以通过 Numpy 数组支持的底层操作实现相同的结果：执行元素相乘并计算所得数字之和。</p>
<pre><code class="language-python">(kanto * weights).sum()
# 56.8
</code></pre>
<p>如果两个数组的大小相同，<code>*</code> 操作符将执行元素相乘。<code>sum</code> 方法计算数组中数字的总和。</p>
<pre><code class="language-python">arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

arr1 * arr2
# array([ 4, 10, 18])

arr2.sum()
# 15
</code></pre>
<h3 id="numpy">使用 Numpy 数组有什么好处？</h3>
<p>与 Python 的列表相比，Numpy 数组在操作数值数据方面具有以下优势：</p>
<ul>
<li>**它们很容易 <strong>使用</strong>：你可以编写像 <code>(kanto * weights).sum()</code> 这样的小型、简洁和直观的数学表达式，而不是使用循环和自定义函数（如 <code>crop_yield</code>）。</li>
<li><strong>性能</strong>：Numpy 的操作和函数由 C++ 内部实现，这使得它们比使用 Python 的语句和循环快得多，因为后者是在运行时解释的。</li>
</ul>
<p>以下是对 Python 循环和 Numpy 数组执行的点积的比较，使用两个向量，每个都有一百万个元素。</p>
<pre><code># Python lists
arr1 = list(range(1000000))
arr2 = list(range(1000000, 2000000))

# Numpy arrays
arr1_np = np.array(arr1)
arr2_np = np.array(arr2)

%%time
result = 0
for x1, x2 in zip(arr1, arr2):
    result += x1*x2
result

# CPU times: user 300 ms, sys: 3.26 ms, total: 303 ms
# Wall time: 302 ms
# 833332333333500000

%%time
np.dot(arr1_np, arr2_np)

# CPU times: user 2.11 ms, sys: 951 µs, total: 3.07 ms
# Wall time: 1.58 ms
# 833332333333500000
</code></pre>
<p>如你所见，使用 <code>np.dot</code> 比使用 <code>for</code> 循环快 100 倍。这使得 Numpy 处理非常大的数据集时非常有用，特别是那些具有数万或数百万个数据点时。</p>
<h3 id="numpy">多维 Numpy 数组</h3>
<p>现在让我们更进一步，使用单个二维 Numpy 数组来表示所有地区的气候数据。</p>
<pre><code>climate_data = np.array([[73, 67, 43],
                         [91, 88, 64],
                         [87, 134, 58],
                         [102, 43, 37],
                         [69, 96, 70]])
                         
climate_data
# array([[ 73,  67,  43],
#        [ 91,  88,  64],
#        [ 87, 134,  58],
#        [102,  43,  37],
#        [ 69,  96,  70]])
</code></pre>
<p>如果你在高中时学过线性代数课，你会把上面的二维数组看作是一个五行三列的矩阵。每一行代表一个区域，列分别代表温度、降雨量和湿度。</p>
<p>Numpy 数组可以有任意数量的维度，每个维度可以有不同的长度。可以通过数组的 <code>.shape</code> 属性来检查每个维度的长度。</p>
<p><img src="https://fgnt.github.io/python_crashkurs_doc/_images/numpy_array_t.png" alt="numpy_array_t" width="1440" height="805" loading="lazy"></p>
<p>上图来源：<a href="https://github.com/elegant-scipy/elegant-scipy/blob/master/figures/NumPy_ndarrays_v2.png">Elegant Scipy</a>。</p>
<pre><code># 2D array (matrix)
climate_data.shape
# (5, 3)

weights
# array([0.3, 0.2, 0.5])

# 1D array (vector)
weights.shape
# (3,)

# 3D array 
arr3 = np.array([
    [[11, 12, 13], 
     [13, 14, 15]], 
    [[15, 16, 17], 
     [17, 18, 19.5]]])

arr3.shape
# (2, 2, 3)
</code></pre>
<p>Numpy 数组中的所有元素都具有相同的数据类型。你可以使用 <code>.dtype</code> 属性检查数组的数据类型。</p>
<pre><code>weights.dtype
# dtype('float64')

climate_data.dtype
# dtype('int64')
</code></pre>
<p>如果数组中包含一个浮点数，所有其他元素也会转换为浮点数。</p>
<pre><code>arr3.dtype
# dtype('float64')
</code></pre>
<p>通过 <code>climate_data</code> （一个 5x3 的矩阵）和 <code>weights</code> （一个长度为 3 的向量）之间的单一矩阵乘法，我们就可以计算出所预测的苹果产量了。看起来就像下面这样：</p>
<p><img src="https://i.imgur.com/LJ2WKSI.png" alt="LJ2WKSI" width="578" height="334" loading="lazy"></p>
<p>通过观看<a href="https://www.youtube.com/watch?v=xyAuNHPsq-g&amp;list=PLFD0EB975BA0CC1E0&amp;index=1">这个 YouTube 播放列表</a>的前 3-4 个视频，你可以学到矩阵及矩阵乘法。</p>
<p>我们可以使用 <code>np.matmul</code> 函数或者 <code>@</code> 操作符来执行矩阵乘法。</p>
<pre><code>np.matmul(climate_data, weights)
# array([56.8, 76.9, 81.9, 57.7, 74.9])

climate_data @ weights
# array([56.8, 76.9, 81.9, 57.7, 74.9])
</code></pre>
<h3 id="csv">如何处理 CSV 数据文件</h3>
<p>Numpy 同样提供辅助函数来对文件进行读写。我们来下载一个文件 <code>climate.txt</code>，它包含了 10,000 个气候测量结果（温度、降雨量和湿度），格式如下：</p>
<pre><code>temperature,rainfall,humidity
25.00,76.00,99.00
39.00,65.00,70.00
59.00,45.00,77.00
84.00,63.00,38.00
66.00,50.00,52.00
41.00,94.00,77.00
91.00,57.00,96.00
49.00,96.00,99.00
67.00,20.00,28.00
...
</code></pre>
<p>这种存储数据的格式称为 <strong>comma-separated values</strong> 或者 CSV。</p>
<blockquote>
<p><strong><strong>CSVs</strong></strong>：逗号分隔值（CSV）文件是使用逗号分隔值的分隔文本文件。文件的每一行就是一条数据记录。每条记录包括一个或多个字段，以逗号隔开。CSV 文件通常以纯文本形式存储表格数据（数字和文本），因此每行都有相同数量的字段。（维基百科）</p>
</blockquote>
<p>我们使用 <code>genfromtxt</code> 函数来把这个文件读入一个到 numpy 数组中。</p>
<pre><code>import urllib.request

urllib.request.urlretrieve(
    'https://hub.jovian.ml/wp-content/uploads/2020/08/climate.csv', 
    'climate.txt')
    
climate_data = np.genfromtxt('climate.txt', delimiter=',', skip_header=1)

climate_data
# array([[25., 76., 99.],
#        [39., 65., 70.],
#        [59., 45., 77.],
#        ...,
#        [99., 62., 58.],
#        [70., 71., 91.],
#        [92., 39., 76.]])

climate_data.shape
# (10000, 3)
</code></pre>
<p>现在，我们可以使用 <code>@</code> 运算符执行矩阵乘法，利用给定的权重集预测整个数据集的苹果产量。</p>
<pre><code>weights = np.array([0.3, 0.2, 0.5])

yields = climate_data @ weights
yields
# array([72.2, 59.7, 65.2, ..., 71.1, 80.7, 73.4])

yields.shape
# (10000,)
</code></pre>
<p>让我们使用 <a href="https://numpy.org/doc/stable/reference/generated/numpy.concatenate.html"><code>np.concatenate</code></a> 函数将产量添加到 <code>climate_data</code> 中，作为第四列。</p>
<pre><code>climate_results = np.concatenate((climate_data, yields.reshape(10000, 1)), axis=1)

climate_results
# array([[25. , 76. , 99. , 72.2],
#        [39. , 65. , 70. , 59.7],
#        [59. , 45. , 77. , 65.2],
#        ...,
#        [99. , 62. , 58. , 71.1],
#        [70. , 71. , 91. , 80.7],
#        [92. , 39. , 76. , 73.4]])
</code></pre>
<p>这里有几个微妙之处：</p>
<ul>
<li>由于我们希望添加新列，我们把参数 <code>axis=1</code> 传给 <code>np.concatenate</code>。<code>axis</code> 参数指定了串联的维度。</li>
<li>数组必须有相同数量的维度，每个维度长度要相同，除了用于串联的维度。我们使用 <a href="https://jovian.ai/outlink?url=https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Freference%2Fgenerated%2Fnumpy.reshape.html"><code>np.reshape</code></a> 函数来将 <code>yields</code> 的形状从 <code>(10000,)</code> 改到 <code>(10000,1)</code>。</li>
</ul>
<p>以下是在 <code>axis=1</code> 时 <code>np.concatenate</code> 的一个直观解释（你能猜出 <code>axis=0</code> 的结果是什么吗？）：</p>
<p><img src="https://www.w3resource.com/w3r_images/python-numpy-image-exercise-58.png" alt="python-numpy-image-exercise-58" width="576" height="536" loading="lazy"></p>
<p>上图来源：<a href="https://chinese.freecodecamp.org/news/exploratory-data-analysis-with-numpy-pandas-matplotlib-seaborn/w3resource.com">w3resource.com</a>。</p>
<p>理解 Numpy 函数的最好方式是是对其进行试验并阅读文档以了解其参数和返回值。使用下面的单元格来试验 <code>np.concatenate</code> 和 <code>np.reshape</code>。</p>
<p>让我们使用 <code>np.savetxt</code> 函数来将上面计算的最终结果写回到文件中。</p>
<pre><code>np.savetxt('climate_results.txt', 
           climate_results, 
           fmt='%.2f', 
           delimiter=',',
           header='temperature,rainfall,humidity,yeild_apples', 
           comments='')
</code></pre>
<p>结果以 CSV 格式写回文件 <code>climate_results.txt</code>。</p>
<pre><code>temperature,rainfall,humidity,yeild_apples
25.00,76.00,99.00,72.20
39.00,65.00,70.00,59.70
59.00,45.00,77.00,65.20
84.00,63.00,38.00,56.80
...
</code></pre>
<p>Numpy 提供了数百个用于对数组执行操作的函数。以下是一些常用的函数：</p>
<ul>
<li>数学：<code>np.sum</code>、<code>np.exp</code>、<code>np.round</code>，以及算术运算符</li>
<li>数组操作：<code>np.reshape</code>、<code>np.stack</code>、<code>np.concatenate</code>、<code>np.split</code></li>
<li>线性代数：<code>np.matmul</code>、<code>np.dot</code>、<code>np.transpose</code>、<code>np.eigvals</code></li>
<li>统计：<code>np.mean</code>、<code>np.median</code>、<code>np.std</code>、<code>np.max</code></li>
</ul>
<p><strong>那么如何找到你需要的函数呢？</strong> 要找到特定操作或用例的正确函数，最简单的方法就是网络搜索。例如，搜索“如何连接 numpy 数组”，就会找到<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fcmdlinetips.com%2F2018%2F04%2Fhow-to-concatenate-arrays-in-numpy%2F">数组连接教程</a>。</p>
<p>你可以在这里找到<a href="https://numpy.org/doc/stable/reference/routines.html">数组函数的完整列表</a>.</p>
<h3 id="numpy">Numpy 算术运算、广播和比较</h3>
<p>Numpy 数组支持像 <code>+</code>，<code>-</code>，<code>*</code> 等的算术运算。你可以对一个单一的数字（也称为标量）或者具有同样形状的数组进行算术运算。</p>
<p>运算符让编写具有多维数组的数学表达式变得很容易。</p>
<pre><code>arr2 = np.array([[1, 2, 3, 4], 
                 [5, 6, 7, 8], 
                 [9, 1, 2, 3]])
                 
arr3 = np.array([[11, 12, 13, 14], 
                 [15, 16, 17, 18], 
                 [19, 11, 12, 13]])
                 
# Adding a scalar
arr2 + 3

# array([[ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12,  4,  5,  6]])

# Element-wise subtraction
arr3 - arr2

# array([[10, 10, 10, 10],
#        [10, 10, 10, 10],
#        [10, 10, 10, 10]])

# Division by scalar
arr2 / 2

# array([[0.5, 1. , 1.5, 2. ],
#        [2.5, 3. , 3.5, 4. ],
#        [4.5, 0.5, 1. , 1.5]])

# Element-wise multiplication
arr2 * arr3

# array([[ 11,  24,  39,  56],
#        [ 75,  96, 119, 144],
#        [171,  11,  24,  39]])

# Modulus with scalar
arr2 % 4

# array([[1, 2, 3, 0],
#        [1, 2, 3, 0],
#        [1, 1, 2, 3]])
</code></pre>
<h4 id="numpy"><strong>Numpy 数组广播</strong></h4>
<p>Numpy 数组也支持 <strong>广播</strong>，允许在具有不同维数但形状兼容的两个数组之间进行算术运算。让我们通过一个例子来看看它是如何工作的。</p>
<pre><code>arr2 = np.array([[1, 2, 3, 4], 
                 [5, 6, 7, 8], 
                 [9, 1, 2, 3]])               
arr2.shape
# (3, 4)

arr4 = np.array([4, 5, 6, 7])
arr4.shape
# (4,)

arr2 + arr4
# array([[ 5,  7,  9, 11],
#        [ 9, 11, 13, 15],
#        [13,  6,  8, 10]])
</code></pre>
<p>当计算表达式 <code>arr2 + arr4</code> 时，<code>arr4</code> (形状为 <code>(4,)</code>）被复制了三次以匹配 <code>arr2</code> 的形状 <code>(3, 4)</code>。Numpy 执行复制时，并不真实地去创建较小维度数组的三个副本，这样就提高了性能，并使用更少的内存。</p>
<p><img src="https://jakevdp.github.io/PythonDataScienceHandbook/figures/02.05-broadcasting.png" alt="02.05-broadcasting" width="432" height="324" loading="lazy"></p>
<p>上图来源：<a href="https://jakevdp.github.io/PythonDataScienceHandbook/02.05-computation-on-arrays-broadcasting.html">Python 数学科学手册</a>。</p>
<p>只有当一个数组可以复制以匹配另一个数组的形状时，广播才有效。</p>
<pre><code>arr5 = np.array([7, 8])
arr5.shape
# (2,)

arr2 + arr5
# ValueError: operands could not be broadcast together with shapes (3,4) (2,) 
</code></pre>
<p>在上面的例子中，即使 <code>arr5</code> 被复制三次，它并不能匹配 <code>arr2</code> 的形状。所以无法成功计算 <code>arr2 + arr5</code>。<a href="https://numpy.org/doc/stable/user/basics.broadcasting.html">在此处学习有关广播的更多信息</a>.</p>
<h4 id="numpy"><strong>Numpy 数组比较</strong></h4>
<p>Numpy 数组也支持像 <code>==</code>、<code>!=</code>、<code>&gt;</code> 等这样的比较操作符。比较结果是一个布尔值数组。</p>
<pre><code>arr1 = np.array([[1, 2, 3], [3, 4, 5]])
arr2 = np.array([[2, 2, 3], [1, 2, 5]])

arr1 == arr2
# array([[False,  True,  True],
#        [False, False,  True]])

arr1 != arr2
# array([[ True, False, False],
#        [ True,  True, False]])

arr1 &gt;= arr2
# array([[False,  True,  True],
#        [ True,  True,  True]])

arr1 &lt; arr2
# array([[ True, False, False],
#        [False, False, False]])
</code></pre>
<p>数组比较经常使用 <code>sum</code> 方法来计算两个数组中相等元素的数量。请记住，在算术运算中使用布尔值时，<code>True</code> 被视为 <code>1</code>，而<code>False</code> 被视为 <code>0</code>。</p>
<pre><code>(arr1 == arr2).sum()
# 3
</code></pre>
<h3 id="numpy">Numpy 数组索引和切片</h3>
<p>Numpy 以一种直观的方式，将 Python 的列表索引符号 <code>[]</code> 扩展到多个维度。你可以提供一个以逗号分隔的索引或范围列表，来从 Numpy 数组中选择一个指定的元素或者一个子数组（也称为切片）。</p>
<pre><code class="language-python">arr3 = np.array([
    [[11, 12, 13, 14], 
     [13, 14, 15, 19]], 
    
    [[15, 16, 17, 21], 
     [63, 92, 36, 18]], 
    
    [[98, 32, 81, 23],      
     [17, 18, 19.5, 43]]])
     
arr3.shape
# (3, 2, 4)

# Single element
arr3[1, 1, 2]

# 36.0

# Subarray using ranges
arr3[1:, 0:1, :2]

# array([[[15., 16.]],
# 
#        [[98., 32.]]])

# Mixing indices and ranges
arr3[1:, 1, 3]

# array([18., 43.])

arr3[1:, 1, :3]
# array([[63. , 92. , 36. ],
#        [17. , 18. , 19.5]])

# Using fewer indices
arr3[1]

# array([[15., 16., 17., 21.],
#        [63., 92., 36., 18.]])

arr3[:2, 1]
# array([[13., 14., 15., 19.],
#        [63., 92., 36., 18.]])

# Using too many indices
arr3[1,3,2,1]

# IndexError: too many indices for array: array is 3-dimensional, but 4 were indexed
</code></pre>
<p>符号及其结果起初看起来会有点困惑，因此请花点时间进行实验并适应它。</p>
<p>请用下面的单元格，使用不同的索引和范围组合，尝试进行数组索引和切片的一些示例。以下是一些直观演示的示例：</p>
<p><img src="https://scipy-lectures.org/_images/numpy_indexing.png" alt="numpy_indexing" width="772" height="383" loading="lazy"></p>
<p>上图来源：<a href="https://scipy-lectures.org/intro/numpy/array_object.html">Scipy 讲座</a>。</p>
<h3 id="numpy">如何用其他方法创建 Numpy 数组</h3>
<p>Numpy 还提供了一些简便的函数来创建具有固定或随机形状的数组。查阅<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Freference%2Froutines.array-creation.html">官方文档</a>或者使用 <code>help</code> 函数来了解更多。</p>
<pre><code># All zeros
np.zeros((3, 2))

# array([[0., 0.],
#        [0., 0.],
#        [0., 0.]])

# All ones
np.ones([2, 2, 3])

# array([[[1., 1., 1.],
#         [1., 1., 1.]],
#
#        [[1., 1., 1.],
#         [1., 1., 1.]]])

# Identity matrix
np.eye(3)

# array([[1., 0., 0.],
#        [0., 1., 0.],
#        [0., 0., 1.]])

# Random vector
np.random.rand(5)

# array([0.92929562, 0.11301864, 0.64213555, 0.8600434 , 0.53738656])

# Random matrix
np.random.randn(2, 3) # rand vs. randn - what's the difference?

# array([[ 0.09906435, -1.64668094,  0.08073528],
#        [ 0.1437016 ,  0.80715712,  1.27285476]])

# Fixed value
np.full([2, 3], 42)

# array([[42, 42, 42],
#        [42, 42, 42]])

# Range with start, end and step
np.arange(10, 90, 3)

# array([10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58,
#        61, 64, 67, 70, 73, 76, 79, 82, 85, 88])

# Equally spaced numbers in a range
np.linspace(3, 27, 9)

# array([ 3.,  6.,  9., 12., 15., 18., 21., 24., 27.])
</code></pre>
<h3 id="">练习</h3>
<p>尝试以下练习来熟悉 Numpy 数组，锻炼你的技能：</p>
<ul>
<li>Numpy 数组函数的赋值：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fjovian.ml%2Faakashns%2Fnumpy-array-operations">https://jovian.ml/aakashns/numpy-array-operations</a></li>
<li>（选做）100个 Numpy 小练习：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fjovian.ml%2Faakashns%2F100-numpy-exercises">https://jovian.ml/aakashns/100-numpy-exercises</a></li>
</ul>
<h3 id="">总结和进一步阅读</h3>
<p>到此，我们完成了用 Numpy 进行数值计算的讨论。本教程的这一部分，我们介绍了以下主题：</p>
<ul>
<li>如何从 Python 列表转到 Numpy 数组</li>
<li>如何操作 Numpy 数组</li>
<li>相对列表而言，使用 Numpy 数组的优势</li>
<li>多维 Numpy 数组</li>
<li>如何处理 CSV 数据文件</li>
<li>算术运算与广播</li>
<li>数组索引和切片</li>
<li>创建 Numpy 的其他方法</li>
</ul>
<p>查阅以下资源以学习更多 Numpy 知识：</p>
<ul>
<li><a href="https://numpy.org/devdocs/user/quickstart.html">官方文档</a></li>
<li><a href="https://chinese.freecodecamp.org/news/the-ultimate-guide-to-the-numpy-scientific-computing-library-for-python/">freeCodeCamp 上的 Numpy 教程</a></li>
<li><a href="http://scipy-lectures.org/advanced/advanced_numpy/index.html">高级 Numpy（探索内部结构）</a></li>
</ul>
<h3 id="">回顾问题以检验你的掌握程度</h3>
<p>尝试回答以下问题来测试你对本文前面话题的掌握程度：</p>
<ol>
<li>什么是向量？</li>
<li>如何用 Python 列表来表示向量？请举例。</li>
<li>什么是两个向量的点积？</li>
<li>写一个函数来计算两个向量的点积。</li>
<li>什么是 Numpy？</li>
<li>如何安装 Numpy？</li>
<li>如何导入 <code>numpy</code> 模块？</li>
<li>用别名导入一个模块意味着什么？请举例。</li>
<li>通常使用的 <code>numpy</code> 别名是什么？</li>
<li>什么是 Numpy 数组？</li>
<li>如何创建 Numpy 数组？请举例。</li>
<li>什么是 Numpy 数组的类型？</li>
<li>如何访问 Numpy 数组的元素？</li>
<li>如何使用 Numpy 计算两个向量的点积？</li>
<li>如果尝试计算具有不同大小的两个向量的点积，会怎么样？</li>
<li>如何计算两个 Numpy 数组的元素乘积？</li>
<li>如何计算 Numpy 数组中所有元素的总和？</li>
<li>相对 Python 列表，使用 Numpy 数组处理数值数据的优势是什么？</li>
<li>为什么 Numpy 数组操作比 Python 函数和循环具有更好的性能？</li>
<li>举例说明 Numpy 数组操作和 Python 循环之间的性能差异。</li>
<li>什么是多维 Numpy 数组？</li>
<li>举例说明如何创建 2、3 和 4 维的 Numpy 数组。</li>
<li>如何查看 Numpy 数组的维度数量以及每个维度的长度？</li>
<li>Numpy 数组中的元素可以有不同的数据类型吗？</li>
<li>如何查看 Numpy 数组中元素的数据类型？</li>
<li>Numpy 数组的数据类型是什么？</li>
<li>矩阵和二维 Numpy 数组的区别是什么？</li>
<li>如何用 Numpy 执行矩阵乘法？</li>
<li>Numpy 中的 <code>@</code> 操作符用于做什么？</li>
<li>什么是 CSV 文件格式？</li>
<li>如何使用 Numpy 从 CSV 文件中读取数据？</li>
<li>如何连接两个 Numpy 数组？</li>
<li><code>np.concatenate</code> 的 <code>axis</code> 参数的作用是什么？</li>
<li>什么时候两个 Numpy 数组可以兼容连接？</li>
<li>给出一个能进行连接的两个 Numpy 数组的例子。</li>
<li>给出一个不能进行连接的两个 Numpy 数组的例子。</li>
<li><code>np.reshape</code> 函数的作用是什么？</li>
<li>“reshape”一个 Numpy 数组是什么意思？</li>
<li>如何将 numpy 数组写入 CSV 文件？</li>
<li>给出一些用于执行数学运算的 Numpy 函数示例。</li>
<li>给出一些用于执行数组操作的 Numpy 函数示例。</li>
<li>给出一些用于执行线性代数的 Numpy 函数示例。</li>
<li>给出一些用于执行统计运算的 Numpy 函数示例。</li>
<li>如何为特定操作或用例找到正确的 Numpy 函数？</li>
<li>在哪里可以看到所有 Numpy 数组函数和操作的列表？</li>
<li>Numpy 数组支持哪些算术运算符？举例说明。</li>
<li>什么是数组广播？它如何有用？举例说明。</li>
<li>给出一些兼容广播的数组的例子。</li>
<li>给出一些不兼容广播的数组的例子。</li>
<li>Numpy 数组支持哪些比较运算符？举例说明。</li>
<li>如何从 Numpy 数组访问特定的子数组或切片？</li>
<li>通过一些示例说明多维 Numpy 数组中的数组索引和切片。</li>
<li>如何创建一个全为0的给定形状的 Numpy 数组？</li>
<li>如何创建一个全为1的给定形状的 Numpy 数组？</li>
<li>如何创建给定形状的单位矩阵？</li>
<li>如何创建一个给定长度的随机向量？</li>
<li>如何创建给定形状且每个元素具有固定值的Numpy数组？</li>
<li>如何创建给定形状且每个元素具有随机初始值的Numpy数组？</li>
<li><code>np.random.rand</code> 与 <code>np.random.randn</code> 的区别是什么？举例说明。</li>
<li><code>np.arange</code> 与 <code>np.linspace</code> 的区别是什么？举例说明。</li>
</ol>
<p>现在，你已经准备好进入本教程的下一节了。</p>
<h2 id="pythonpandas">如何用 Python 和 Pandas 分析表格数据</h2>
<p><img src="https://i.imgur.com/zfxLzEv.png" alt="zfxLzEv" width="3175" height="1414" loading="lazy"></p>
<p>按照下面的步骤运行代码：<a href="https://jovian.ai/aakashns/python-pandas-data-analysis">https://jovian.ai/aakashns/python-pandas-data-analysis</a>。</p>
<p>本节包含以下主题：</p>
<ul>
<li>如何将 CSV 文件读入到 Pandas 数据帧</li>
<li>如何从 Pandas 数据帧中获得数据</li>
<li>如何查询、排序和分析数据</li>
<li>如何合并、分组和汇总数据</li>
<li>如何从日期中提取有用信息</li>
<li>使用直线图和条形图进行基本绘图</li>
<li>如何将数据帧写到 CSV 文件中</li>
</ul>
<h3 id="pandascsv">如何用 Pandas 读取 CSV 文件</h3>
<p><a href="https://jovian.ai/outlink?url=https%3A%2F%2Fpandas.pydata.org%2F">Pandas</a> 是一个非常流行的 Python 库，用于处理表格数据（类似于存在电子表格中的数据）。 它提供了辅助函数，用以从各种文件格式（如CSV、Excel电子表格、HTML表格、JSON、SQL等）中读取数据。</p>
<p>我们下载一个文件 <code>italy-covid-daywise.txt</code>，里面包含了意大利每日的 Covid-19 数据，格式如下：</p>
<pre><code>date,new_cases,new_deaths,new_tests
2020-04-21,2256.0,454.0,28095.0
2020-04-22,2729.0,534.0,44248.0
2020-04-23,3370.0,437.0,37083.0
2020-04-24,2646.0,464.0,95273.0
2020-04-25,3021.0,420.0,38676.0
2020-04-26,2357.0,415.0,24113.0
2020-04-27,2324.0,260.0,26678.0
2020-04-28,1739.0,333.0,37554.0
...
</code></pre>
<p>这种存储数据的格式被称为 <strong>comma-separated values</strong> 或者 CSV。如果你需要 CSV 格式的定义，可以参考以下：</p>
<blockquote>
<p><strong>CSVs</strong>：逗号分隔值（CSV）文件是一种用逗号分隔数值的分隔文本文件。文件中的每一行都是一条数据记录。每一条记录包含一个或多个字段，以逗号隔开。CSV 文件通常以纯文本形式存储表格数据（数字和文本），每一行拥有相同数量的字段。（维基百科）</p>
</blockquote>
<p>我们使用 <code>urlretrieve</code> 函数从 <code>urllib.request</code> 模块中下载这个文件。</p>
<pre><code>from urllib.request import urlretrieve

urlretrieve('https://hub.jovian.ml/wp-content/uploads/2020/09/italy-covid-daywise.csv', 'italy-covid-daywise.csv')
</code></pre>
<p>要读取文件，我们可以使用 Pandas 的 <code>read_csv</code> 方法。首先，让我们安装 Pandas 库。</p>
<pre><code>!pip install pandas --upgrade --quiet
</code></pre>
<p>现在我们可以导入 <code>pandas</code> 模块。按照惯例，导入时会使用别名 <code>pd</code>。</p>
<pre><code>import pandas as pd

covid_df = pd.read_csv('italy-covid-daywise.csv')
</code></pre>
<p>文件中的数据被读取并存到 <code>DataFrame</code> 对象——它是 Pandas 中的一个核心数据结构，用于存储和处理表格数据。通常我们在数据帧的变量名称中使用 <code>_df</code> 后缀。</p>
<pre><code>type(covid_df)
# pandas.core.frame.DataFrame

covid_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-110.png" class="kg-image" alt="image-110" width="600" height="400" loading="lazy"></figure>
<p>以下是我们通过查看数据帧可以得知的信息：</p>
<ul>
<li>该文件提供了意大利新冠肺炎的四项每日计数</li>
<li>报告的指标是确诊病例、死亡人数和测试人数</li>
<li>提供了248天的数据：从2019年12月12日到2020年9月3日</li>
</ul>
<p>请记住，这些是官方报告的数字。实际病例和死亡人数可能更高，因为并非所有病例都被诊断出来。</p>
<p>我们可以通过 <code>.info</code> 方法来查看数据帧的一些基本信息。</p>
<pre><code>covid_df.info()
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-109.png" class="kg-image" alt="image-109" width="600" height="400" loading="lazy"></figure>
<p>看起来每一列都包含了一种特定数据类型的值。你可以通过 <code>.describe</code> 方法来查看数值列的统计信息（平均值、标准偏差、最小值/最大值和非空值的数量）。</p>
<pre><code>covid_df.describe()
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-110.png" class="kg-image" alt="image-110" width="600" height="400" loading="lazy"></figure>
<p><code>columns</code> 属性包含数据帧中的列列表。</p>
<pre><code>covid_df.columns
# Index(['date', 'new_cases', 'new_deaths', 'new_tests'], dtype='object')
</code></pre>
<p>你还可以使用 <code>.shape</code> 方法获取数据帧的行数和列数。</p>
<pre><code>covid_df.shape
# (248, 4)
</code></pre>
<p>下面是我们到目前为止所研究的函数和方法的总结：</p>
<ul>
<li><code>pd.read_csv</code> – 将数据从 CSV 文件中读入到 Pandas 的 <code>DataFrame</code> 对象中</li>
<li><code>.info()</code> – 查看关于行、列和数据类型的基本信息</li>
<li><code>.describe()</code> – 查看数值列的统计信息</li>
<li><code>.columns</code> – 获取一个包含列名的列表</li>
<li><code>.shape</code> – 获取行数和列数作为一个数组</li>
</ul>
<h3 id="pandas">如何从 Pandas 数据帧中检索数据</h3>
<p>你想做的首件事可能是从这个数据帧中检索数据，如一个指定日的计数，或者一个特定列的值列表。</p>
<p>为此，你应该了解数据帧中数据的内部表示方法。从概念上讲，你可以将数据帧视为一个字典列表：键是列名，值是包含相应列数据的列表或数组。</p>
<pre><code class="language-python"># Pandas format is simliar to this
covid_data_dict = {
    'date':       ['2020-08-30', '2020-08-31', '2020-09-01', '2020-09-02', '2020-09-03'],
    'new_cases':  [1444, 1365, 996, 975, 1326],
    'new_deaths': [1, 4, 6, 8, 6],
    'new_tests': [53541, 42583, 54395, None, None]
}
</code></pre>
<p>用上面的格式来表示数据具有以下几个好处：</p>
<ul>
<li>列中的所有值通常具有相同类型的值，因此将它们存储在单个数组中更有效。</li>
<li>检索特定行的值只需要从每个列数组中提取给定索引处的元素。</li>
<li>与其他格式相比，如对每行数据使用字典，这种表示形式更加紧凑（列名只记录一次）（参见下面的示例）。</li>
</ul>
<pre><code class="language-python"># Pandas 格式与此不相似
covid_data_list = [
    {'date': '2020-08-30', 'new_cases': 1444, 'new_deaths': 1, 'new_tests': 53541},
    {'date': '2020-08-31', 'new_cases': 1365, 'new_deaths': 4, 'new_tests': 42583},
    {'date': '2020-09-01', 'new_cases': 996, 'new_deaths': 6, 'new_tests': 54395},
    {'date': '2020-09-02', 'new_cases': 975, 'new_deaths': 8 },
    {'date': '2020-09-03', 'new_cases': 1326, 'new_deaths': 6},
]
</code></pre>
<p>与字典列表进行类比，你大概可以猜到如何从数据帧中检索数据。例如，我们可以使用 <code>[]</code> 索引符号来从一个指定列中获取值列表。</p>
<pre><code class="language-python">covid_data_dict['new_cases']
# [1444, 1365, 996, 975, 1326]

covid_df['new_cases']
# 0         0.0
# 1         0.0
# 2         0.0
# 3         0.0
# 4         0.0
#         ...  
# 243    1444.0
# 244    1365.0
# 245     996.0
# 246     975.0
# 247    1326.0
# Name: new_cases, Length: 248, dtype: float64
</code></pre>
<p>每一列都用名为 <code>Series</code> 的数据结构来表示，它本质上是一个包含额外方法和属性的 numpy 数组。</p>
<pre><code class="language-python">type(covid_df['new_cases'])
# pandas.core.series.Series
</code></pre>
<p>与数组一样，你也可以使用索引符号 <code>[]</code> 通过系列检索特定值。</p>
<pre><code class="language-python">covid_df['new_cases'][246]
# 975.0

covid_df['new_tests'][240]
57640.0
</code></pre>
<p>Pandas 还提供了 <code>.at</code> 方法，可直接检索特定行和列的元素。</p>
<pre><code class="language-python">covid_df.at[246, 'new_cases']
# 975.0

covid_df.at[240, 'new_tests']
# 57640.0
</code></pre>
<p>除了使用索引符号 <code>[]</code>, Pandas 也允许使用 <code>.</code> 符号来将列作为数据帧的属性进行访问。但是，这个方法仅限于那些不包含空字符或者特殊字符的列。</p>
<pre><code>covid_df.new_cases
# 0         0.0
# 1         0.0
# 2         0.0
# 3         0.0
# 4         0.0
#         ...  
# 243    1444.0
# 244    1365.0
# 245     996.0
# 246     975.0
# 247    1326.0
# Name: new_cases, Length: 248, dtype: float64
</code></pre>
<p>更进一步，你可以传递一个列的列表到索引符号 <code>[]</code> 中，用来访问这些列的数据帧的子集。</p>
<pre><code class="language-python">cases_df = covid_df[['date', 'new_cases']]
cases_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-111.png" class="kg-image" alt="image-111" width="600" height="400" loading="lazy"></figure>
<p>新的数据帧 <code>cases_df</code> 只是原始数据帧 <code>covid_df</code> 的“视图”。两者都指向计算机内存中相同的数据。在其中一个更改值，另一个相应的值也会被更改。</p>
<p>在数据帧之间共享数据使得 Pandas 中的数据操作速度非常快。每次想要操作现有数据帧来创建新数据帧时，你都不必担心复制数千或数百万行导致的性能开销。</p>
<p>有些时候你需要数据帧的完整副本，这时你可以使用 <code>copy</code> 方法。</p>
<pre><code class="language-python">covid_df_copy = covid_df.copy()
</code></pre>
<p><code>covid_df_copy</code> 中的数据与 <code>covid_df</code> 的是完全分开的，改变其中一个的值并不会影响另一个。</p>
<p>要访问特定的数据行，Pandas 提供了<code>.loc</code> 方法。</p>
<pre><code class="language-python">covid_df
</code></pre>
<pre><code class="language-python">covid_df.loc[243]
# date          2020-08-30
# new_cases         1444.0
# new_deaths           1.0
# new_tests        53541.0
# Name: 243, dtype: object
</code></pre>
<p>检索到的每一行也是一个 <code>Series</code> 对象。</p>
<pre><code class="language-python">type(covid_df.loc[243])
# pandas.core.series.Series
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-112.png" class="kg-image" alt="image-112" width="600" height="400" loading="lazy"></figure>
<p>我们可以使用 <code>.head</code> 和 <code>.tail</code> 方法查看数据的前几行或最后几行。</p>
<pre><code class="language-python">covid_df.head(5)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-113.png" class="kg-image" alt="image-113" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">covid_df.tail(4)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-114.png" class="kg-image" alt="image-114" width="600" height="400" loading="lazy"></figure>
<p>要注意的是，在 <code>new_cases</code> 和 <code>new_deaths</code> 列中，刚开始的一些值是 <code>0</code>，但是在 <code>new_tests</code> 列中对应的值是 <code>NaN</code>。那是因为这个 CSV 文件本身并没有特定日期的 <code>new_tests</code> 列的数据（你可以通过查看文件来验证这一点）。这些值可能缺失或未知。</p>
<pre><code class="language-python">covid_df.at[0, 'new_tests']
# nan

type(covid_df.at[0, 'new_tests'])
# numpy.float64
</code></pre>
<p><code>0</code> 和 <code>NaN</code> 之间的区别很微妙但很重要。在此数据集中，它表示在指定日期没有报告每日测试数量。意大利从 2020 年 4 月 19 日开始报告每日测试数据。在 4 月 19 日之前，他们已经进行了 935,310 次测试。</p>
<p>我们可以使用列的 <code>first_valid_index</code> 方法找到不包含 <code>NaN</code> 值的第一个索引。</p>
<pre><code class="language-python">covid_df.new_tests.first_valid_index()
# 111
</code></pre>
<p>让我们查看此索引前后的几行，以验证值是否从 <code>NaN</code> 更改为实际数字。我们可以向<code>loc</code>传递一个范围来实现查看。</p>
<pre><code class="language-python">covid_df.loc[108:113]
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-115.png" class="kg-image" alt="image-115" width="600" height="400" loading="lazy"></figure>
<p>我们可以使用 <code>.sample</code> 方法从数据帧中获取随机抽样行。</p>
<pre><code class="language-python">covid_df.sample(10)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-116.png" class="kg-image" alt="image-116" width="600" height="400" loading="lazy"></figure>
<p>注意，尽管我们采取了随机样品，每一行的原始索引都被保留了。这是数据帧非常有用的一个属性。</p>
<p>下面是本节我们看到的函数和方法的总结：</p>
<ul>
<li><code>covid_df['new_cases']</code> – 使用列名将列当作 <code>Series</code> 来检索</li>
<li><code>new_cases[243]</code> – 使用索引从 <code>Series</code> 中检索值</li>
<li><code>covid_df.at[243, 'new_cases']</code> – 从数据帧中检索单个值</li>
<li><code>covid_df.copy()</code> – 创建数据帧的深度副本</li>
<li><code>covid_df.loc[243]</code> - 从数据帧中检索数据行或数据行范围</li>
<li><code>head</code>、<code>tail</code> 和 <code>sample</code> – 从数据帧中检索多行数据</li>
<li><code>covid_df.new_tests.first_valid_index</code> – 查找序列中的第一个非空索引</li>
</ul>
<h3 id="pandas">如何分析 Pandas 数据帧中的数据</h3>
<p>让我们尝试回答这些数据的一些问题。</p>
<p><strong>问：关于意大利新冠肺炎，总的确诊病例和死亡人数是多少？</strong></p>
<p>与 Numpy 数组类似，Pandas 序列支持 <code>sum</code> 方法，这个问题也就回答了。</p>
<pre><code class="language-python">total_cases = covid_df.new_cases.sum()
total_deaths = covid_df.new_deaths.sum()

print('The number of reported cases is {} and the number of reported deaths is {}.'.format(int(total_cases), int(total_deaths)))
# The number of reported cases is 271515 and the number of reported deaths is 35497.
</code></pre>
<p><strong>问：总的死亡率是多少（报告的死亡数除以确诊病例）？</strong></p>
<pre><code class="language-python">death_rate = covid_df.new_deaths.sum() / covid_df.new_cases.sum()

print("The overall reported death rate in Italy is {:.2f} %.".format(death_rate*100))
# The overall reported death rate in Italy is 13.07 %.
</code></pre>
<p><strong>问：进行测试的总人数是多少？在报告每日测试数量之前，共进行了 935</strong>，<strong>310 次测试。</strong></p>
<pre><code class="language-python">initial_tests = 935310
total_tests = initial_tests + covid_df.new_tests.sum()

total_tests
# 5214766.0
</code></pre>
<p><strong>问：哪些部分测试结果为阳性？</strong></p>
<pre><code class="language-python">positive_rate = total_cases / total_tests

print('{:.2f}% of tests in Italy led to a positive diagnosis.'.format(positive_rate*100))
# 5.21% of tests in Italy led to a positive diagnosis.
</code></pre>
<p>尝试提问回答关于这些数据更多的问题。</p>
<h3 id="pandas">如何在 Pandas 中对行进行查询和排序</h3>
<p>假设我们只想查看确诊病例大于 1，000 的日子。那么可以使用布尔表达式来检查哪些行满足此条件。</p>
<pre><code class="language-python">high_new_cases = covid_df.new_cases &gt; 1000

high_new_cases
# 0      False
# 1      False
# 2      False
# 3      False
# 4      False
#        ...  
# 243     True
# 244     True
# 245    False
# 246    False
# 247     True
# Name: new_cases, Length: 248, dtype: bool
</code></pre>
<p>布尔表达式返回一个包含 <code>True</code> 和 <code>False</code> 布尔值的序列。你可以使用这个序列从原始数据帧中选择行的子集，对应于这个序列中的 <code>True</code> 值。</p>
<p><code>covid_df[high_new_cases]</code></p>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-117.png" class="kg-image" alt="image-117" width="600" height="400" loading="lazy"></figure>
<p>这个数据帧包含 72 行，但是为了简洁起见，默认情况下 Jupyter 只显示前五行和后五行。我们可以更改一些显示选项，来查看所有行。</p>
<pre><code class="language-python">high_cases_df = covid_df[covid_df.new_cases &gt; 1000]

high_cases_df
</code></pre>
<p>我们还可以制定涉及多个列的更复杂的查询。例如，尝试确定确诊病例除以测试数量的比例高于总的 <code>positive_rate</code> 的日子。</p>
<pre><code class="language-python">positive_rate
# 0.05206657403227681

high_ratio_df = covid_df[covid_df.new_cases / covid_df.new_tests &gt; positive_rate]

high_ratio_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-120.png" class="kg-image" alt="image-120" width="600" height="400" loading="lazy"></figure>
<p>对两列进行操作的结果是一个新数列。</p>
<pre><code class="language-python">covid_df.new_cases / covid_df.new_tests
# 0           NaN
# 1           NaN
# 2           NaN
# 3           NaN
# 4           NaN
#          ...   
# 243    0.026970
# 244    0.032055
# 245    0.018311
# 246         NaN
# 247         NaN
# Length: 248, dtype: float64
</code></pre>
<p>我们可以使用该系列为数据帧添加新列。</p>
<pre><code class="language-python">covid_df['positive_rate'] = covid_df.new_cases / covid_df.new_tests

covid_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-121.png" class="kg-image" alt="image-121" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-121.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-121.png 625w" width="600" height="400" loading="lazy"></figure>
<p>但是，请记住，有时需要一些日子才能获得测试结果，因此，我们不能对同一天的新增病例数和测试数量进行比较。基于 <code>positive_rate</code> 列的任何推断都可能是不正确的。</p>
<p>注意这些微妙的联系是非常重要的，通常 CSV 文件中不会传达这些关系，而需要外部的上下文环境。通读数据集附带的文档或询问更多的信息，不失为一个好主意。</p>
<p>现在，让我们使用 <code>drop</code> 方法来移除 <code>positive_rate</code> 列。</p>
<pre><code class="language-python">covid_df.drop(columns=['positive_rate'], inplace=True)
</code></pre>
<p>你能指出 <code>inplace</code> 参数的目的吗？</p>
<h4 id="pandas"><strong>如何在 Pandas 中使用列值对行进行排序</strong></h4>
<p>你可以使用 <code>.sort_values</code> 通过一个指定的列来对行进行排序。让我们排序以确定病例数最多的天数，然后使用 <code>head</code> 方法将其链接起来，只列出前十个结果。</p>
<pre><code class="language-python">covid_df.sort_values('new_cases', ascending=False).head(10)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-122.png" class="kg-image" alt="image-122" width="600" height="400" loading="lazy"></figure>
<p>看起来 3 月最后两周的每日病例数最多。让我们来对比所记录的死亡人数最多的日子。</p>
<pre><code class="language-python">covid_df.sort_values('new_deaths', ascending=False).head(10)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-123.png" class="kg-image" alt="image-123" width="600" height="400" loading="lazy"></figure>
<p>可以发现，每日死亡人数的顶峰出现在每日病例达到顶峰之后的一周。</p>
<p>我们也来看看病例数最少的日子。我们也许会想到一年中最开始的几天会出现在列表上。</p>
<pre><code class="language-python">covid_df.sort_values('new_cases').head(10)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-124.png" class="kg-image" alt="image-124" width="600" height="400" loading="lazy"></figure>
<p>2020 年 6 月 20 日的新病例数似乎是 <code>-148</code>，一个负数！这跟我们预想的不一样，但这就是现实世界数据的本质。这可能是一个数据输入的错误，或者政府可能为了解决过去的计算错误而作的一个更正。</p>
<p>你能在网上挖掘新闻文章并找出这个数字为什么是负数吗？</p>
<p>让我们再来看看 2020 年 6 月 20 日前后的几天。</p>
<pre><code class="language-python">covid_df.loc[169:175]
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-125.png" class="kg-image" alt="image-125" width="600" height="400" loading="lazy"></figure>
现在，我们假设这实际上是一个数据输入错误。我们可以使用以下的其中一个方法来处理缺失值或错误值：
<ol>
<li>将其替换为 <code>0</code></li>
<li>将其替换为整列的平均值</li>
<li>将其替换为前后两个日期的平均值</li>
<li>删除该行</li>
</ol>
<p>选择哪种方法需要有关数据和问题的一些背景信息。在本例中，由于我们正在处理按日期排序的数据，我们可以继续使用第三种方法。</p>
<p>你可以使用 <code>.at</code> 方法来修改数据帧中指定的值。</p>
<pre><code class="language-python">covid_df.at[172, 'new_cases'] = (covid_df.at[171, 'new_cases'] + covid_df.at[173, 'new_cases'])/2
</code></pre>
<p>以下是我们在本节中看到的函数和方法的汇总：</p>
<ul>
<li><code>covid_df.new_cases.sum()</code> – 计算列或系列中值的总和</li>
<li><code>covid_df[covid_df.new_cases &gt; 1000]</code> – 使用布尔表达式查询满足所选条件的行子集</li>
<li><code>df['pos_rate'] = df.new_cases/df.new_tests</code> – 通过合并现有列中的数据来添加新列</li>
<li><code>covid_df.drop('positive_rate')</code> – 从数据帧中删除一列或多列</li>
<li><code>sort_values</code> – 使用列值对数据帧的行进行排序</li>
<li><code>covid_df.at[172, 'new_cases'] = ...</code> – 替换数据帧中的值</li>
</ul>
<h3 id="pandas">如何处理 Pandas 中的日期</h3>
<p>虽然我们已经查看了病例、测试、阳性率等这些总体的数字，但按月研究这些数字也很有用。</p>
<p><code>date</code> 列在这里可能会派上用场，因为 Pandas 提供了许多用于处理日期的实用程序。</p>
<pre><code class="language-python">covid_df.date
# 0      2019-12-31
# 1      2020-01-01
# 2      2020-01-02
# 3      2020-01-03
# 4      2020-01-04
#           ...    
# 243    2020-08-30
# 244    2020-08-31
# 245    2020-09-01
# 246    2020-09-02
# 247    2020-09-03
# Name: date, Length: 248, dtype: object
</code></pre>
<p>当前日期的数据类型是 <code>object</code>，因此 Pandas 不知道这一列是日期。我们用 <code>pd.to_datetime</code> 方法将它转成 <code>datetime</code> 列。</p>
<pre><code class="language-python">covid_df['date'] = pd.to_datetime(covid_df.date)

covid_df['date']
# 0     2019-12-31
# 1     2020-01-01
# 2     2020-01-02
# 3     2020-01-03
# 4     2020-01-04
#          ...    
# 243   2020-08-30
# 244   2020-08-31
# 245   2020-09-01
# 246   2020-09-02
# 247   2020-09-03
# Name: date, Length: 248, dtype: datetime64[ns]
</code></pre>
<p>现在你可以看到它的数据类型是 <code>datetime64</code>。我们用 <code>DatetimeIndex</code> 类将数据的不同部分提取到单独的列中。(<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fpandas.pydata.org%2Fpandas-docs%2Fversion%2F0.23.4%2Fgenerated%2Fpandas.DatetimeIndex.html">查看文档</a>)。</p>
<pre><code class="language-python">covid_df['year'] = pd.DatetimeIndex(covid_df.date).year
covid_df['month'] = pd.DatetimeIndex(covid_df.date).month
covid_df['day'] = pd.DatetimeIndex(covid_df.date).day
covid_df['weekday'] = pd.DatetimeIndex(covid_df.date).weekday

covid_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-126.png" class="kg-image" alt="image-126" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-126.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-126.png 735w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>我们来看一下 5 月份的整体指标。通过查询五月的行，选择其列的子集，并使用 <code>sum</code> 方法来合计每个选定列的值。</p>
<pre><code class="language-python"># 查询五月份的记录
covid_df_may = covid_df[covid_df.month == 5]

# 提取要汇总的列子集
covid_df_may_metrics = covid_df_may[['new_cases', 'new_deaths', 'new_tests']]

# 按列求和
covid_may_totals = covid_df_may_metrics.sum()

covid_may_totals
# new_cases       29073.0
# new_deaths       5658.0
# new_tests     1078720.0
# dtype: float64

type(covid_may_totals)
# pandas.core.series.Series
</code></pre>
<p>我们还可以将上述操作合并为一条语句。</p>
<pre><code class="language-python">covid_df[covid_df.month == 5][['new_cases', 'new_deaths', 'new_tests']].sum()
# new_cases       29073.0
# new_deaths       5658.0
# new_tests     1078720.0
# dtype: float64
</code></pre>
<p>再举一个例子，让我们检查一下周日报告的病例数是否高于每天报告的平均病例数。这次，我们可能要使用 <code>.mean</code> 方法对列进行汇总。</p>
<pre><code class="language-python"># 总平均值
covid_df.new_cases.mean()

# 1096.6149193548388

# 周日平均数
covid_df[covid_df.weekday == 6].new_cases.mean()

# 1247.2571428571428
</code></pre>
<p>与其他日子相比，星期天所报告的病例看起来更多。</p>
<p>尝试提问回答更多的数据中有关日期的问题。</p>
<h3 id="pandas">如何在 Pandas 中分组和聚合数据</h3>
<p>下一步，如果我们想要汇总逐日的数据，还要创建一个包含逐月数据的新数据帧。我们可以用 <code>groupby</code> 函数来为每一个月创建一个组，然后选择我们想要聚合的列，并用 <code>sum</code> 方法来聚合。</p>
<pre><code class="language-python">covid_month_df = covid_df.groupby('month')[['new_cases', 'new_deaths', 'new_tests']].sum()

covid_month_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-127.png" class="kg-image" alt="image-127" width="600" height="400" loading="lazy"></figure>
<p>结果是一个新的数据帧，它使用传递给 <code>groupby</code> 的列中的唯一值作为索引。分组与聚合是非常有用的方法，用于逐步将数据汇总为更小的数据帧。</p>
<p>除了按总和聚合之外，还可以按平均值等其他方式进行聚合。让我们分别来计算每个月每日新增病例、死亡人数和检测数的平均值。</p>
<pre><code class="language-python">covid_month_mean_df = covid_df.groupby('month')[['new_cases', 'new_deaths', 'new_tests']].mean()

covid_month_mean_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-128.png" class="kg-image" alt="image-128" width="600" height="400" loading="lazy"></figure>
<p>除了分组之外，另一种聚合形式是计算截止到每行日期的病例、测试或死亡的累积总和。我们可以使用 <code>cumsum</code> 方法计算某一列的累积总和并作为一个新的系列。</p>
<p>我们来添加新的三列：<code>total_cases</code>，<code>total_deaths</code> 和 <code>total_tests</code>。</p>
<pre><code class="language-python">covid_df['total_cases'] = covid_df.new_cases.cumsum()
covid_df['total_deaths'] = covid_df.new_deaths.cumsum()
covid_df['total_tests'] = covid_df.new_tests.cumsum() + initial_tests
</code></pre>
<p>我们还在 <code>total_test</code> 中加入了初始测试次数，以反映每日报告开始前进行的测试。</p>
<p><code>covid_df</code></p>
<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-129.png" class="kg-image" alt="image-129" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-129.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-129.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-129.png 1065w" width="600" height="400" loading="lazy"></figure>
<p>注意 <code>total_tests</code> 列中的 <code>NaN</code> 值是如何保持不被影响的。</p>
<h3 id="pandas">如何在 Pandas 中合并来自多个来源的数据</h3>
<p>要确定其他指标，例如每百万人口的测试人数、每百万人口的确诊病例数等，我们需要该国家/地区的更多信息，即其人口。</p>
<p>让我们来下载另一个文件 <code>locations.csv</code>，它包含了包括意大利在内的许多国家的健康相关信息。</p>
<pre><code class="language-python">urlretrieve('https://gist.githubusercontent.com/aakashns/8684589ef4f266116cdce023377fc9c8/raw/99ce3826b2a9d1e6d0bde7e9e559fc8b6e9ac88b/locations.csv', 'locations.csv')

locations_df = pd.read_csv('locations.csv')
locations_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-130.png" class="kg-image" alt="image-130" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-130.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-130.png 928w" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">locations_df[locations_df.location == "Italy"]
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-131.png" class="kg-image" alt="image-131" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-131.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-131.png 877w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>通过添加更多的列，我们可以将这些数据合并到先前的数据中。但是，要合并两个数据帧，我们至少需要一个共同的列。因此，我们在 <code>covid_df</code> 数据帧中插入 <code>location</code> 列，并将该列的所有值设为 <code>“Italy”</code>。</p>
<pre><code class="language-python">covid_df['location'] = "Italy"

covid_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-132.png" class="kg-image" alt="image-132" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-132.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-132.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-132.png 1142w" width="600" height="400" loading="lazy"></figure>
现在，我们可以使用 `.merge` 方法将 `locations_df` 中的列添加到 `covid_df` 中。
<pre><code class="language-python">merged_df = covid_df.merge(locations_df, on="location")

merged_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-133.png" class="kg-image" alt="image-133" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-133.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-133.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-133.png 1358w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"><figcaption>Check out the full data frame <a href="https://jovian.ai/embed?url=https://jovian.ai/aakashns/python-pandas-data-analysis">here</a>.</figcaption></figure>
<p>在<a href="https://jovian.com/embed?url=https://jovian.ai/aakashns/python-pandas-data-analysis">这里</a>查看完整的数据。</p>
<p>在 <code>covid_df</code> 中，每一行都附加上了意大利的位置信息。如果 <code>covid_df</code> 数据帧中包含了多个地区的数据，那么每一行应该附加上相应国家的位置信息。</p>
<p>现在，我们就可以计算每百万人口的病例数、死亡人数以及测试人数这些指标了。</p>
<pre><code class="language-python">merged_df['cases_per_million'] = merged_df.total_cases * 1e6 / merged_df.population
merged_df['deaths_per_million'] = merged_df.total_deaths * 1e6 / merged_df.population
merged_df['tests_per_million'] = merged_df.total_tests * 1e6 / merged_df.population

merged_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-134.png" class="kg-image" alt="image-134" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-134.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-134.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-134.png 1405w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"><figcaption>Check out the full data frame <a href="https://jovian.ai/embed?url=https://jovian.ai/aakashns/python-pandas-data-analysis">here</a>.</figcaption></figure>
<p>在<a href="https://jovian.com/embed?url=https://jovian.ai/aakashns/python-pandas-data-analysis">这里</a>查看完整的数据。</p>
<h3 id="pandas">如何用 Pandas 将数据写回到文件中</h3>
<p>在完成分析，添加新列之后，你需要将结果写回到文件中。否则，一旦 Jupter notebook 关闭后，数据就会丢失。</p>
<p>在写入文件之前，让我们先创建一个只包含我们希望记录的列的数据帧。</p>
<pre><code class="language-python">result_df = merged_df[['date',
                       'new_cases', 
                       'total_cases', 
                       'new_deaths', 
                       'total_deaths', 
                       'new_tests', 
                       'total_tests', 
                       'cases_per_million', 
                       'deaths_per_million', 
                       'tests_per_million']]
                       
result_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-135.png" class="kg-image" alt="image-135" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-135.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-135.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-135.png 1279w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"></figure>
<p>要将数据帧中的数据写入文件，我们可以使用 <code>to_csv</code> 函数。</p>
<pre><code class="language-python">result_df.to_csv('results.csv', index=None)
</code></pre>
<p><code>to_csv</code> 函数默认还包含一列用于存储数据帧索引的额外列。我们通过 <code>index=None</code> 来关闭这种行为。现在可以验证 <code>results.csv</code> 是否已创建，并包含 CSV 格式数据帧中的数据：</p>
<pre><code class="language-python">date,new_cases,total_cases,new_deaths,total_deaths,new_tests,total_tests,cases_per_million,deaths_per_million,tests_per_million
2020-02-27,78.0,400.0,1.0,12.0,,,6.61574439992122,0.1984723319976366,
2020-02-28,250.0,650.0,5.0,17.0,,,10.750584649871982,0.28116913699665186,
2020-02-29,238.0,888.0,4.0,21.0,,,14.686952567825108,0.34732658099586405,
2020-03-01,240.0,1128.0,8.0,29.0,,,18.656399207777838,0.47964146899428844,
2020-03-02,561.0,1689.0,6.0,35.0,,,27.93498072866735,0.5788776349931067,
2020-03-03,347.0,2036.0,17.0,52.0,,,33.67413899559901,0.8600467719897585,
</code></pre>
<h3 id="pandas">奖励：使用 Pandas 进行基本绘图</h3>
<p>通常在 Jupyter notebook 中，我们使用像 <code>matplotlib</code> 或 <code>seaborn</code> 这样的库来绘图。但是，Pandas 数据帧和序列提供了便利的 <code>.plot</code> 方法来进行快速简单地绘图。</p>
<p>我们来绘制一个折线图，显示每日病例数如何随时间变化。</p>
<pre><code class="language-python">result_df.new_cases.plot();
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-137.png" class="kg-image" alt="image-137" width="600" height="400" loading="lazy"></figure>
<p>虽然此图显示了整体趋势，但很难判断峰值发生的位置，因为 X 轴上没有日期。我们可以使用 <code>date</code> 列作为数据帧的索引来解决这个问题。</p>
<pre><code class="language-python">result_df.set_index('date', inplace=True)

result_df
</code></pre>
<figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-138.png" class="kg-image" alt="image-138" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-138.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-138.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-138.png 1237w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"></figure>
注意数据帧的索引并非必须是数值，使用日期作为索引，同样可以通过 `.loc` 获取指定日期的数据。
<pre><code class="language-python">result_df.loc['2020-09-01']
# new_cases             9.960000e+02
# total_cases           2.696595e+05
# new_deaths            6.000000e+00
# total_deaths          3.548300e+04
# new_tests             5.439500e+04
# total_tests           5.214766e+06
# cases_per_million     4.459996e+03
# deaths_per_million    5.868661e+02
# tests_per_million     8.624890e+04
# Name: 2020-09-01 00:00:00, dtype: float64
</code></pre>
<p>下面我们将每天的新病例和新死亡人数绘制为折线图。</p>
<pre><code class="language-python">result_df.new_cases.plot()
result_df.new_deaths.plot();
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-139.png" class="kg-image" alt="image-139" width="600" height="400" loading="lazy"></figure>
<p>我们还可以比较总病例数和总死亡人数。</p>
<pre><code class="language-python">result_df.total_cases.plot()
result_df.total_deaths.plot();
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-140.png" class="kg-image" alt="image-140" width="600" height="400" loading="lazy"></figure>
<p>让我们看看死亡率和阳性检测率如何随时间变化的。</p>
<pre><code class="language-python">death_rate = result_df.total_deaths / result_df.total_cases

death_rate.plot(title='Death Rate');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-141.png" class="kg-image" alt="image-141" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">positive_rates = result_df.total_cases / result_df.total_tests

positive_rates.plot(title='Positive Rate');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-142.png" class="kg-image" alt="image-142" width="600" height="400" loading="lazy"></figure>
<p>最后，我们来绘制逐月数据的条形图，以在更高的层次上查看趋势。</p>
<pre><code class="language-python">covid_month_df.new_cases.plot(kind='bar');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-143.png" class="kg-image" alt="image-143" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">covid_month_df.new_tests.plot(kind='bar')
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-144.png" class="kg-image" alt="image-144" width="600" height="400" loading="lazy"></figure>
<h3 id="pandas">Pandas 练习</h3>
<p>尝试以下练习，以熟悉 Pandas 数据帧，并锻炼你的技术：</p>
<ul>
<li><a href="https://jovian.ml/aakashns/pandas-practice-assignment">Pandas 数据帧任务</a></li>
<li><a href="https://github.com/guipsamora/pandas_exercises">Pandas 附加练习</a></li>
<li><a href="https://www.kaggle.com/datasets">尝试从 Kaggle 下载并分析数据</a></li>
</ul>
<h3 id="">总结及延展阅读</h3>
<p>在本教程中，我们涵盖了以下主题：</p>
<ul>
<li>如何将 CSV 文件读入到 Pandas 数据帧中</li>
<li>如何从 Pandas 数据帧中检索数据</li>
<li>如何查询、排序和分析数据</li>
<li>如何合并、分组和聚合数据</li>
<li>如何从日期中提取有用的信息</li>
<li>使用折线图和条形图进行基本绘图</li>
<li>如何将数据帧写入到 CSV 文件中</li>
</ul>
<p>查看以下资源以了解 Pandas 的更多信息：</p>
<ul>
<li><a href="https://pandas.pydata.org/docs/user_guide/index.html">Pandas 用户指南</a></li>
<li><a href="https://www.oreilly.com/library/view/python-for-data/9781491957653/">Python 数据分析（Wes McKinney 的书 —— 他是 Pandas 的创建者）</a></li>
</ul>
<h3 id="pandas">查看问题以检验你对 Pandas 的理解</h3>
<p>尝试回答以下问题，来测验你对本章所涵盖的主题的理解：</p>
<ol>
<li>Pandas 是什么？有用在哪里？</li>
<li>如何安装 Pandas 库？</li>
<li>如何导入 <code>pandas</code> 模块？</li>
<li>导入 <code>pandas</code> 模块后，它的常用别名是什么？</li>
<li>如果用 Pandas 读入 CSV 文件？请举例。</li>
<li>用 Pandas 还可以读入哪些文件格式？举例说明。</li>
<li>Pandas 数据帧是什么？</li>
<li>Pandas 数据帧与 Numpy 数组的区别是什么？</li>
<li>在数据帧中如何找到行数和列数？</li>
<li>如何在数据帧中获取列的列表？</li>
<li>数据帧中<code>describe</code> 方法的作用是什么？</li>
<li><code>info</code> 和 <code>describe</code> 这两个数据帧方法的区别是什么？</li>
<li>Pandas 数据帧在概念上与字典列表或列表字典相似吗？举例解释。</li>
<li>Pandas 中的 <code>Series</code> 是什么？它跟 Numpy 数组的区别是什么？</li>
<li>如何访问数据帧中的列？</li>
<li>如何访问数据帧中的行？</li>
<li>如何访问数据帧中指定的行和列中的元素？</li>
<li>如何创建具有特定列集的数据帧子集？</li>
<li>如何创建具有特定行范围的数据帧子集？</li>
<li>更改数据帧内的值，是否会影响使用行或列的子集所创建的其他数据帧？为什么？</li>
<li>如何创建数据帧的副本？</li>
<li>为什么要避免创建太多的数据帧副本？</li>
<li>如何查看数据帧中的开头几行？</li>
<li>如何查看数据帧中的末尾几行？</li>
<li>如何在数据帧中选择随机行？</li>
<li>数据帧中的“索引”是什么？如何有用？</li>
<li>Pandas 数据帧中的 <code>NaN</code> 值代表什么意思？</li>
<li><code>Nan</code> 和 <code>0</code> 的区别是什么？</li>
<li>在 Pandas 序列或列中，如何识别第一个非空行？</li>
<li><code>df.loc</code> and <code>df.at</code> 的区别是什么？</li>
<li>在哪里可以找到 Pandas 中 <code>DataFrame</code> 和 <code>Series</code> 对象所支持的全部方法列表？</li>
<li>如何在数据帧的列中找到数字的总和？</li>
<li>如何找到数据帧列中数字的平均值？</li>
<li>如何找到数据帧列中非空数字的数量？</li>
<li>在布尔表达式中使用 Pandas 列可以得到什么结果？举例说明。</li>
<li>如何选择行子集，使得其指定的列值满足给定的条件？举例说明。</li>
<li>表达式 <code>df[df.new_cases &gt; 100]</code> 的结果是什么？</li>
<li>如何在 Jupyter 单元格输出中显示 pandas 数据帧的所有行？</li>
<li>对数据帧中的两列执行算术运算，会得到什么结果？举例说明。</li>
<li>如何通过组合两个现有列的值，在数据帧中添加新列？举例说明。</li>
<li>如何删除数据帧中的列？举例说明。</li>
<li>在数据帧方法中 <code>inplace</code> 参数的作用是什么？</li>
<li>如何基于一个特定列中的值来对数据帧的行进行排序？</li>
<li>如果利用多个列中的值来对 pandas 数据帧进行排序？</li>
<li>在对 Pandas 数据帧排序时，如何指定是按升序还是降序来排序？</li>
<li>如何修改数据帧中指定的值？</li>
<li>如何将数据帧的列转换成 <code>datetime</code> 数据类型？</li>
<li>使用 <code>datetime</code> 数据类型而不用 <code>object</code> 的好处是什么？</li>
<li>如何将日期列的不同部分（如月、年、月、工作日等）提取到单独的列中？举例说明。</li>
<li>如何聚合数据帧的多个列？</li>
<li>数据帧的 <code>groupby</code> 方法的作用是什么？举例说明。</li>
<li>聚合用 <code>groupby</code> 创建的组有哪些不同的方式？</li>
<li>运行或累积总和是什么意思？</li>
<li>如何创建一个新列，包含另一列的运行或累积总和？</li>
<li>Pandas 数据帧还支持哪些其他的累积方法？</li>
<li>合并两个数据帧是什么意思？举例说明。</li>
<li>如何指定用于合并两个数据帧的列？</li>
<li>如何将 Pandas 数据帧的数据写入到 CSV 文件中？请举个例子。</li>
<li>还可以将 Pandas 数据帧写入到哪些文件格式中？举例说明。</li>
<li>如何创建折线图，用于显示数据帧中列的值？</li>
<li>如何将数据帧的列转换为其索引？</li>
<li>数据帧的索引可以是非数字吗？</li>
<li>使用非数字数据帧的好处是什么？举例说明。</li>
<li>如何创建条形图，用于显示数据帧中列的值？</li>
<li>Pandas 数据帧和系列还支持哪些其他类型的绘图方法？</li>
</ol>
<p>你已经准备好进入本教程的下一部分了。</p>
<h2 id="pythonmatplotlibseaborn">使用 Python、Matplotlib 和 Seaborn 进行数据可视化</h2>
<p><img src="https://i.imgur.com/9i806Rh.png" alt="9i806Rh" width="2314" height="1092" loading="lazy"></p>
<p>Notebook 链接：<a href="https://jovian.ai/aakashns/python-matplotlib-data-visualization">https://jovian.ai/aakashns/python-matplotlib-data-visualization</a></p>
<p>数据可视化是对数据的图形化呈现。它生成图片，将要呈现的数据之间的关系传递给读者。</p>
<p>可视化数据是数据分析和机器学习的重要部分。我们将使用 Python 库 <a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org">Matplotlib</a> 和 <a href="https://jovian.ai/outlink?url=https%3A%2F%2Fseaborn.pydata.org">Seaborn</a> 来学习和应用一些常用的数据可视化技术。在本教程中，我们会交替使用 <strong>chart</strong>，<strong>plot</strong> 和 <strong>graph</strong> 这三个词。</p>
<p>开始前，我们需要先安装并导入这些库。<code>matplotlib.pyplot</code> 模块用于基本的绘图，如折线图和条形图，导入后通常使用别名 <code>plt</code> 。<code>seaborn</code> 模块用于更高级的绘图，导入后通常使用别名 <code>sns</code>。</p>
<pre><code class="language-python">!pip install matplotlib seaborn --upgrade --quiet

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
</code></pre>
<p>注意我们还包含了特殊命令 <code>%matplotlib inline</code>，确保所绘的图内嵌在 Jupyter notebook 中显示。如果不使用这条命令，有时图形会以弹窗显示。</p>
<h3 id="python">如何在 Python 中创建折线图</h3>
<p>折线图是最简单、应用最广泛的数据可视化技术之一。折线图将信息显示为由直线连接的一系列数据点或标记。</p>
<p>你可以自定义线条和标记的形状、大小、颜色和其他美学元素，以获得更好的视觉清晰度。</p>
<p>下面是一个 Python 列表，显示了一个名为 Kanto 的虚构国家在六年内的苹果产量（吨/公顷）。</p>
<pre><code class="language-python">yield_apples = [0.895, 0.91, 0.919, 0.926, 0.929, 0.931]
</code></pre>
<p>我们可以使用折线图来可视化苹果的产量如何随时间变化。我们使用 <code>plt.plot</code> 函数来绘制折线图。</p>
<pre><code class="language-python">plt.plot(yield_apples)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-145.png" class="kg-image" alt="image-145" width="600" height="400" loading="lazy"></figure>
<p>调用 <code>plt.plot</code> 函数就能绘制预期的折线图，同时它还返回了绘制的绘图列表 <code>[&lt;matplotlib.lines.Line2D at 0x7ff70aa20760&gt;]</code>，会显示在输出区域。我们可以在单元格中最后一条语句的末尾添加分号（<code>;</code>），使得只显示图形而不显示输出内容。</p>
<pre><code class="language-python">plt.plot(yield_apples);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-146.png" class="kg-image" alt="image-146" width="600" height="400" loading="lazy"></figure>
让我们一步一步来增强这个图形，使它更具信息性和美感。
<h4 id="matplotlibx">如何在 MatPlotLib 中自定义 X 轴</h4>
<p>当前图形的 X 轴显示了列表元素的索引 0 到 5。如果我们可以显示数据中的年份，这个图形将更具信息性。通过 <code>plt.plot</code> 中的两个参数即可实现。</p>
<pre><code class="language-python">years = [2010, 2011, 2012, 2013, 2014, 2015]
yield_apples = [0.895, 0.91, 0.919, 0.926, 0.929, 0.931]

plt.plot(years, yield_apples)
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-147.png" class="kg-image" alt="image-147" width="600" height="400" loading="lazy"></figure>
#### MatPlotLib 中的坐标标签
<p>通过 <code>plt.xlabel</code> 和 <code>plt.ylabel</code> 这两个函数，我们可以为坐标添加标签，来显示坐标代表的意义。</p>
<pre><code class="language-python">plt.plot(years, yield_apples)
plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-148.png" class="kg-image" alt="image-148" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中绘制多条折线</h4>
<p>你可以为每条线调用一次 <code>plt.plot</code> 函数，这样就可以在同一个图形中绘制多条折线。让我们来比较 Kanto 苹果与橘子的产量。</p>
<pre><code class="language-python">years = range(2000, 2012)
apples = [0.895, 0.91, 0.919, 0.926, 0.929, 0.931, 0.934, 0.936, 0.937, 0.9375, 0.9372, 0.939]
oranges = [0.962, 0.941, 0.930, 0.923, 0.918, 0.908, 0.907, 0.904, 0.901, 0.898, 0.9, 0.896, ]

plt.plot(years, apples)
plt.plot(years, oranges)
plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-149.png" class="kg-image" alt="image-149" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">MatPlotLib 中的图表标题和图例</h4>
<p>为了区分不同的线条，我们可以使用 <code>plt.legend</code> 函数在图形中添加一个图例。我们还可以使用 <code>plt.title</code> 函数来设置图表的标题。</p>
<pre><code class="language-python">plt.plot(years, apples)
plt.plot(years, oranges)

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-150.png" class="kg-image" alt="image-150" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中使用线条标记</h4>
<p>通过使用 <code>plt.plot</code> 的<code>marker</code> 参数，我们还可以为每条线上的数据点增添标记。</p>
<p>Matplotlib 提供许多不同的标记，如圆圈、叉号、方块和菱形等。你可以从这个链接找到所有标记类型的列表：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org%2F3.1.1%2Fapi%2Fmarkers_api.html">https://matplotlib.org/3.1.1/api/markers_api.html</a> 。</p>
<pre><code class="language-python">plt.plot(years, apples, marker='o')
plt.plot(years, oranges, marker='x')

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-151.png" class="kg-image" alt="image-151" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中设置线条和标记的样式</h4>
<p><code>plt.plot</code> 函数提供很多参数用于设置线条和标记的样式：</p>
<ul>
<li><code>color</code> 或 <code>c</code> – 设置线条颜色 (<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org%2F3.1.0%2Fgallery%2Fcolor%2Fnamed_colors.html">支持的颜色</a>)</li>
<li><code>linestyle</code> 或 <code>ls</code> – 选择是实线还是虚线</li>
<li><code>linewidth</code> 或 <code>lw</code> – 设置线条宽度</li>
<li><code>markersize</code> 或 <code>ms</code> – 设置标记尺寸</li>
<li><code>markeredgecolor</code> 或 <code>mec</code> – 设置标记的边缘颜色</li>
<li><code>markeredgewidth</code> 或 <code>mew</code> – 设置标记的边缘宽度</li>
<li><code>markerfacecolor</code> 或 <code>mfc</code> – 设置标记的填充颜色</li>
<li><code>alpha</code> – 图形的不透明度</li>
</ul>
<p>查阅 <code>plt.plot</code> 的文档以学习更多内容：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org%2Fapi%2F_as_gen%2Fmatplotlib.pyplot.plot.html%23matplotlib.pyplot.plot">https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot</a> 。</p>
<pre><code class="language-python">plt.plot(years, apples, marker='s', c='b', ls='-', lw=2, ms=8, mew=2, mec='navy')
plt.plot(years, oranges, marker='o', c='r', ls='--', lw=3, ms=10, alpha=.5)

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-152.png" class="kg-image" alt="image-152" width="600" height="400" loading="lazy"></figure>
<p><code>fmt</code> 参数提供了便捷的方法来设置标记的颜色、线条样式和颜色。你可以将它作为 <code>plt.plot</code> 的第三参数。</p>
<pre><code class="language-python">fmt = '[marker][line][color]'

plt.plot(years, apples, 's-b')
plt.plot(years, oranges, 'o--r')

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-153.png" class="kg-image" alt="image-153" width="600" height="400" loading="lazy"></figure>
<p>你可以使用 <code>plt.figure</code> 函数来改变图形的大小。</p>
<pre><code class="language-python">plt.plot(years, oranges, 'or')
plt.title("Yield of Oranges (tons per hectare)");
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-154.png" class="kg-image" alt="image-154" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中更改图形的尺寸</h4>
<p>你可以使用 <code>plt.figure</code> 函数来更改图形的尺寸。</p>
<pre><code class="language-python">plt.figure(figsize=(12, 6))

plt.plot(years, oranges, 'or')
plt.title("Yield of Oranges (tons per hectare)");
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-155.png" class="kg-image" alt="image-155" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-155.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-155.png 996w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h4 id="seaborn">如何使用 Seaborn 改进默认样式</h4>
<p>使用 Seaborn 库中的一些默认样式，很容易让你的图表看起来更加漂亮。你可以全局使用 <code>sns.set_style</code> 函数。以下是预定义样式的完整列表：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fseaborn.pydata.org%2Fgenerated%2Fseaborn.set_style.html">https://seaborn.pydata.org/generated/seaborn.set_style.html</a> 。</p>
<pre><code class="language-python">sns.set_style("whitegrid")
plt.plot(years, apples, 's-b')
plt.plot(years, oranges, 'o--r')

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-156.png" class="kg-image" alt="image-156" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">sns.set_style("darkgrid")

plt.plot(years, apples, 's-b')
plt.plot(years, oranges, 'o--r')

plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

plt.title("Crop Yields in Kanto")
plt.legend(['Apples', 'Oranges']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-157.png" class="kg-image" alt="image-157" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">plt.plot(years, oranges, 'or')
plt.title("Yield of Oranges (tons per hectare)");
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-158.png" class="kg-image" alt="image-158" width="600" height="400" loading="lazy"></figure>
<p>你还可以通过修改 <code>matplotlib.rcParams</code> 字典直接编辑默认样式。了解更多信息：<a href="https://matplotlib.org/3.2.1/tutorials/introductory/customizing.html#matplotlib-rcparams">https://matplotlib.org/3.2.1/tutorials/introductory/customizing.html#matplotlib-rcparams</a> 。</p>
<pre><code class="language-python">import matplotlib

matplotlib.rcParams['font.size'] = 14
matplotlib.rcParams['figure.figsize'] = (9, 5)
matplotlib.rcParams['figure.facecolor'] = '#00000000'
</code></pre>
<h3 id="matplotlib">MatPlotLib 中的散点图</h3>
<p>在散点图中，两个变量的值被绘成二维网格上的一个点。此外，你还可以使用第三个变量来确定这些点的大小和颜色。让我们来试一个例子。</p>
<p><a href="https://jovian.ai/outlink?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FIris_flower_data_set">鸢尾花卉数据集</a> 提供了三种花的花萼和花瓣的样本测量。该数据集包含了 Seaborn 库，你可以把它当作 Pandas 数据帧来加载。</p>
<pre><code class="language-python"># 将数据加载到 Pandas 数据帧中
flowers_df = sns.load_dataset("iris")

flowers_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-159.png" class="kg-image" alt="image-159" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">flowers_df.species.unique()
# array(['setosa', 'versicolor', 'virginica'], dtype=object)
</code></pre>
<p>让我们尝试将萼片长度和萼片宽度之间的关系可视化。我们的第一反应可能是使用 <code>plt.plot</code> 创建一个折线图。</p>
<pre><code class="language-python">plt.plot(flowers_df.sepal_length, flowers_df.sepal_width);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-160.png" class="kg-image" alt="image-160" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-160.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-160.png 758w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>由于数据集中有太多两个属性的组合，因此输出的信息不是很丰富。它们之间看上去并不是简单的关系。</p>
<p>通过 <code>seaborn</code> 模块（以别名 <code>sns</code> 导入）中的 <code>scatterplot</code> 函数，我们用散点图可视化花萼长度和宽度是如何变化的。</p>
<pre><code class="language-python">sns.scatterplot(x=flowers_df.sepal_length, y=flowers_df.sepal_width);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-161.png" class="kg-image" alt="image-161" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-161.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-161.png 774w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中添加色调</h4>
<p>注意，上图中有些点形成了一些异常值的不同簇。我们可以将这三个花的品种各自当作一个<code>色调</code>来给这些点上色，还可以用 <code>s</code> 参数来放大这些点。</p>
<pre><code class="language-python">sns.scatterplot(x=flowers_df.sepal_length, y=flowers_df.sepal_width, hue=flowers_df.species, s=100);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-162.png" class="kg-image" alt="image-162" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-162.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-162.png 778w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>添加色调使得图形更具信息性。我们可以立刻看出，刚毛鸢尾的花萼较短，但是较宽。而弗吉尼亚鸢尾正好相反。</p>
<h4 id="seaborn">如何自定义 Seaborn 图形</h4>
<p>由于 Seaborn 内部用的是 Matplotlib 的绘图函数，我们可以使用像 <code>plt.figure</code> 和 <code>plt.title</code> 这样的函数来修改图形。</p>
<pre><code class="language-python">plt.figure(figsize=(12, 6))
plt.title('Sepal Dimensions')

sns.scatterplot(x=flowers_df.sepal_length, 
                y=flowers_df.sepal_width, 
                hue=flowers_df.species,
                s=100);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-163.png" class="kg-image" alt="image-163" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-163.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-163.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-163.png 1007w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h4 id="seabornpandas">如何使用带有 Seaborn 的 Pandas 数据帧绘制数据</h4>
<p>Seaborn 内置了对 Pandas 数据帧的支持。你可以提供列名并使用 <code>data</code> 参数来指定数据帧，无需将每一列作为序列来传递。</p>
<pre><code class="language-python">plt.title('Sepal Dimensions')
sns.scatterplot(x='sepal_length', 
                y='sepal_width', 
                hue='species',
                s=100,
                data=flowers_df);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-164.png" class="kg-image" alt="image-164" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-164.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-164.png 783w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h3 id="matplotlib">MatPlotLib 中的直方图</h3>
<p>直方图通过沿值的范围创建组距（间隔）并显示垂直条来表示每个组距中的观察数，从而表示变量的分布。</p>
<p>例如，我们要可视化鸢尾花数据集中花萼宽度值的分布。我们可以使用 <code>plt.hist</code> 函数来创建直方图。</p>
<pre><code class="language-python"># 将数据加载到 Pandas 数据帧中
flowers_df = sns.load_dataset("iris")

flowers_df.sepal_width
# 0      3.5
# 1      3.0
# 2      3.2
# 3      3.1
# 4      3.6
#       ... 
# 145    3.0
# 146    2.5
# 147    3.0
# 148    3.4
# 149    3.0
# Name: sepal_width, Length: 150, dtype: float64
</code></pre>
<pre><code class="language-python">plt.title("Distribution of Sepal Width")
plt.hist(flowers_df.sepal_width);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-165.png" class="kg-image" alt="image-165" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-165.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-165.png 753w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>我们能立马发现花萼的宽度在 2.0 - 4.5 范围内，大约有 35 个落在 2.9 - 3.1 之间，它们似乎是最多的组距。</p>
<h4 id="">如何控制组距的大小和数量</h4>
<p>我们可以使用组距参数来控制组距的数量以及每个组距的大小。</p>
<pre><code class="language-python"># Specifying the number of bins
plt.hist(flowers_df.sepal_width, bins=5);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-166.png" class="kg-image" alt="image-166" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-166.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-166.png 756w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python">import numpy as np

# Specifying the boundaries of each bin
plt.hist(flowers_df.sepal_width, bins=np.arange(2, 5, 0.25));
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-167.png" class="kg-image" alt="image-167" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-167.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-167.png 744w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<pre><code class="language-python"># Bins of unequal sizes
plt.hist(flowers_df.sepal_width, bins=[1, 3, 4, 4.5]);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-168.png" class="kg-image" alt="image-168" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-168.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-168.png 741w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h4 id="matplotlib">如何在 MatPlotLib 中管理多个直方图</h4>
<p>与折线图类似，我们可以在一个图表里绘制多个直方图。我们可以降低每个直方图的不透明度，这样每个直方图里的柱条不会遮住其他的。</p>
<p>让我们来为每一个花的品种绘制自己的直方图。</p>
<pre><code class="language-python">setosa_df = flowers_df[flowers_df.species == 'setosa']
versicolor_df = flowers_df[flowers_df.species == 'versicolor']
virginica_df = flowers_df[flowers_df.species == 'virginica']

plt.hist(setosa_df.sepal_width, alpha=0.4, bins=np.arange(2, 5, 0.25));
plt.hist(versicolor_df.sepal_width, alpha=0.4, bins=np.arange(2, 5, 0.25));
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-169.png" class="kg-image" alt="image-169" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-169.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-169.png 735w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>我们还可以将多个直方图堆叠在一起。</p>
<pre><code class="language-python">plt.title('Distribution of Sepal Width')

plt.hist([setosa_df.sepal_width, versicolor_df.sepal_width, virginica_df.sepal_width], 
         bins=np.arange(2, 5, 0.25), 
         stacked=True);

plt.legend(['Setosa', 'Versicolor', 'Virginica']);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-170.png" class="kg-image" alt="image-170" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-170.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-170.png 744w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h3 id="matplotlib">MatPlotLib 中的条</h3>
<p>条形图与折线图很像，都显示一系列的值。只不过，每个值都会显示一个条形，而不是由线连接的点。我们可以使用 <code>plt.bar</code> 函数来绘制条形图。</p>
<pre><code class="language-python">years = range(2000, 2006)
apples = [0.35, 0.6, 0.9, 0.8, 0.65, 0.8]
oranges = [0.4, 0.8, 0.9, 0.7, 0.6, 0.8]

plt.bar(years, oranges);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-171.png" class="kg-image" alt="image-171" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-171.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-171.png 750w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>与直方图一样，我们可以将条形图堆叠在一起。我们使用 <code>plt.bar</code> 的 <code>bottom</code> 参数来实现这一目的。</p>
<pre><code class="language-python">plt.bar(years, apples)
plt.bar(years, oranges, bottom=apples);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-172.png" class="kg-image" alt="image-172" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-172.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-172.png 754w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h4 id="seaborn">Seaborn 中包含平均值的条形图</h4>
<p>我们来看另一个包含 Seaborn 的样本数据集，名为 <code>tips</code>。这个数据集包含有关一周内访问餐厅的客户的性别、时间、总账单和小费金额的信息。</p>
<pre><code class="language-python">tips_df = sns.load_dataset("tips");

tips_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-173.png" class="kg-image" alt="image-173" width="600" height="400" loading="lazy"></figure>
<p>我们可能想要绘制一个条形图来可视化平均账单金额在一周中的不同天数之间的变化。实现的一种方式是计算每日的平均值，然后使用<code>plt.bar</code>（请当做练习来尝试）。</p>
<p>然而，由于这是一个非常普遍的用例，Seaborn 库提供了 <code>barplot</code> 函数，可以自动计算平均值。</p>
<pre><code class="language-python">sns.barplot(x='day', y='total_bill', data=tips_df);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-174.png" class="kg-image" alt="image-174" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-174.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-174.png 770w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>切割每个条形的线表示值的变化量。例如，看起来总账单的变化在周五相对较高，而在周六较低。</p>
<p>我们还可以指定一个 <code>hue</code> 参数来并排比较基于第三个特征的条形图，例如性别。</p>
<pre><code class="language-python">sns.barplot(x='day', y='total_bill', hue='sex', data=tips_df);
</code></pre>
<pre><code class="language-python">sns.barplot(x='total_bill', y='day', hue='sex', data=tips_df);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-175.png" class="kg-image" alt="image-175" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-175.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-175.png 772w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>只需切换坐标轴，就能使条形图水平显示。</p>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-176.png" class="kg-image" alt="image-176" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-176.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-176.png 784w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h3 id="seaborn">Seaborn 中的热度</h3>
<p>热图用于可视化二维数据，如使用颜色的矩阵或表格。理解它的最好方式就是具体看一个例子。</p>
<p>我们将使用另一个 Seaborn 的样本数据集，叫做 <code>flights</code>，来可视化机场在过去12年中的乘客流量。</p>
<pre><code class="language-python">flights_df = sns.load_dataset("flights").pivot("month", "year", "passengers")

flights_df
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-177.png" class="kg-image" alt="image-177" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-177.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-177.png 728w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p><code>flights_df</code> 是一个矩阵，一行表示一月，一列为一年。值显示了在一年中具体某个月到访机场的乘客数量（以千为计）。我们可以使用 <code>sns.heatmap</code> 函数来可视化机场的客流。</p>
<pre><code class="language-python">plt.title("No. of Passengers (1000s)")
sns.heatmap(flights_df);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-178.png" class="kg-image" alt="image-178" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-178.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-178.png 737w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>颜色越明亮，表示机场客流量越大。通过这个图，我们可以推断两件事：</p>
<ul>
<li>在所有给定的年份中，机场客流总是在七八月份达到最高。</li>
<li>每个月机场的客流量都会逐年增加。</li>
</ul>
<p>我们还可以通过指定 <code>annot=True</code> 来显示每个块的实际值，使用 <code>cmap</code> 参数来改变调色板。</p>
<pre><code class="language-python">plt.title("No. of Passengers (1000s)")
sns.heatmap(flights_df, fmt="d", annot=True, cmap='Blues');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-179.png" class="kg-image" alt="image-179" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-179.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-179.png 731w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h3 id="matplotlib">MatPlotLib 中的图片</h3>
<p>我们还可以用 Matplotlib 来显示图片。我们先从网上下载一张图片。</p>
<pre><code class="language-python">from urllib.request import urlretrieve

urlretrieve('https://i.imgur.com/SkPbq.jpg', 'chart.jpg');
</code></pre>
<p>在显示图像之前，必须使用 <code>PIL</code> 模块将图像读入内存。</p>
<pre><code class="language-python">from PIL import Image

img = Image.open('chart.jpg')
</code></pre>
<p>使用 PIL 加载的图像是一个简单的三维 numpy 数组，包含图像红、绿、蓝（RGB）通道的像素强度。我们可以使用 <code>np.array</code> 将图像转换为数组。</p>
<pre><code class="language-python">img_array = np.array(img)

img_array.shape
# (481, 640, 3)
</code></pre>
<p>我们可以使用 <code>plt.imshow</code> 显示 PIL 图像。</p>
<pre><code class="language-python">plt.imshow(img);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-180.png" class="kg-image" alt="image-180" width="600" height="400" loading="lazy"></figure>
<p>我们可以使用相关函数关闭坐标轴和网格线，并显示标题。</p>
<pre><code class="language-python">plt.grid(False)
plt.title('A data science meme')
plt.axis('off')
plt.imshow(img);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-181.png" class="kg-image" alt="image-181" width="600" height="400" loading="lazy"></figure>
<p>要显示图像的一部分，我们只需从 numpy 数组中选择一个片段即可。</p>
<pre><code class="language-python">plt.grid(False)
plt.axis('off')
plt.imshow(img_array[125:325,105:305]);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-182.png" class="kg-image" alt="image-182" width="600" height="400" loading="lazy"></figure>
<h3 id="matplotlibseaborn">MatPlotLib 和 Seaborn 中如何绘制多个图表</h3>
<p>Matplotlib 和 Seaborn 还支持在网格中绘制多个图表，通过使用 <code>plt.subplots</code>，返回用于绘图的轴的系列。</p>
<p>以下单个网格中显示了本教材涵盖的各种不同类型的图表。</p>
<pre><code class="language-python">fig, axes = plt.subplots(2, 3, figsize=(16, 8))

# Use the axes for plotting
axes[0,0].plot(years, apples, 's-b')
axes[0,0].plot(years, oranges, 'o--r')
axes[0,0].set_xlabel('Year')
axes[0,0].set_ylabel('Yield (tons per hectare)')
axes[0,0].legend(['Apples', 'Oranges']);
axes[0,0].set_title('Crop Yields in Kanto')


# Pass the axes into seaborn
axes[0,1].set_title('Sepal Length vs. Sepal Width')
sns.scatterplot(x=flowers_df.sepal_length, 
                y=flowers_df.sepal_width, 
                hue=flowers_df.species, 
                s=100, 
                ax=axes[0,1]);

# Use the axes for plotting
axes[0,2].set_title('Distribution of Sepal Width')
axes[0,2].hist([setosa_df.sepal_width, versicolor_df.sepal_width, virginica_df.sepal_width], 
         bins=np.arange(2, 5, 0.25), 
         stacked=True);

axes[0,2].legend(['Setosa', 'Versicolor', 'Virginica']);

# Pass the axes into seaborn
axes[1,0].set_title('Restaurant bills')
sns.barplot(x='day', y='total_bill', hue='sex', data=tips_df, ax=axes[1,0]);

# Pass the axes into seaborn
axes[1,1].set_title('Flight traffic')
sns.heatmap(flights_df, cmap='Blues', ax=axes[1,1]);

# Plot an image using the axes
axes[1,2].set_title('Data Science Meme')
axes[1,2].imshow(img)
axes[1,2].grid(False)
axes[1,2].set_xticks([])
axes[1,2].set_yticks([])

plt.tight_layout(pad=2);
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-183.png" class="kg-image" alt="image-183" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-183.png 600w, https://www.freecodecamp.org/news/content/images/size/w1000/2021/10/image-183.png 1000w, https://www.freecodecamp.org/news/content/images/2021/10/image-183.png 1383w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<p>通过该网页查看支持函数的完整列表：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org%2F3.3.1%2Fapi%2Faxes_api.html%23the-axes-class">https://matplotlib.org/3.3.1/api/axes_api.html#the-axes-class</a> 。</p>
<h4 id="seaborn">用 Seaborn 来配对绘图</h4>
<p>Seaborn 还提供了一个助手函数 <code>sns.pairplot</code>，用于在一个数据帧内自动绘制多个不同的图表，以显示多个特征对。</p>
<pre><code class="language-python">sns.pairplot(flowers_df, hue='species');
</code></pre>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-184.png" class="kg-image" alt="image-184" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-184.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-184.png 987w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"><figcaption>See the full output <a href="https://jovian.ai/embed?url=https://jovian.ai/aakashns/python-matplotlib-data-visualization/">here</a>.</figcaption></figure>
<pre><code class="language-python">sns.pairplot(tips_df, hue='sex');
</code></pre>
<figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/10/image-185.png" class="kg-image" alt="image-185" srcset="https://www.freecodecamp.org/news/content/images/size/w600/2021/10/image-185.png 600w, https://www.freecodecamp.org/news/content/images/2021/10/image-185.png 748w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure>
<h3 id="">总结及扩展阅读</h3>
<p>本教程涵盖了以下主题：</p>
<ul>
<li>如何使用 Matplotlib 来创建和自定义折线图</li>
<li>如何使用散点图可视化两个或多个变量之间的关系</li>
<li>如何使用直方图和条形图研究变量的分布</li>
<li>如何使用热图可视化二维数据</li>
<li>如何使用 Matplotlib 的 <code>plt.imshow</code> 显示图像</li>
<li>如何在一个网格中显示多个 Matplotlib 和 Seaborn 图表</li>
</ul>
<p>在本章中，我们学习了使用 Matplotlib 和 Seaborn 进行数据可视化的一些基本概念和常用技术。数据可视化是一个很宽泛的领域，我们在这里几乎还没有触及其表层。查阅以下参考文献来学习探索更多内容：</p>
<ul>
<li>数据可视化备忘单：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fjovian.ml%2Faakashns%2Fdataviz-cheatsheet">https://jovian.ml/aakashns/dataviz-cheatsheet</a></li>
<li>Seaborn 资料：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fseaborn.pydata.org%2Fexamples%2Findex.html">https://seaborn.pydata.org/examples/index.html</a></li>
<li>Matplotlib 资料：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fmatplotlib.org%2F3.1.1%2Fgallery%2Findex.html">https://matplotlib.org/3.1.1/gallery/index.html</a></li>
<li>Matplotlib 教程：<a href="https://jovian.ai/outlink?url=https%3A%2F%2Fgithub.com%2Frougier%2Fmatplotlib-tutorial">https://github.com/rougier/matplotlib-tutorial</a></li>
</ul>
<h3 id="">回顾问题来检验你的掌握程度</h3>
<p>尝试回答以下问题来测试你对本文所涵盖的主题的理解程度：</p>
<ol>
<li>数据可视化是什么？</li>
<li>Matplotlib是什么？</li>
<li>Seaborn是什么？</li>
<li>如何安装 Matplotlib 和 Seaborn？</li>
<li>如何导入 Matplotlib 和 Seaborn？导入这两个模块时常用的别名是什么？</li>
<li>神奇命令 <code>%matplotlib inline</code> 的作用是什么？</li>
<li>什么是折线图？</li>
<li>如何在 Python 中绘制折线图？举例说明。</li>
<li>如何指定折线图 X 轴的值？</li>
<li>如何为图表的轴指定标签？</li>
<li>如何在同一轴上绘制多个折线图？</li>
<li>如何显示包含多个线条的折线图的图例？</li>
<li>如何设置图表的标题？</li>
<li>如何显示折线图的标记？</li>
<li>折线图中线条和标记的样式有哪些不同的选项？举例说明。</li>
<li><code>plt.plot</code> 中 <code>fmt</code> 参数的作用是什么？</li>
<li>在哪能找到可以被 <code>plt.plot</code> 接受的所有参数的列表？</li>
<li>如何使用 Matplotlib 更改图形的大小？</li>
<li>如何将 Seaborn 的默认样式应用于全局所有的图表？</li>
<li>Seaborn 中可用的预定义样式有哪些？举例说明。</li>
<li>什么是散点图？</li>
<li>散点图与折线图有何不同？</li>
<li>如何使用 Seaborn 绘制散点图？举例说明。</li>
<li>如何判断什么时候使用散点图和折线图？</li>
<li>如何使用分类变量为散点图上的点指定颜色？</li>
<li>如何为 Seaborn 绘图自定义标题、图形大小、图例等？</li>
<li>如何使用带有 <code>sns.scatterplot</code> 的 Pandas 数据框？</li>
<li>什么是直方图？</li>
<li>什么时候应该使用直方图和折线图？</li>
<li>如何使用 Matplotlib 绘制直方图？举例说明。</li>
<li>直方图中的“组距”是什么？</li>
<li>如何更改直方图中组距的数量？</li>
<li>如何更改直方图中组距的大小？</li>
<li>如何在同一轴上显示多个直方图？</li>
<li>如何将多个直方图堆叠在一起？</li>
<li>什么是条形图？</li>
<li>如何使用 Matplotlib 绘制条形图？举例说明。</li>
<li>条形图和直方图的区别是什么？</li>
<li>条形图和折线图的区别是什么？</li>
<li>你如何将条形堆叠在一起？</li>
<li><code>plt.bar</code> 和 <code>sns.barplot</code> 的区别是什么？</li>
<li>在 Seaborn 条形图中，分割柱状条的线条代表了什么？</li>
<li>如何并排显示条形图？</li>
<li>如何绘制水平条形图？</li>
<li>什么是热图？</li>
<li>什么类型的数据最好用热图来进行可视化？</li>
<li>Pandas 数据帧中的 <code>pivot</code> 方法是干什么用的？</li>
<li>如何用 Seaborn 来绘制热图？举例说明。</li>
<li>如何更改热图的颜色方案？</li>
<li>如何显示热图中数据集的原始值？</li>
<li>如何用 Python 从 URL 下载图片？</li>
<li>如何用 Python 打开图片以用于处理？</li>
<li>Python 中 <code>PIL</code> 模块的作用是什么？</li>
<li>如何将 PIL 下载的图片转换成 Numpy 数组？</li>
<li>图片的 Numpy 数组有几维？每个维度代表什么？</li>
<li>图片中的“颜色通道”是什么意思？</li>
<li>什么是 RGB？</li>
<li>如何用 Matplotlib 显示图片？</li>
<li>如何关闭图表中的轴和网格线？</li>
<li>如何使用 Matplotlib 显示部分图片？</li>
<li>如何用 Matplotlib 和 Seaborn 在单个网格中绘制多个图表？举例说明。</li>
<li><code>plt.subplots</code> 函数的作用是什么？</li>
<li>什么是 Seaborn 的配对绘图？举例说明。</li>
<li>如何用 Matplotlib 将图表导出到 PNG 图片？</li>
<li>在哪里可以学到能用 Matplotlib 和 Seaborn创建的不同类型的图表？</li>
</ol>
<p>祝贺你完成本教程的学习！现在，你可以应用这些技能来分析来自以下来源的真实世界数据集：<a href="https://kaggle.com/datasets">Kaggle</a>。</p>
<p>如果你想从事数据科学和机器学习的工作，可以考虑加入<a href="https://jovian.ai/zero-to-data-science-bootcamp">从零开始数据科学训练营（约维安）</a>。这是一个为期20周的业余课程，你将完成7门课程、12个编码作业和4个真实的项目。你还将获得6个月的职业支持，以帮助你找到第一份数据科学工作。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 什么是软件测试？ 开发人员在项目中使用的 10 种最常见的测试类型 ]]>
                </title>
                <description>
                    <![CDATA[ 软件开发和软件测试密不可分。在敏捷软件开发中，会经常发布迭代版本，你必须非常频繁地做测试。 如果你想更高效地做测试，就需要知道不同的测试类型，以及在什么时候使用它们。 在这篇文章中，我想谈谈其中的一些测试类型，它们能帮助你确保产品或者应用的可操作性、完整性和安全性。 软件测试金字塔 （《软件测试金字塔》 如果觉得这张图片很赞，可以随意分享到你的博客或者推特。） 软件测试金字塔覆盖了整个软件开发生命周期 [/news/get-a-basic-understanding-of-the-life-cycles-of-software-development/] （SDLC）。它从底层的单元测试开始延伸，穿过集成测试，到顶部的功能性测试结束。 然而，这些测试类型并没有固定的套路，相反，你需要自己来决定哪种才最适合你的需求。为了决定选哪一种，你需要综合考虑使用它们所需的费用、时间以及资源。 敏捷软件开发者也常使用软件测试四象限 [https://www.kaizenko.com/what-is-the-agile-testing-quadrant/] ，这个法则根据是面向业务还是 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/types-of-software-testing/</link>
                <guid isPermaLink="false">60dacf68240b4e0653a3e15d</guid>
                
                    <category>
                        <![CDATA[ 软件测试 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Fri, 29 Oct 2021 07:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/06/pexels-thisisengineering-3861969.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>软件开发和软件测试密不可分。在敏捷软件开发中，会经常发布迭代版本，你必须非常频繁地做测试。</p>
<p>如果你想更高效地做测试，就需要知道不同的测试类型，以及在什么时候使用它们。</p>
<p>在这篇文章中，我想谈谈其中的一些测试类型，它们能帮助你确保产品或者应用的可操作性、完整性和安全性。</p>
<h2 id="">软件测试金字塔</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Instagram-Square-Pyramid-Chart---CC.png" alt="The Software Testing Pyramid" width="600" height="400" loading="lazy"></p>
<p>（《软件测试金字塔》 如果觉得这张图片很赞，可以随意分享到你的博客或者推特。）</p>
<p>软件测试金字塔覆盖了整个<a href="https://chinese.freecodecamp.org/news/get-a-basic-understanding-of-the-life-cycles-of-software-development/">软件开发生命周期</a>（SDLC）。它从底层的单元测试开始延伸，穿过集成测试，到顶部的功能性测试结束。</p>
<p>然而，这些测试类型并没有固定的套路，相反，你需要自己来决定哪种才最适合你的需求。为了决定选哪一种，你需要综合考虑使用它们所需的费用、时间以及资源。</p>
<p>敏捷软件开发者也常使用<a href="https://www.kaizenko.com/what-is-the-agile-testing-quadrant/">软件测试四象限</a>，这个法则根据是面向业务还是面向技术，是评论产品还是支持团队这两个维度来对测试进行归类。</p>
<p>例如，单元测试是一种支持团队的面向技术的测试，而可用性测试是一种发现产品问题的面向业务的测试。</p>
<p>现在让我们一起来看看一些重要的测试类型。</p>
<h2 id="">单元测试定义</h2>
<p>单元测试是指测试单个代码组件，而不是整块代码。它验证所有组件逻辑的可操作性，以便在软件开发生命周期的早期阶段就发现缺陷，在进一步开发之前，对其进行修复。</p>
<p>单元测试也叫做“白盒”测试，因为需要完全掌握应用程序的结构和环境才能进行。</p>
<p>下面这个单元测试的例子，创建了模拟对象用于测试代码块，如还未生成参数变量的函数。</p>
<pre><code class="language-JavaScript">const mocha = require('mocha')
const chai = require('chai')  // It is an assertion library
describe('Test to check add function', function(){
  it('should add two numbers', function(){
    (add(2,3)).should.equal(5)  //Checking that 2+3 should equal 5 using the given add function
  });
});
</code></pre>
<h2 id="">集成测试定义</h2>
<p>单元测试往上一步就是集成测试，它把各个组件联合起来，作为一个组来进行测试。集成测试用于识别各个组件之间交互时出现的问题，以检验代码是否符合功能说明书。</p>
<p>集成测试区别于单元测试的一个点是，它关注独立工作在整个组里面的模块和组件。而另外一边，单元测试关注于在测试前隔离模块或组件。</p>
<p>集成测试的关键是，在集成后的模块或组件之间，暴露任何软件缺陷或漏洞。</p>
<p>拿一个更为简单的例子来说，如果你正在对刚创建的邮箱服务进行一项集成测试，那么你需要测试各个组件，如撰写邮件、保存草稿、发件、移动到收件箱、登出等等。</p>
<p>在这之前，你得先对单个特性进行一次单元测试，主要是跟集成测试中相关的每个功能函数。</p>
<h2 id="">端到端测试定义</h2>
<p>金字塔的顶部是端到端测试。如名所示，端到端测试重复应用程序的所有操作，以测试应用程序的连接性和依赖性的方方面面。这包括网络连接、数据访问和外部依赖。</p>
<p>端到端测试在模拟真实用户的环境下进行。</p>
<p>你可以通过某些指标来定义端到端测试是否成功，包括测试状态（用可视化图表来跟踪）和报告状态（用于展示测试执行的状态和已发现的漏洞或缺陷）。</p>
<h2 id="">软件测试类型</h2>
<p>测试金字塔的每个层级都包含了各式各样的具体流程，用于测试各种应用程序功能和特性，也包括应用程序的完整性和安全性。</p>
<h3 id="">应用程序安全性测试定义</h3>
<p>应用程序安全性测试是应用程序各种测试类型中最重要的一个。它帮助你识别应用程序漏洞，这些漏洞很有可能被黑客利用，所以要在发布产品或应用之前把它们修复掉。</p>
<p>有很多应用程序安全性测试供你使用，它们可应用于软件开发生命周期中的不同部分。</p>
<p>你可以在测试金字塔的不同层级找到不同类型的应用安全性测试。每种测试都有其自己的优点和缺点。你应该同时使用不同的测试类型，以确保它们整体上的完整性。</p>
<h3 id="sast">静态应用程序安全性测试（SAST）定义</h3>
<p>你应该在软件开发生命周期早期使用静态应用程序安全性测试（SAST）。它是单元测试的一个例子。</p>
<p>SAST 反映了开发人员的能力，包括应用程序的通用设计和实现，因此它是白盒测试，或者叫由内而外的测试。</p>
<p>SAST 分析代码本身而不是最终的应用程序，你不需要执行代码就可以运行起来。</p>
<p><img src="https://lh4.googleusercontent.com/R4aFSAcHZcrpNNzFnLlYk-vtXFq7QnjIJKzx_jvqmt-ycGE8CcMozgirFIxfXVXKkjYs1dV_nIQrhCFRC809_Kzp3FLvMqRw519XnDQHX8VEV0065Scw-SzxQlJg44xWeggZx2-e" alt="R4aFSAcHZcrpNNzFnLlYk-vtXFq7QnjIJKzx_jvqmt-ycGE8CcMozgirFIxfXVXKkjYs1dV_nIQrhCFRC809_Kzp3FLvMqRw519XnDQHX8VEV0065Scw-SzxQlJg44xWeggZx2-e" width="600" height="400" loading="lazy"></p>
<p><a href="https://www.seciq.in/static-application-security-testing/">图片来源</a></p>
<p><a href="https://www.clouddefense.ai/sast-static-application-security-testing">云防御</a>的安全分析师说，</p>
<blockquote>
<p>“SAST 检查你的代码是否违反安全性规则，同时在源分支和目标分支之间比较已发现的漏洞……一旦项目新发现的漏洞会影响项目依赖性，你就会被通知到。”</p>
</blockquote>
<p>一旦发现漏洞，你就可以在最终应用程序构建之前把它们解决掉。</p>
<p>你应该在软件项目的开发阶段就将 SAST 应用进去。在设计和编写应用程序时就将 SAST 扫描包含到开发流程中，不失为一个好方法。</p>
<h3 id="dast">动态应用程序安全性测试（DAST）定义</h3>
<p>处于另一端的是动态应用程序安全性测试（DAST），它测试完整编译好的应用程序。你设计和运行这些测试时，不需要知道潜在的结构或代码。</p>
<p>因为 DAST 采用黑客视角，它被称为黑盒测试，或由外向内的测试。</p>
<p>DAST 通过攻击运行中的代码以及寻找可利用的潜在漏洞来进行测试。DAST 可能采用跨站点脚本和 SQL 注入等常见攻击技术。</p>
<p>DAST 在软件开发生命周期后面才进行，它是集成安全性测试的一个例子。由于很慢（一整个完整的应用程序的 DAST 测试平均可能需要花 5 到 7 天），它会为你揭示应用程序中黑客最有可能攻击的漏洞。</p>
<h3 id="">交互式应用程序安全性测试定义</h3>
<p>交互式应用程序安全性测试（IAST）是一种比较新的测试方法，它结合了 SAST 和 DAST 的高效性，同时克服了与这些确立的测试相关联的问题。</p>
<p>IAST 使用一种插入式的监控代理，来对应用程序进行持续实时扫描，从而发现错误和漏洞。尽管 IAST 是在应用程序运行时进行的, 它仍然被当作是一个 SDLC 早期的测试过程。</p>
<p>不管你在寻找什么样的软件进行测试，IAST 最适合在 QA（质量保证）环境中使用，同样，也很适合专门设计出来用于复制客户或者顾客真实使用产品的场景。</p>
<h3 id="">兼容性测试定义</h3>
<p>兼容性测试评估你的应用程序如何运行，以及它在各种设备和环境（包括移动设备和不同操作系统）上的安全性。</p>
<p>兼容性测试还可以评估当前版本的软件是否与其他软件版本兼容。版本测试可以是朝后或者朝前的。</p>
<p><img src="https://lh6.googleusercontent.com/SDElGdbGkactASCRfFSfWXcdOM36IiAQnDZ3uofeiYAeaxzvwvaQzB9cEqEcUFu7L6Z3GxjoC_nCMy0NhgANP8XdjP3s9MKcxvvMdrZsIsmq3kuIJMYbmViDsbAQpBrvyGZscgm0" alt="SDElGdbGkactASCRfFSfWXcdOM36IiAQnDZ3uofeiYAeaxzvwvaQzB9cEqEcUFu7L6Z3GxjoC_nCMy0NhgANP8XdjP3s9MKcxvvMdrZsIsmq3kuIJMYbmViDsbAQpBrvyGZscgm0" width="600" height="400" loading="lazy"></p>
<p><a href="https://www.testrigtechnologies.com/service/compatibility-testing/">图片来源</a></p>
<p>兼容性测试的例子包括：</p>
<ul>
<li>浏览器测试（检查以确保你的网站或移动网址与不同的浏览器完全兼容）</li>
<li>移动测试（确保您的应用程序与 iOS 和 Android 兼容）</li>
<li>或软件测试（如果你要创建多个需要彼此交互的软件应用程序，那么需要进行兼容性测试以确保它们正常运行）。</li>
</ul>
<h2 id="">软件测试金字塔之外</h2>
<p>测试金字塔的修改版本可以包括与端到端测试相邻或之上的层级。此层级包括针对应用程序用户的测试。</p>
<h3 id="">性能测试定义</h3>
<p>你需要知道应用程序将如何在各种不同的条件下工作，这就是性能测试的目的。性能测试可以对各种负载和压力进行建模，以评估应用程序的稳健性。性能测试的类型基于所应用的条件。</p>
<p>性能测试的一个例子是负载测试，用于确定最大负载，即系统何时会崩溃。</p>
<p>另一方面，另一个例子，如可扩展性测试，将逐渐增加的负载应用于系统，以评估适应增加的系统压力的方法。</p>
<p>尖峰测试用于评估对系统突然施加大负载变化所带来的影响。</p>
<p>在任何软件系统面向市场之前，你都应该对其进行性能测试。测试其稳定性、可扩展性和速度，这样你才可以在上线之前就识别要修复的内容。</p>
<h3 id="">可用性测试定义</h3>
<p>测试应用程序接口的实际使用是一项重要的任务。理解应用的功能是否按设计运行是一回事，而这个设计本身是否为用户所接受又是另一回事了。这就是可用性测试的出发点。</p>
<p>通过可用性测试，开发人员可以评估用户对特定应用程序特性和功能的反应。这包括你可能事先知道从用户角度来看不太理想的功能，但是这些功能是强安全性和正确操作所必需的（像强密码这种要求）。</p>
<p>可用性测试与外观问题或修复任何书面文本中的语法错误无关（尽管这两个问题本身当然很重要）。相反，它与终端用户使用应用程序的难易程度有关。</p>
<h2 id="">结论</h2>
<p>测试不仅仅是应用程序开发结束后 QA 部门应该做的事情，它也是软件开发过程的重要组成部分。</p>
<p>了解你可以使用哪些测试以及它们如何工作，将帮助你保证应用程序运行良好、安全并且为最终用户所接受。</p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/types-of-software-testing/">What is Software Testing? The 10 Most Common Types of Tests Developers Use in Projects</a>，作者：<a href="https://www.freecodecamp.org/news/author/nahla/">Nahla Davies</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ CSS Background Color——如何更改 HTML 中的背景色 ]]>
                </title>
                <description>
                    <![CDATA[ 假设你已经创建了 HTML 网页，现在想给它加点颜色——可能是更改字体颜色，又或是设置一个漂亮的背景色。你会怎么做呢？ 在这篇文章中，我将向你展示，如何用几种不同的方式更改页面的背景颜色。 如何更改一个 HTML 元素的背景色 想要改变一个 HTML 元素的背景色，你可以使用 background-color  这个 CSS 属性，给它赋上一个颜色值。 p {   background-color: pink; } 上面的代码给段落设置了粉色的背景。 例如，这份代码将使得 HTML 页面中的所有段落元素拥有一个粉色的背景，因为 background-color  属性的值是 pink。 你可以使用大约 140 种颜色，例如 teal、hotpink、indigo  等等。 你可以使用的一些可能的颜色名称注意：如果你给一个元素设置了 background-color，但是没有看到变化，很可能是一个语法错误，也可能是因为没有给这个元素设置宽和高。尝试放一些内容进去，或者通过 CSS 属性  width  和 height  给它设置宽和高。 实际上大概有 1680 万 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/css-background-color-how-to-change-the-background-color-in-html/</link>
                <guid isPermaLink="false">610fee86c8a51b065cd07838</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Sun, 08 Aug 2021 12:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/08/html-background-color-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>假设你已经创建了 HTML 网页，现在想给它加点颜色——可能是更改字体颜色，又或是设置一个漂亮的背景色。你会怎么做呢？</p>
<p>在这篇文章中，我将向你展示，如何用几种不同的方式更改页面的背景颜色。</p>
<h1 id="html">如何更改一个 HTML 元素的背景色</h1>
<p>想要改变一个 HTML 元素的背景色，你可以使用 <code>background-color</code> 这个 CSS 属性，给它赋上一个颜色值。</p>
<pre><code class="language-CSS">p {
  background-color: pink;
}
</code></pre>
<p>上面的代码给段落设置了粉色的背景。</p>
<p>例如，这份代码将使得 HTML 页面中的所有段落元素拥有一个粉色的背景，因为 <code>background-color</code> 属性的值是 <code>pink</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-16.png" alt="image-16" width="600" height="400" loading="lazy"></p>
<p>你可以使用大约 140 种颜色，例如 <code>teal</code>、<code>hotpink</code>、<code>indigo</code> 等等。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-23.png" alt="你可以使用的一些可能的颜色名称" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>你可以使用的一些可能的颜色名称</figcaption>
</figure>
<p>注意：如果你给一个元素设置了 background-color，但是没有看到变化，很可能是一个语法错误，也可能是因为没有给这个元素设置宽和高。尝试放一些内容进去，或者通过 CSS 属性 <code>width</code> 和 <code>height</code> 给它设置宽和高。</p>
<p>实际上大概有 1680 万种颜色可供你使用。你可以通过 RGB 值来使用它们。还有 HSL 颜色，大约有 370 万种可供你选择。在下一节中，你将了解所有这些创建颜色的不同方法。</p>
<h1 id="">不同的颜色表示</h1>
<p><code>background-color</code> 属性接受颜色作为可能的值。这里，你将看到四种不同的颜色值表示法。</p>
<p>第一种是颜色名称，差不多有 140 个关键字可供你使用。这是最简单的一种选择颜色的方式，因为它不要求掌握特殊符号——但它的选择范围有限。</p>
<p>第二种、第三种命名或者选择颜色的方式分别是用 RGB 值和十六进制值。这两种方式里，颜色由它们包含的红色、绿色和蓝色的数量来标识。</p>
<p>这源自于屏幕显示颜色的工作原理。屏幕由像素组成，每个像素由绿、蓝和红三种不同颜色的 LED 点亮，它们可以发出不同强度的光。</p>
<p>第四种表示法是 HSL 颜色，或者 Hue-Saturation-Lightness。这种表示来自平面设计，因为它反映了人类思考颜色的一种更自然的方式：纯色（色调），其饱和度和亮度可以变化。</p>
<p>你可以使用任意一种方式来给背景设置颜色，但是让我们来看更多的细节，以便你选择你中意的方式。</p>
<h2 id="html">HTML 颜色名称</h2>
<p>HTML 的第一个版本中能识别出 16 种基本颜色。现在你可以使用 140 多种命名颜色。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-24.png" alt="16 种基本颜色" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>16 种基本颜色</figcaption>
</figure>
<pre><code class="language-CSS">body {
  background-color: black;
}
</code></pre>
<p>这条 CSS 给 <code>body</code> 设置黑色背景。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-17.png" alt="一个 HTML 页面的例子，其中 body 被赋予了 black 的 background-color" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>一个 HTML 页面的例子，其中 body 被赋予了 black 的 background-color</figcaption>
</figure>
<p>你可以在文章末尾的附录中看到所有命名的颜色。</p>
<h2 id="rgb">RGB 颜色</h2>
<p>RGB 代表 Red-Green-Blue。在这种格式下，颜色被写成 <code>rgb(0,0,0)</code>，其中每个值都是介于 <code>0</code> 和 <code>255</code> 之间的数字，分别表示用于组成每种颜色的红色、绿色和蓝色的数量。</p>
<p>例如，<code>rgb(0,0,0)</code> 表示黑色。</p>
<p>要获得红色，你可以写成 <code>rgb(255,0,0)</code>，使得红色最大化为 <code>255</code>，绿色为 <code>0</code>，蓝色为 <code>0</code>。</p>
<p>通过较小数值的绿色和（或）蓝色，以及少一点的红色，你可以得到红色的其他变种。例如，用 <code>rgb(255,69,0)</code> 可以得到橘红色，用 <code>rgb(139,0,0)</code> 可以得到深红色。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-25.png" alt="上面提到的 rgb 值的颜色" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>上面提到的 rgb 值的颜色</figcaption>
</figure>
<pre><code class="language-CSS">div {
  background-color: rgb(139,0,0);
}
</code></pre>
<p>给 <code>div</code> 元素设置深红色背景。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-18.png" alt="image-18" width="600" height="400" loading="lazy"></p>
<p>上图是一个 HTML 页面的例子，其中 <code>div</code> 元素被赋予了 <code>rgb(139,0,0)</code> 的 <code>background-color</code></p>
<p>下面的例子展示了，当调整其中两个 RGB 值时，颜色是如何变化的：彩色方块的左上角等于 <code>rgb(0,0,0)</code>，右上角等于 <code>rgb(0,0,255)</code>，左下角等于 <code>rgb(0,255,0)</code>，右下角等于 <code>rgb(0,255,255)</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-28.png" alt="image-28" width="600" height="400" loading="lazy"></p>
<p>幸运的是，你不需要靠猜测数值来获得你想要的颜色。你可以在网上找到各种各样的颜色选取器，让你使用滑块（或其他方法）选择颜色并提供给你要使用的 RGB 颜色值。</p>
<h2 id="">十六进制颜色</h2>
<p>十六进制颜色是编写 RGB 颜色的另一种方式。对于十六进制，依然有三个数字，每种颜色对应一个，每一个数字有 256 种可能的值。</p>
<p>但是，在这种情况下，每种颜色有两个数字，分别从 <code>0</code> 到 <code>F</code>（也就是，<code>0</code>，<code>1</code>，<code>2</code>，<code>3</code>，<code>4</code>，<code>5</code>，<code>6</code>，<code>7</code>，<code>8</code>，<code>9</code>，<code>A</code>，<code>B</code>，<code>C</code>，<code>D</code>，<code>E</code>，<code>F</code>)。一位数字有 16 个可能的值，两位数字有 256 个可能的值，从 <code>00</code> 到 <code>FF</code>（255）。</p>
<p>用十六进制颜色编写时，要在数值的前面加一个 <code>#</code>。例如，红色写成 <code>#FF0000</code>，深红色写成 <code>#8B0000</code>，橘红色写成 <code>#FF4500</code>。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-2.png" alt="上一节中提到的颜色" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>上一节中提到的颜色</figcaption>
</figure>
<pre><code>h1 {
  background-color: #FF4500;
}
</code></pre>
<p>给 <code>h1</code> 元素设置橘红色背景。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-19.png" alt="image-19" width="600" height="400" loading="lazy"></p>
<p>上图是一个 HTML 页面的例子，其中 <code>h1</code> 元素被赋予了 <code>#FF4500</code> 的 <code>background-color</code></p>
<p>你也可以用颜色选取器来生成十六进制值。</p>
<h3 id="">十六进制简写</h3>
<p>你可以用简写的形式来写十六进制数值，只用三位数而不是六位数。例如，你可以将红色写成 <code>#F00</code>。这将可能的颜色数量减少到略高于 4000，但写入时间较短，有时这很重要。</p>
<p>每个数字代替两个相同的数字，所以我们无法将 <code>#8B0000</code> 简写，因为 <code>8</code> 和 <code>B</code> 不一样。但是我们可以写 <code>#800</code>，这等价于 <code>#880000</code>，非常接近深红色。橘红色可以写成 <code>#F40</code>（等价于 <code>#FF4400</code>）。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-8.png" alt="上一节中提到的颜色" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>上一节中提到的颜色</figcaption>
</figure>
<h2 id="hsl">HSL 颜色</h2>
<p>HSL 表示 Hue-Saturation-Lightness，这是一种目前为止我们看到的完全不同的颜色书写方式。</p>
<p>HSL 颜色用三个数字表示：色调从 <code>0</code> 到 <code>360</code>，饱和度和亮度从 <code>0</code> 到 <code>100</code>。</p>
<p>色调决定了基色，它的值是一个角度，色轮上的度数。在这种情况下，红色是 <code>0</code>，绿色是 <code>120</code>，蓝色是 <code>240</code>，然后 <code>360</code> 依然还是红色。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-11.png" alt="所有可能的颜色仅改变色调，左侧色调为 0，右侧色调为 360" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>所有可能的颜色仅改变色调，左侧色调为 0，右侧色调为 360</figcaption>
</figure>
<p>饱和度从 <code>0</code> 开始，也就是灰色，到 <code>100</code>，也就是全色。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-9.png" alt="红色饱和度变化，左侧为 0%，右侧为 100%" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>红色饱和度变化，左侧为 0%，右侧为 100%</figcaption>
</figure>
<p>亮度是添加到颜色中的黑色或白色的数量。<code>0</code> 表示黑色，<code>50</code> 是颜色其本身，<code>100</code> 表示白色。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/08/image-10.png" alt="亮度变化，左侧为 0%，右侧为 100%" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>亮度变化，左侧为 0%，右侧为 100%</figcaption>
</figure>
<p>例如，你要将红色写成 <code>hsl(0,100%,50%)</code>，橘红色写成 <code>hsl(16,100%,50%)</code>，深红色写成 <code>hsl(0,100%,27%)</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-26.png" alt="image-26" width="600" height="400" loading="lazy"></p>
<p>相比其他配色方案，使用 HSL 更容易找到相似的颜色。从红色以及它的变种色，你已经看到，要获取更深的红色，你只需要改变亮度的百分比就可以了，而将红色与其他颜色相混，足以改变其色调。</p>
<p>让我们用十六进制的混合颜色来看看它的效果，如橙色（<code>#FFA500</code> 或 <code>rgb(255,166,0)</code>），写成 HSL 就是 <code>hsl(39,100%,50%)</code>。通过提高亮度，你可以得到一个更亮的橙色。</p>
<p>例如，写成 <code>hsl(39,100%,65%)</code> 就能得到更亮的橙色，而用其他表示法，你需要写成 <code>rgb(255,193,77)</code> 或者 <code>#FFC14D</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-27.png" alt="image-27" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-20.png" alt="image-20" width="600" height="400" loading="lazy"></p>
<p>上面是一个 HTML 页面的例子，其中 <code>main</code> 元素被赋予了 <code>hsl(39, 100%, 65%)</code> 的 <code>background-color</code></p>
<p>你也可以在网上找到用于 HSL 颜色的选取器。</p>
<h1 id="">属性名简写</h1>
<p>你也可以使用简写的 <code>background</code> 属性来设置背景色.</p>
<pre><code class="language-CSS">p {
  background: pink;
}

body {
  background: black;
}

div {
  background: rgb(139,0,0);
}

h1 {
  background: #FF4500;
}

main {
  background: hsl(39,100%,65%);
}
</code></pre>
<p>与前面看到的 CSS 属性一样，只是换成了 <code>background</code> 简写属性。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-21.png" alt="image-21" width="600" height="400" loading="lazy"></p>
<p>上面是一个 HTML 页面的例子，其中所有元素都被赋予了一种背景色。</p>
<p>这是一个更通用的属性，<a href="https://chinese.freecodecamp.org/news/learn-css-background-properties/">因为它是各种 <code>background</code> 属性的简写</a>，如 <code>background-image</code> 和 <code>background-position</code>。当你将它与颜色值一起使用时，它的作用与 <code>background-color</code> 完全一样。</p>
<h1 id="">总结</h1>
<p>你已经学习了如何给 HTML 元素设置背景色，可以用 <code>background-color</code> 属性以及它的简写属性 <code>background</code>，也学习了不同的颜色表示法。</p>
<p>现在你拥有了为网页添加任何颜色所需的所有工具。好好享受吧！</p>
<h1 id="">附录</h1>
<h2 id="140">全部 140 多种命名颜色</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/CodePen-colored-squares-2.png" alt="CodePen-colored-squares-2" width="600" height="400" loading="lazy"></p>
<h2 id="">拼写的变体</h2>
<p>包含单词 “Gray” 的颜色名称，也可以写成像下面这样，拼写成 “Grey”。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-22.png" alt="image-22" width="600" height="400" loading="lazy"></p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/css-background-color-how-to-change-the-background-color-in-html/">CSS Background Color – How to Change the Background Color in HTML</a>，作者：<a href="https://www.freecodecamp.org/news/author/ilenia/">Ilenia Magoni</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 详解 JavaScript 模块（含示例） ]]>
                </title>
                <description>
                    <![CDATA[ 模块是一个函数或一组相似的函数。它们组合起来放在一个文件里，其代码被大型应用程序调用时，能够执行一项具体的任务。 创建模块可以更好地组织并结构化你的代码库。你可以使用模块来拆解大型程序，拆成更小、更好管理、更独立的代码块，这些代码块执行单一的任务，或者多个相关的任务。 模块应该是:  1. 独立的/自我包含的：  模块必须尽可能与其他依赖项分离。  2. 具体的：  模块要能执行单个或一组相关的任务。最初创建它们的核心本质是创建单独的功能块。一个模块，对应于一个（种）任务。  3. 可重用的：  模块必须能很容易地集成到各种各样的程序来执行其任务。 为了更好地阐述，我给你打个比方： 假设我们想从头开始建造一座大房子。建造房子所需的所有工具都堆放在一个房间里。 在这种情况下，如果想以正确的方式组织这些工具，以便我们开始建造，将会很困难。 不同于将独立的依赖项全部堆放在一个房间里，我们应该将每一系列相关的工具组合，分组放到不同的房间里。每个房间都是独立的，只包含其解决指定任务的工具。 我们可以贴上标签，如：“这些工具用于建屋顶”，“这些工具用于砌砖”，“这些工具用于挖地基” ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/javascript-modules-explained-with-examples/</link>
                <guid isPermaLink="false">610658efc8a51b065cd07333</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Sun, 01 Aug 2021 08:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/08/boitumelo-phetla-1gZQ5chmcH0-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>模块是一个函数或一组相似的函数。它们组合起来放在一个文件里，其代码被大型应用程序调用时，能够执行一项具体的任务。</p>
<p>创建模块可以更好地组织并结构化你的代码库。你可以使用模块来拆解大型程序，拆成更小、更好管理、更独立的代码块，这些代码块执行单一的任务，或者多个相关的任务。</p>
<p>模块应该是:</p>
<ol>
<li><strong>独立的/自我包含的：</strong> 模块必须尽可能与其他依赖项分离。</li>
<li><strong>具体的：</strong> 模块要能执行单个或一组相关的任务。最初创建它们的核心本质是创建单独的功能块。一个模块，对应于一个（种）任务。</li>
<li><strong>可重用的：</strong> 模块必须能很容易地集成到各种各样的程序来执行其任务。</li>
</ol>
<p>为了更好地阐述，我给你打个比方：</p>
<p>假设我们想从头开始建造一座大房子。建造房子所需的所有工具都堆放在一个房间里。</p>
<p>在这种情况下，如果想以正确的方式组织这些工具，以便我们开始建造，将会很困难。</p>
<p>不同于将独立的依赖项全部堆放在一个房间里，我们应该将每一系列相关的工具组合，分组放到不同的房间里。每个房间都是独立的，只包含其解决指定任务的工具。</p>
<p>我们可以贴上标签，如：“<strong>这些工具用于建屋顶</strong>”，“<strong>这些工具用于砌砖</strong>”，“<strong>这些工具用于挖地基</strong>”等。</p>
<p>每当我们想要一个工具来执行特定任务时，我们能准确知道应该去哪个房间找它。这样，一切都更有条理，更好定位。</p>
<p>另外，假设我们已经完成了房子的建造，然后决定建造一些不同的东西。我们仍然可以使用相同的工具集。这强化了<strong>可重用性</strong>的原则。模块可重用，因为它们是独立的。</p>
<h2 id="">一个模块的例子</h2>
<p>目前在代码环境中，模块非常重要。</p>
<p>让我们来考虑一个电子商务应用程序的简化版例子，它用于个人和企业在线销售产品。这个程序非常典型地由两个或多个不相关的任务组成，例如：</p>
<ul>
<li>创建帐户</li>
<li>验证信息</li>
<li>处理支付</li>
<li>计算用户评分</li>
</ul>
<p>等等。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/main-task.png" alt="main-task" width="600" height="400" loading="lazy"></p>
<p>不同于把所有不相关的程序放到一个模块\文件中，为这些任务创建若干个文件或者模块才是更好的方式。在这种情况下，模块变成了依赖项。</p>
<p>然后在主应用或者主程序中，你可以简单地导入\载入依赖项（也就是你需要的模块），并相应地执行。由此，你的主应用变得更简洁更小。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/modules.png" alt="modules" width="600" height="400" loading="lazy"></p>
<div style="text-align:center; margin-bottom: 1.5em;">main.js 已被拆分为四个模块</div>
<p>例如，假设你需要在代码库的其他应用中处理支付功能，这就变得很容易去重用相同的功能。不需要复制粘贴，也不需要从头编写新功能。</p>
<h2 id="javascript">JavaScript 模块</h2>
<p>JavaScript 中的模块就是一个包含相关代码的文件。</p>
<p>JavaScript 使用 <code>import</code> 和 <code>export</code> 关键字在不同模块之间进行分享和接受功能块。</p>
<ul>
<li>关键字 <code>export</code> 使得其他模块可以访问变量、函数、类和对象。换句话说，它变成了公共代码。</li>
<li>关键字 <code>import</code> 用于从其他模块引入公共代码。</li>
</ul>
<p>让我们来看一个简单的例子：</p>
<pre><code class="language-js">function getPower(decimalPlaces) {
	return 10 ** decimalPlaces;
}

function capitalize(word) {
	return word[0].toUpperCase() + word.slice(1);
}

function roundToDecimalPlace(number, decimalPlaces = 2) {
	const round = getPower(decimalPlaces);
	return Math.round(number * round) / round;
}

export { capitalize, roundToDecimalPlace };
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/main.js</div>
<p>这个模块定义了三个函数：</p>
<ul>
<li><code>getPower</code>：此函数获取数字的幂</li>
<li><code>capitalize</code>：此函数将单词中的第一个字母大写</li>
<li><code>roundToDecimalPlace</code>：此函数将给定的数字四舍五入到指定的小数位数。</li>
</ul>
<p>在文件的最后，可以看到三个函数中的两个被导出了。换句话说，它们变成了公共函数，可以被其他脚本使用了。</p>
<p>要从三个函数中导出两个，使用 <code>export</code> 关键字，并在后面加上一个对象，包含你想要访问的函数。一旦这样做，该代码库中需要这些函数的任何程序，都可以进行访问了。</p>
<p>让我们看看如何使用它们：</p>
<pre><code class="language-js">import { capitalize, roundToDecimalPlace } from './main';

function displayTotal(name, total) {
	return `${capitalize(name)}, your total cost is: ${roundToDecimalPlace(total)}`;
}

displayTotal('kingsley', 20.4444444);
// "Kingsley, your total cost is: 20.44"

export { displayTotal };
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/displayTotal.js</div>
<p><code>displayTotal.js</code> 模块没有 <code>capitalize()</code> 和 <code>roundToDecimalPlace()</code>，但是想使用首字母大写的功能和舍入小数位的功能。该怎么引入呢？使用 <code>import</code>！</p>
<p>要实现它，我们使用 <code>import</code> 关键字，并在后面加上我们要想从模块中导入的函数名，在这个例子中也就是 <code>capitalize</code> 和 <code>roundToDecimalPlace</code>。</p>
<p>如果你只是想导入 <code>capitalize</code> 函数到程序呢？</p>
<p>很简单——只导入 <code>capitalize()</code> 即可，像这样：</p>
<pre><code class="language-js">import { capitalize } from './main';

function warn(name) {
	return `I am warning you, ${capitalize(name)}!`;
}

warn('kingsley');
// I am warning you, Kingsley!

export { warn };
</code></pre>
<blockquote>
<p>注意：在处理模块时，理解文件结构的工作原理是非常重要的。在上面的例子中，我们只是简单地从同级目录下的文件中导入，因此我们用了符号 <code>'./import'</code>。</p>
</blockquote>
<p>如果你想从另一个模块中导入所有公共函数，请使用星号 <code>*</code> 关键字:</p>
<pre><code class="language-js">import * as mainfunctions from './main';

function warn(name) {
return `I am warning you, ${mainfunctions.capitalize(name)}!`;
}
warn('kingsley');
// I am warning you, Kingsley!

export { warn };
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/warn.js</div>
<blockquote>
<p><strong>提示</strong>：如果要导入一个模块的全部函数，你应该使用星号，而不是把所有函数逐个显式地写出来。</p>
</blockquote>
<p>你可能注意到 <code>as</code> 关键字。我们用它将公共函数导入到新的对象中，在我们的例子中，这个对象是 <code>mainfunctions</code>。然后就可以在我们的程序中访问和调用这些需要用到的函数了。</p>
<p>到现在为止，我们只考虑了在文件末尾导出的例子。其实你可以在函数、变量或类的定义前注册 <code>export</code> 关键字，这同样可以导出它们。像这样：</p>
<pre><code class="language-js">function getPower(decimalPlaces) {
	return 10 ** decimalPlaces;
}

export function capitalize(word) {
	return word[0].toUpperCase() + word.slice(1);
}

export function roundToDecimalPlace(number, decimalPlaces = 2) {
	const round = getPower(decimalPlaces);
	return Math.round(number * round) / round;
}
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/anothermain.js</div>
<p>如果和第一个例子进行比较，你会注意到这种语法差异：</p>
<ul>
<li>在第一个例子中，<code>export</code> 关键字用于在脚本的末尾导出两个函数。而在上面的例子中，<code>export</code> 关键字在定义两个函数时被依附在前面。</li>
</ul>
<p>不过，它们的结果是一样的：<code>capitalize</code> 和 <code>roundToDecimalPlace</code> 都将被导出。</p>
<h2 id="">默认导出</h2>
<p>如果你要导出全部三个函数，但是想让其中一个作为默认值（也许是因为你最有可能使用那个函数），你只需使用 <code>default</code> 关键字。</p>
<p>默认关键字使得导入一个函数变得更加容易，让我们来考虑下面的例子：</p>
<pre><code class="language-js">export function getPower(decimalPlaces) {
	return 10 ** decimalPlaces;
	}

export default function capitalize(word) {
	return word[0].toUpperCase() + word.slice(1);
	}

export function roundToDecimalPlace(number, decimalPlaces = 2) {
	const round = getPower(decimalPlaces);
	return Math.round(number * round) / round;
	}
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/default.js</div>
<p>可以看到，我们把 <code>capitalize</code> 作为我们的默认函数。这实质上意味着我们赋予了它某种特权。</p>
<p>现在我们想将模块中的 <code>capitalize</code> 函数导入到另一个程序中。语法非常相似，只是导入的函数不再需要用花括号括起来：</p>
<pre><code class="language-js">import capitalize from './main';

function warn(name) {
	return `I am warning you, ${capitalize(name)}!`;
}

warn('kingsley');
// I am warning you, Kingsley!

export { warn };
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/warndefault.js</div>
<p>如果要将默认函数与任何其他函数一起导入，就将裸露的“默认”函数与花括号中的其他函数混合在一起导入：</p>
<pre><code class="language-js">import capitalize, { getPower } from './main';

function warn(name) {
	return `I am warning you, ${capitalize(name)}!`;
}

warn('kingsley');
// I am warning you, Kingsley!

export { warn };
</code></pre>
<div style="text-align:center; margin-bottom: 1.5em;">filepath/mixed.js</div>
<h2 id="">总结</h2>
<p>模块是独立且自包含的代码块。将较大的程序拆分为逻辑部分或依赖项，从而创建模块。</p>
<p>模块应该是独立的、专门的和可重用的。</p>
<p>使用 <code>import</code> 和 <code>export</code> 关键字来交换 JavaScript 模块间的功能。</p>
<p>使用 <code>default</code> 关键字来指定那些你要作为首选导入的函数、对象、变量或类。</p>
<p>至此，我们已经涵盖了 JavaScript 模块的基础知识。</p>
<p>希望你能从这篇文章中得到一些有价值的东西。我每周都会在我的<a href="https://ubahthebuilder.tech">个人博客</a>上写与编程相关的文章。</p>
<p>感谢你阅读本文。</p>
<blockquote>
<p><strong>附言</strong>：如果你正在学习 JavaScript，我创建了一本电子书，用手绘数字笔记的方式教授了 JavaScript 的 50 个主题。<a href="https://ubahthebuilder.gumroad.com/l/js-50">点这里查看</a>。</p>
</blockquote>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/javascript-modules-explained-with-examples/">JavaScript Modules – Explained with Examples</a>，作者：<a href="https://www.freecodecamp.org/news/author/ubahthebuilder/">Kingsley Ubah</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 开发者如何写好技术文章 ]]>
                </title>
                <description>
                    <![CDATA[ 软件开发人员致力于设计、编码、测试和交付我们每天使用的软件。不管开发人员的专长是什么，他们对很多事情都很了解——这也就意味着他们应该分享这些知识。 作为开发者，将我们所学到的知识通过发布文章和创建视频内容的形式分享出去，是一个很棒的方式。你可以拥有自己的博客，也可以为专栏撰稿。不管是哪种，你都可以遵循特定的流程来好好创作。 本文将介绍博客写作的基础知识，以帮助开发者撰写出色的文章。 TL;DR 以下高度总结了大部分要点。但是，我们将更详细地讨论一些现实生活中的经验以及学习如何写博客。请继续往下看。 > 高质量的内容写作是一个过程，它需要： 👉 计划 👉 研究内容 👉 审核 👉 发布时间 👉 最重要的，写作的意图 为产出高质量的内容花一些时间是值得的，不要着急。 — Tapas Adhikary (@tapasadhikary) 2021.04.03 [https://twitter.com/tapasadhikary/status/1378224989288062982?ref_src=twsrc%5Etfw] 了解你的目的 当我们开始做某事时， ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/technical-blogging-basics/</link>
                <guid isPermaLink="false">60e312080f76ab0660b140b8</guid>
                
                    <category>
                        <![CDATA[ 写作 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Mon, 05 Jul 2021 13:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/07/freeCodeCamp-Cover-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>软件开发人员致力于设计、编码、测试和交付我们每天使用的软件。不管开发人员的专长是什么，他们对很多事情都很了解——这也就意味着他们应该分享这些知识。</p>
<p>作为开发者，将我们所学到的知识通过发布文章和创建视频内容的形式分享出去，是一个很棒的方式。你可以拥有自己的博客，也可以为专栏撰稿。不管是哪种，你都可以遵循特定的流程来好好创作。</p>
<p>本文将介绍博客写作的基础知识，以帮助开发者撰写出色的文章。</p>
<h1 id="tldr">TL;DR</h1>
<p>以下高度总结了大部分要点。但是，我们将更详细地讨论一些现实生活中的经验以及学习如何写博客。请继续往下看。</p>
<blockquote>
<p>高质量的内容写作是一个过程，它需要：</p>
<p>👉 计划</p>
<p>👉 研究内容</p>
<p>👉 审核</p>
<p>👉 发布时间</p>
<p>👉 最重要的，写作的意图</p>
<p>为产出高质量的内容花一些时间是值得的，不要着急。</p>
<p>— Tapas Adhikary (@tapasadhikary) <a href="https://twitter.com/tapasadhikary/status/1378224989288062982?ref_src=twsrc%5Etfw">2021.04.03</a></p>
</blockquote>
<h1 id="">了解你的目的</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/intent.png" alt="intent" width="600" height="400" loading="lazy"></p>
<p>当我们开始做某事时，都需要一个目的，以及继续做它的动力。我们行动背后的意图和动机，因人而异。你需要找到你的意图或目的，能够解释为什么你要开始创建一个博客或分享内容。</p>
<p>在大多数情况下，简单的答案可能是<code>激情</code>。很有道理！它也可能是一种商业策略，或者你想教别人。也许你想持续学习——不管你是因为什么原因开始写作，都很棒。</p>
<p>作为一个开发者，我们一直在学习新东西。记住我们所学的每一部分知识几乎是不可能的。当我们记录那些教训和信息时，这些知识也就可以被重用了。</p>
<p>这就是为什么写一篇关于你最近学到的东西的文章，是一个很好的主意，这就是一个好的意图。</p>
<p>💡 <strong>小提示：</strong> 创建一个私人 GitHub 仓库，以及一个 markdown 文件。当你遇到新事物时，在这个文件中添加注释（如果需要的话还可以加代码）。</p>
<p>这个文件的内容将作为你今后文章的优秀资源。出于这个目的，我在维护一个名为 TIL_2021.md 的文件（记录了我 2021 年学到的东西）。</p>
<p>当决定写博客时，我打算通过分享知识来学习。如果你想深入学习一些东西，请开始教别人。写博客就是一个很棒的方式。</p>
<h1 id="">找到你的动机</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/motivation.png" alt="motivation" width="600" height="400" loading="lazy"></p>
<p>拥有动机可以创造奇迹，但是没有它就很难继续做下去。作为内容创作者，最大的动力无疑是听到读者的反馈。积极的反馈和建设性的批评总是可以帮助你改进创造的内容。</p>
<p>但是有个问题，刚开始，很少有人会给你反馈。如果你是一个个人博主，失望的概率会很高。因此，拥有自我激励，对维持和继续你的工作是很有帮助的。</p>
<p>记住——不要放弃，保持动力。作为开发人员，你有很多东西要学习、分享和撰写。</p>
<p>💡 <strong>小提示：</strong> 如果你想以开发者的身份开始写博客，开发者社区有助于你保持联系、保持动力。有很多极其精彩的社区，如 <a href="https://hashnode.com/@atapas/joinme">Hashnode</a>，<a href="https://dev.to/">Dev.to</a>，<a href="https://community.codenewbie.org/">Codenewbie</a>，<a href="https://hackernoon.com/">Hackernoon</a>，<a href="https://forum.freecodecamp.org/">freeCodeCamp</a>，<a href="https://girlswhocode.com/">GirlsWhoCode</a>等，还有很多。</p>
<h1 id="">做好你的研究</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/research.png" alt="research" width="600" height="400" loading="lazy"></p>
<p>研究是关键。内容决定一切。</p>
<p>对博客来说，内容为王。作为开发者，我们有各种各样的想法、解决问题的步骤，以及想要掌握的新知识。但是最重要的是能把它们转化为优质的内容。通常，花时间把你的话题彻底研究明白，是很有必要的。</p>
<p>现在我来举一个关于内容研究的例子。假设你用<code>链表</code>解决了一个问题，而且是你第一次使用，你非常激动，想把学到的分享出来，以下是需要考虑的点：</p>
<ul>
<li>你需要大致理解<code>链表</code>以及已经被解决的问题的上下文</li>
<li>你需要理解<code>链表</code>的优缺点</li>
<li>你需要创建几个例子来演示如何用好它</li>
<li>你需要确保清楚地解释了你解决问题的方法，这样读者才能在他们自己的案例中使用</li>
</ul>
<p>💡 <strong>小提示：</strong> 一旦明白了你需要知道什么，你就可以从任何完备的资源中进行学习。你可以在 <code>Google</code>，<code>Quora</code>，<code>Reddit</code> 等上面进行搜索。<code>Stackoverflow</code> 同样也是一个优秀的平台，你可以用它来检索你的话题。</p>
<p>确保在取得进步时记下所学的内容，这些笔记最终将转化成你要撰写和发布的文章。</p>
<h1 id="">规划你的内容结构</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/plan.png" alt="plan" width="600" height="400" loading="lazy"></p>
<p>一旦完成了内容研究，下一步就是规划文章的结构。如果你的文章结构不完整而且混乱，那么再好的内容也会被读者忽略。</p>
<p>以下是一些小提示，帮助你用一种可读的方式来构建文章内容：</p>
<ul>
<li><strong>文章标题：</strong> 一个引人注目的标题可以吸引很多读者来访问你的文章。不管怎样，人们很难忽视阅读文章的标题。保持标题悦耳易记，能提升文章的流量。</li>
<li><strong>封面图片：</strong> 一张相关的封面图片使得文章更加具有吸引力。当你在社交媒体上分享文章时，一张创意十足的封面将吸引你的读者。</li>
<li><strong>简介：</strong> 这部分高度概括了你的文章内容。它可以是第一段，也可以是一个 <a href="https://en.wikipedia.org/wiki/Wikipedia:Too_long;_didn%27t_read">Tl;DR</a>，用以解释你打算在文章中介绍的内容。</li>
<li><strong>段落标题和子标题：</strong> 你应该将内容分解成几个关联的子话题。为了达到这个目的，创建几个部分，并提供与之相关的标题和子标题。例如，在这篇文章中，我创建了多个部分，给每个部分配上了标题，如<code>了解你的目的</code>，<code>找到你的动机</code>等。</li>
<li><strong>图形：</strong> “一张图片胜过千言万语”，因此请考虑用一些图表、图片等来支持你的内容。</li>
<li><strong>总结：</strong> 最后的总结部分，可帮助你的读者回顾到目前为止他们从文章中学到的东西。同样，对于有些读者，再次过来收集内容时，只要通过快速阅览总结部分就可以了，这很有帮助。</li>
<li><strong>重要的链接：</strong> 你可能希望以一个参考链接的列表来结束文章，以供读者进一步阅读。你也可以在这一部分列出你以前发布的文章的链接。</li>
</ul>
<p>💡 小提示：尝试在你的文章中使用一个统一的内容结构，这样你的读者会习惯它，然后会发现很容易理解。</p>
<h1 id="">写作工具</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/Tools.png" alt="Tools" width="600" height="400" loading="lazy"></p>
<p>创造优质内容很花时间。你可以使用一些免费可用的工具，使自己成为一个多产和高效的内容创造者。这里有一些你可能觉得有用的工具，</p>
<p>⚒️ <a href="https://www.notion.so/">Notion</a>：这个工具可以帮助你以高效的方式管理个人和专业的工作代办事项。任何时候产生一篇文章的想法或者你解决了一个有趣的问题，在这个工具中创建一项任务。你可以轻松排序，安排时间，分配任务。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-29.png" alt="image-29" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="http://grammarly.com">Grammarly</a>：如果你跟我一样，是一个非英语母语者，有时可能会对语言的语法规则不够熟悉。</p>
<p>在这种情况下，像 <code>Grammarly</code> 这样的工具在各个方面扮演拯救者。它检查语法和拼写错误，建议对复杂句子重新措辞，纠正被动语态为主动语态，等等。你可以先使用试用版本，之后根据你的使用情况来升级到付费版。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-30.png" alt="image-30" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://hemingwayapp.com/">Hemingway Editor</a>：这是另一个优秀的工具，用于协助你进行英语写作。如果你愿意，可以和 <code>Grammarly</code> 结合使用。副词、主动/被动语态，以及复杂的单词和短语，这些如果使用不当，它都能指出，这一点我很喜欢。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-31.png" alt="image-31" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://www.canva.com/">Canva</a>：Canva 是进行设计、艺术和释放创造力的工具。在没有任何 <code>Canva</code> 经验的情况下，你依然可以用它来创建封面图像、文章图形、动画 gif 等。它慷慨的免费计划足以让你开始使用。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-32.png" alt="image-32" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://pixteller.com/">Pixteller</a>：这是用于创建封面图像、图形等的另一个工具。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-33.png" alt="image-33" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://getsharex.com/downloads/">ShareX</a>：它是一款超酷的生产力工具，用于截屏、制作动画图片、文件共享等。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-34.png" alt="image-34" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://obsproject.com/download">OBS Studio</a>：这是一个免费的开源视频录制和流媒体工具。你可能会疑惑，为什么我写博客需要它？</p>
<p>有时，你可能想要创建一段视频，上传到 YouTube 或 Vimeo，并从你的文章中链接到该视频。你可以使用 OBS Studio 创建优质视频，它有很多自定义选项。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-35.png" alt="image-35" width="600" height="400" loading="lazy"></p>
<p>⚒️ <a href="https://serpsim.com/">SERP 片段生成器</a>：SERP（搜索引擎结果页）是我们在 Google 或 Bing 等搜索引擎输入查询后看到的页面。SERP 片段生成器可帮助你在发布文章之前确定合适的标题和元描述。</p>
<p>请参阅下图以找出限制范围内的标题和描述，以正确显示搜索结果。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/serpsim_snapshot-1.png" alt="serpsim_snapshot-1" width="600" height="400" loading="lazy"></p>
<h1 id="">进行大量审核</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/reading.png" alt="reading" width="600" height="400" loading="lazy"></p>
<p>你写了一些东西，在发布或分享之前，需要检查错误并审核你的文章。检查，确保你的内容已经准备好进行发布。通常，你应该检查：</p>
<ul>
<li>拼写错误</li>
<li>语法错误</li>
<li>格式问题</li>
<li>标点符号</li>
<li>准确性</li>
<li>语言一致性</li>
</ul>
<p>在校对和审核方面，有一句名言可以激发灵感：</p>
<blockquote>
<p>“我发现修改你自己的作品的最好方法是假装它是别人写的，然后把它撕掉。” - Don Roff</p>
</blockquote>
<h1 id="">发布你的文章</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/publish.png" alt="publish" width="600" height="400" loading="lazy"></p>
<p>如果在审核之后，你对文章很满意，接下来一步自然就是发布它。你可能希望将其安排在一周中的特定日期进行发布，或者你想立即发布——这取决于你自己。</p>
<p>一般而言，最好是在你准备好文章时就发布。同样，你不应该赶着最后期限去匆忙发布。</p>
<p>💡 <strong>小提示：</strong> 发布你的文章必须是整个计划的一部分。如果你需要在一个特定日期发布文章，那就要你逆向规划相应的内容。千万不要为了匆忙发布，而妥协文章内容的质量。</p>
<h1 id="">在社交媒体分享你的文章</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/socialize.png" alt="socialize" width="600" height="400" loading="lazy"></p>
<p>社交媒体是一个极其强大的工具。作为博主，你应该积极利用它。</p>
<p>如果你希望文章尽可能多地吸引潜在读者，发表文章可能还不够。因此，在各种社交媒体平台上分享你的文章是个好主意。</p>
<p>你应该分享文章的链接到以下几个平台：</p>
<ul>
<li><a href="https://twitter.com/">推特</a></li>
<li><a href="https://www.linkedin.com/feed/">领英</a></li>
<li><a href="https://www.reddit.com/">红迪网</a></li>
<li><a href="https://news.ycombinator.com/">黑客新闻</a></li>
<li><a href="https://facebook.com/">脸书</a></li>
</ul>
<p>还有一些平台，单独分享链接并不会有什么效果。你可以创建适合主题的封面照片或图表，然后把它和链接上传到像 <a href="https://www.instagram.com/">Instagram</a> 和 <a href="https://in.pinterest.com/">Pinterest</a> 这样的地方，记得使用正确的主题标签。</p>
<p>💡 小提示：分享博客链接时，请确保你遵守了每个社交媒体平台各自的规则。如果不这么做，你的账号可能会被标记或者被禁掉。</p>
<p>还有另一种令人兴奋的方式来分享你的内容，那就是交叉发布它。如果允许的话，你可以在其他博客平台上重新发布你的文章。例如，一篇发布在 <code>Hashnode</code> 平台上的文章，可以重新发布在 <code>Dev.to</code> 平台上，反之亦然。</p>
<p>💡 <strong>小提示：</strong> 交叉发布文章时，你可以在原始文章的链接上设置 <code>Canonical URL</code>。这种方式告诉像谷歌这样的搜索引擎，哪个是原始的副本，同时消除重复的内容。</p>
<h1 id="">优秀的博客平台</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/paltform.png" alt="paltform" width="600" height="400" loading="lazy"></p>
<p>好了，现在我们已经知道了如何写一篇文章并进行分享，以便他人可以阅读。接下来我们来了解一些你可以开始入门的博客平台。</p>
<p>以下是一些平台，你可以开始在上面写博客，进而成为社区的一份子。</p>
<ul>
<li><a href="https://hashnode.com/@atapas/joinme">Hashnode</a></li>
<li><a href="https://dev.to/">DEV Community</a></li>
<li><a href="https://chinese.freecodecamp.org/news/">freeCodeCamp News</a></li>
<li><a href="https://hackernoon.com/">HACKERnoon</a></li>
<li><a href="https://daily.dev/blog">daily.dev</a></li>
<li><a href="https://www.codenewbie.org/">Codenewbie Community</a></li>
<li><a href="https://www.educative.io/edpresso">Educative Edpresso Shorts</a></li>
<li><a href="https://cofounderstown.com/">CoFoundersTown</a></li>
</ul>
<p>很多专栏和组织会雇佣并支付报酬给内容创作者。作为一个开发者博主，这可能会带来很多自由职业的机会，你会因为分享你的内容而获得报酬。你还可以为开源文档和其他项目做出贡献。</p>
<h1 id="">总结</h1>
<p>总结来说，</p>
<ul>
<li>作为一个开发者，写博客作为一项业余活动，是可以管理的，并不会影响你的工作输出。</li>
<li>你已经解决的问题，以及你在 Google、Quora 和 Stackoverflow 上的搜索，很可能成为你的写作灵感来源。</li>
<li>在开始写文章之前，确定你的目标。背后的意图可以是琐碎的，也可以是很重要的——无论哪种都可以。</li>
<li>保持动力。</li>
<li>使用合适的工具，使你成为一个多产的作者。</li>
<li>规划内容结构，审核你的文章，然后发布它们。</li>
<li>使用社交媒体工具来分享你的文章。</li>
<li>有一些很棒的博客平台，尝试一下，成为开发者社区的一份子。</li>
<li>保持学习，保持写作，以及保持分享。</li>
</ul>
<h1 id="">在我们结束之前……</h1>
<p>我希望这篇指南可以帮助你创作更多好文章。</p>
<p>让我们保持联系。你在可以在 <a href="https://twitter.com/tapasadhikary">推特 (@tapasadhikary)</a> 上面找到我，请随时关注。</p>
<p>你也许还会喜欢以下文章：</p>
<ul>
<li><a href="https://blog.greenroots.info/how-to-find-blog-content-ideas-effortlessly-ckghrjv5200o7rhs1ewn40102">如何毫不费力地找到博客内容创意？</a></li>
<li><a href="https://blog.greenroots.info/where-to-begin-some-practical-tips-from-a-beginner-ckcu5llil00ncw8s11dr1fh2w">从哪里开始？给新手的一些实用技巧</a></li>
<li><a href="https://blog.greenroots.info/why-do-you-need-to-do-side-projects-as-a-developer-ckhn5m5km05teajs1fvjd7u5f">作为开发者，你为什么需要做业余项目？</a></li>
<li><a href="https://blog.greenroots.info/16-side-project-github-repositories-you-may-find-useful-ckk50hic406quhls1dui2d6sd">你可能觉得有用的16个业余项目的 GitHub 仓库</a></li>
<li><a href="https://chinese.freecodecamp.org/news/learn-something-new-every-day-as-a-software-developer/">作为一个软件开发者，如何每天学点新东西</a></li>
</ul>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/technical-blogging-basics/">Technical Blogging Basics – How to Write Articles as a Developer</a>，作者：<a href="https://www.freecodecamp.org/news/author/tapas/">TAPAS ADHIKARY</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ TCP vs UDP——哪个协议更快？ ]]>
                </title>
                <description>
                    <![CDATA[ 什么是 TCP？ TCP  是 Transmission Control Protocol  的首字母缩写词，它是一种传输层协议，允许数据包从一个位置发送到另一个位置。 TCP 是面向连接的协议，也就是说它在网络计算机单元之间的任何通信之前建立连接。由于我们把这个协议与 IP 协议结合使用，我们称其为 TCP/IP。 TCP 是怎么工作的? TCP 的主要任务是从应用层收集数据。它将数据拆分成多个数据包，为每个数据包分配一个编号，然后将这些数据包发送到它们的目的地。 同样，在将数据包发送到应用层之前，它会重新组合数据包。鉴于 TCP 是面向连接的协议，这个连接将一直保持，直到发送方和接收方完成数据交换。 它是一种可靠的协议。因为，接收方总是会给发送方提供一条关于数据包的确认消息，要么肯定要么否定，因此，发送方总是能知道数据包是否到达它的目的地，还是说需要被重新发送。 它保证了数据能到达其目的地，而且到达的顺序与发送时相同。它有一套内置的错误检查和恢复体系，负责提供端到端通信。TCP 还提供对流量控制和服务质量的访问。 TCP 支持全双工服务器，既可以当接收者，也可以当发送者 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/tcp-vs-udp-which-is-faster/</link>
                <guid isPermaLink="false">60dbf2ad240b4e0653a3e18e</guid>
                
                    <category>
                        <![CDATA[ 计算机网络 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sean Bei ]]>
                </dc:creator>
                <pubDate>Wed, 30 Jun 2021 04:30:05 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/06/TCP-VS-UDP.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="tcp">什么是 TCP？</h2>
<p><strong>TCP</strong> 是 <strong>Transmission Control Protocol</strong> 的首字母缩写词，它是一种传输层协议，<strong>允许数据包</strong>从一个位置发送到另一个位置。</p>
<p>TCP 是面向连接的协议，也就是说它在网络计算机单元之间的任何通信之前建立连接。由于我们把这个协议与 IP 协议结合使用，我们称其为 <strong>TCP/IP</strong>。</p>
<h3 id="tcp">TCP 是怎么工作的?</h3>
<p>TCP 的主要任务是从应用层收集数据。它将数据拆分成多个数据包，为每个数据包分配一个编号，然后将这些数据包发送到它们的目的地。</p>
<p>同样，在将数据包发送到应用层之前，它会重新组合数据包。鉴于 TCP 是面向连接的协议，这个连接将一直保持，直到发送方和接收方完成数据交换。</p>
<p>它是一种可靠的协议。因为，接收方总是会给发送方提供一条关于数据包的确认消息，要么肯定要么否定，因此，发送方总是能知道数据包是否到达它的目的地，还是说需要被重新发送。</p>
<p>它保证了数据能到达其目的地，而且到达的顺序与发送时相同。它有一套内置的错误检查和恢复体系，负责提供端到端通信。TCP 还提供对流量控制和服务质量的访问。</p>
<p>TCP 支持<strong>全双工服务器</strong>，既可以当接收者，也可以当发送者。它以点对点的客户端/服务器方式运行。</p>
<h2 id="udp">什么是 UDP？</h2>
<p><strong>UDP</strong> 是 <strong>User Datagram Protocol</strong> 的首字母缩写词。用户数据报协议（UDP）是 TCP/IP 协议套件的最基本的传输层通信协议。它使用最低限度的通信机制。</p>
<h3 id="udp">UDP 是怎么工作的？</h3>
<p>尽管 UDP 被认为是一种不可靠的传输协议，但它通过使用 IP 服务来完成其工作，提供了一种尽力而为的传递方法。</p>
<p>在 UDP 中，接收方不生成数据包的确认，发送方也不等待数据包的确认。正是这个不足，使得该协议虽不可靠但是易于处理。</p>
<p>如果确认是否接收到数据这点并不那么重要，这种情况下，我们使用 UDP。它很适用于单向数据流的场景，最适合基于查询的通信。</p>
<p>UDP 不保证数据包的有序传递。它是无状态的，不提供任何拥塞控制机制。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-2021-05-31-at-10.54.01-AM.png" alt="TCP 与 UDP" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>TCP 与 UDP</figcaption>
</figure>
<h2 id="tcpudp">TCP 与 UDP 的区别</h2>
<p>UDP 是一种无连接协议，而 TCP 是一种面向连接的协议。TCP 比 UDP 要慢，这是两种协议的主要区别之一。</p>
<p>总的来说，UDP 是一种更快、更简单、更高效的协议。但是只有 TCP 允许对丢失的数据包进行重新传输。</p>
<p>TCP 和 UDP 的另一个区别是 TCP 可以确保数据从用户到服务器的有序传输（反之亦然）。UDP 不是为端到端通信而设计的，并不会检查接收方的准备情况，因此它需要相对更少的开销并占用更少的空间。</p>
<h3 id="tcpudp">TCP 与 UDP 的总结</h3>
<h4 id="">连接</h4>
<p>TCP 要求在发送方和接收方开始通信之前建立一个良好的连接，它是一个面向连接的协议。</p>
<p>UDP 是一种无连接协议。</p>
<h4 id="">保持数据传输的顺序</h4>
<p>在 TCP 中，由于事先建立了一个良好的连接，接收方以有序的方式接收数据包。</p>
<p>而在 UDP 中，发送方与接收方之间并没有建立良好的连接，接收方将以无序的方式接收数据包。</p>
<h4 id="">可靠性</h4>
<p>每当通过 TCP 接收到数据包时，接收方都会向发送方发送一条确认。万一失败，它会请求重新传输。</p>
<p>而使用 UDP，在这种情况下不会发送确认，它依赖于高层协议来确保可靠性。</p>
<h4 id="">错误检查</h4>
<p>TCP 中有广泛的错误检查规则，而 UDP 中只有基本的错误检查技术，例如校验和。</p>
<h4 id="">传输方法</h4>
<p>在 TCP 中，数据以字节流的形式读取，消息被发送到段边界。</p>
<p>而在 UDP 中，已定义限制的单个 UDP 数据包被发送，在到达接收方时验证其完整性。</p>
<h4 id="">广播</h4>
<p>TCP 不支持广播。当你使用它时，发送方和接收方必须先建立一条连接，在传输结束后又必须终止这条连接。</p>
<p>UDP 支持广播。</p>
<h3 id="tcpudp">TCP 与 UDP 的用例</h3>
<p>TCP 被用于 HTTPS（安全超文本传输协议）、HTTP（超文本传输协议）、SMTP（简单邮件传输协议）、FTP（文件传输协议）等等。</p>
<p>UDP 用于视频流、视频电话、IP 语音服务（互联网呼叫）、DNS（域名系统）等。</p>
<h2 id="tcpudp">TCP 对比 UDP - 哪个更快?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-2021-05-31-at-10.55.58-AM.png" alt="Screenshot-2021-05-31-at-10.55.58-AM" width="600" height="400" loading="lazy"></p>
<p>通常来说，UDP 比 TCP 更快，原因如下：</p>
<h3 id="tcpudp">TCP 与 UDP 报头大小的差异</h3>
<p>让我们来分析看看 TCP 数据包和 UDP 数据包各自的报头。</p>
<p>TCP 报头的长度必须至少为 20 字节且不超过 60 字节。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-2021-05-31-at-10.56.59-AM.png" alt="Screenshot-2021-05-31-at-10.56.59-AM" width="600" height="400" loading="lazy"></p>
<h4 id="tcp">TCP 的报头包括：</h4>
<ol>
<li><strong>源端口</strong> - 表示发送设备的源端口。占 16 位。</li>
<li><strong>目的端口</strong> - 表示接收设备上的目的端口。占 16 位。</li>
<li><strong>序号</strong> - 表示在一个会话中数据段的序号。占 32 位。</li>
<li><strong>确认号</strong> - 该编号包括下一个预期的数据字节的序号，并在 ACK 标志被设置时，用作对先前接收到的数据的确认。占 32 位。</li>
<li><strong>数据偏移</strong> - 该字段表示整个 TCP 报头的大小（32 位字）以及当前数据包在整个 TCP 段上的数据偏移量。占 4 位。</li>
<li><strong>保留</strong> -  供将来使用的位，默认情况下设置为 0。占 3 位。</li>
<li><strong>标志</strong> - 为各种标志保留了 1 位，这些标志有助于 TCP 检查各种活动，例如确认。</li>
<li><strong>校验和</strong> - 该字段包含校验和。</li>
<li><strong>紧急指针</strong> - 如果 URG 标志设置为 1，则指定数据字节。</li>
<li><strong>选项</strong> - 指定了在常规报头中不存在的其他选项。</li>
</ol>
<p>现在让我们来分析一个 UDP 报头。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-2021-05-31-at-10.57.27-AM.png" alt="Screenshot-2021-05-31-at-10.57.27-AM" width="600" height="400" loading="lazy"></p>
<h4 id="udp">UDP 的报头包括：</h4>
<ol>
<li><strong>源端口</strong> - 表示发送设备的源端口。占 16 位。</li>
<li><strong>目的端口</strong> - 表示接收设备上的目的端口。占 16 位。</li>
<li><strong>长度</strong> - 指定 UDP 数据包的整体长度。它是一个 16 位的字段，最小值为 8 字节，等于 UDP 报头本身的大小。</li>
<li><strong>校验和</strong> - 发送方在发送之前创建的校验和存储在此字段中。该字段在 IPv4 中是可选的，因此如果它不包含任何值，则设置为 0，并且其所有位都设置为 0。</li>
</ol>
<p>我们可以清楚地看到 TCP 报头与 UDP 报头的开销差异。由于 TCP 报头比 UDP 报头大很多, 它需要更多的时间来处理，这使得了 UDP 比 TCP 更快。</p>
<h3 id="tcpudp">TCP 与 UDP 中的确认</h3>
<p>在 TCP 中，接收方在接收到的数据段上向发送方发送确认。这确保了数据包已传送到接收方。</p>
<p>如果没有收到确认，发送方会尝试重新传输。这个处理过程使得 TCP 比 UDP 慢得多。别忘了，UDP 不发送任何确认。</p>
<h3 id="">规则的例外</h3>
<p>在某些情况下，TCP 被证实比 UDP 要快。例如，在一个实验中，在一个最大传输单元为 1500 字节的以太网连接上，发送 300 字节的数据包，TCP 比 UDP 大约快 50%。</p>
<p>这是因为 TCP 会尝试缓存数据，填充到整个网段，从而最大化利用了带宽。而另一边，UDP 立即沿线路发送数据包，这些小数据包很多，堵塞了网络。</p>
<h2 id="">结论</h2>
<p>TCP 和 UDP 都有各自的用途。如果主要关注数据接收的可靠性和顺序，你会更希望使用 TCP。</p>
<p>另一方面，如果主要关注的是速度，而且某些数据包的受损或丢失并不那么重要，请选择 UDP。</p>
<p>所以可以看到，你不得不在可靠性和速度这两个之间进行妥协。如果提升其中一个，由于前面的限制，另一个会下降。</p>
<p>例如，在 YouTube 视频中，您可能已经注意到，有多种选项用于设置视频的质量。</p>
<p>当提高质量时，视频会占用更多带宽。这是因为画质较低时，即使某些数据包丢失，我们也会忽略它们。但是如果想要高质量的视频，我们便不能丢失数据包。</p>
<p>感谢阅读！希望你对 TCP 与 UDP 有了一个更好的了解。</p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/tcp-vs-udp-which-is-faster/">TCP vs UDP – Which Protocol is Faster?</a>，作者：<a href="https://www.freecodecamp.org/news/author/prashanth/">Prashanth</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
