Python 数据分析第三版(二)
原文:
annas-archive.org/md5/74a7b24994c40ad3a90c290c07b529df译者:飞龙
第四章:线性代数
线性代数和统计学是任何数据分析活动的基础。统计学帮助我们获得初步的描述性理解,并从数据中做出推断。在上一章中,我们已经理解了数据分析的描述性和推断性统计度量。另一方面,线性代数是数据专业人员的核心基础之一。线性代数对于处理向量和矩阵非常有用。大多数数据以向量或矩阵的形式存在。深入理解线性代数有助于数据分析师和数据科学家理解机器学习和深度学习算法的工作流程,使他们能够根据业务需求灵活地设计和修改算法。例如,如果你想使用主成分分析(PCA),你必须了解特征值和特征向量的基础知识;或者如果你想开发一个推荐系统,你必须了解奇异值分解(SVD)。扎实的数学和统计学背景将有助于更顺利地过渡到数据分析领域。
本章主要关注线性代数的核心概念,如多项式、行列式、矩阵逆;解线性方程;特征值和特征向量;SVD;随机数;二项分布和正态分布;正态性检验;以及掩码数组。我们还可以使用 Python 的 NumPy 和 SciPy 包来执行这些操作。NumPy 和 SciPy 都提供了用于线性代数运算的 linalg 包。
本章将涵盖以下主题:
-
使用 NumPy 拟合多项式
-
行列式
-
查找矩阵的秩
-
使用 NumPy 计算矩阵逆
-
使用 NumPy 解线性方程
-
使用 SVD 分解矩阵
-
使用 NumPy 计算特征向量和特征值
-
生成随机数
-
二项分布
-
正态分布
-
使用 SciPy 检验数据的正态性
-
使用
numpy.ma子包创建掩码数组
技术要求
本章的以下技术信息可供参考:
-
你可以在以下 GitHub 链接找到代码和数据集:
github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter04。 -
所有的代码块都可以在
ch4.ipynb中找到。 -
本章将使用 NumPy、SciPy、Matplotlib 和 Seaborn Python 库。
使用 NumPy 拟合多项式
多项式是具有非负策略的数学表达式。多项式函数的例子包括线性函数、二次函数、立方函数和四次函数。NumPy 提供了 polyfit() 函数来通过最小二乘法生成多项式。该函数接受 x 坐标、y 坐标和阶数作为参数,并返回一个多项式系数列表。
NumPy 还提供了 polyval() 函数来在给定的值上评估多项式。该函数接受多项式的系数和点的数组,并返回多项式的结果值。另一个函数是 linspace(),它生成一系列等间隔的值。它接受起始值、终止值和起止范围之间的值的个数,并返回闭区间内等间隔的值。
让我们看一个例子,使用 NumPy 生成并评估多项式,如下所示:
# Import required libraries NumPy, polynomial and matplotlib
import numpy as np
import matplotlib.pyplot as plt
# Generate two random vectors
v1=np.random.rand(10)
v2=np.random.rand(10)
# Creates a sequence of equally separated values
sequence = np.linspace(v1.min(),v1.max(), num=len(v1)*10)
# Fit the data to polynomial fit data with 4 degrees of the polynomial
coefs = np.polyfit(v1, v2, 3)
# Evaluate polynomial on given sequence
polynomial_sequence = np.polyval(coefs,sequence)
# plot the polynomial curve
plt.plot(sequence, polynomial_sequence)
# Show plot
plt.show()
这将产生以下输出:
在上面的截图中显示的图形将在每次迭代中发生变化,使用的是之前编写的程序。这种波动的原因是向量的随机值生成。
让我们进入下一个话题:行列式。我们将使用 numpy.linalg 子包执行大部分的线性代数运算。NumPy 提供了 linalg 子包来进行线性代数运算。我们可以利用线性代数进行矩阵操作,如求逆、秩、特征值、特征向量、求解线性方程组以及执行线性回归。
行列式
行列式是线性代数中最基本的概念。它是一个标量值,由方阵计算得出。行列式是一个基础运算,它帮助我们进行逆矩阵的计算以及解线性方程组。行列式仅适用于方阵,方阵的行数和列数相等。numpy.linalg 子包提供了 det() 函数,用于计算给定输入矩阵的行列式。让我们在下面的代码块中计算行列式:
# Import numpy
import numpy as np
# Create matrix using NumPy
mat=np.mat([[2,4],[5,7]])
print("Matrix:\n",mat)
# Calculate determinant
print("Determinant:",np.linalg.det(mat))
这将产生以下输出:
Matrix:
[[2 4]
[5 7]]
Determinant: -5.999999999999998
在上面的代码块中,我们使用 np.linalg.det() 方法计算了给定矩阵的行列式。现在让我们理解另一个线性代数的概念——秩,并使用 numpy.linalg 子包计算它。
寻找矩阵的秩
秩是解决线性方程组时一个非常重要的概念。矩阵的秩表示矩阵中保留的信息量。秩越低表示信息越少,秩越高表示信息量越大。秩可以定义为矩阵中独立行或列的数量。numpy.linalg 子包提供了 matrix_rank() 函数。matrix_rank() 函数接受矩阵作为输入,并返回计算出的矩阵秩。让我们通过下面的代码块来看一个 matrix_rank() 函数的例子:
# import required libraries
import numpy as np
from numpy.linalg import matrix_rank
# Create a matrix
mat=np.array([[5, 3, 1],[5, 3, 1],[1, 0, 5]])
# Compute rank of matrix
print("Matrix: \n", mat)
print("Rank:",matrix_rank(mat))
这将产生以下输出:
Matrix:
[[5 3 1]
[5 3 1]
[1 0 5]]
Rank: 2
在上面的代码块中,numpy.linalg 的 matrix_rank() 函数用于生成矩阵的秩。现在让我们来看线性代数中的另一个重要概念:矩阵逆。
使用 NumPy 计算矩阵的逆
矩阵是由行和列组织的数字、表达式和符号的矩形序列。一个方阵与其逆矩阵相乘的结果是单位矩阵 I。我们可以用以下方程表示:
AA^(-1) = I
numpy.linalg子包提供了一个用于求逆的函数:inv()函数。让我们使用numpy.linalg子包来求矩阵的逆。首先,我们使用mat()函数创建一个矩阵,然后使用inv()函数求矩阵的逆,如下面的代码块所示:
# Import numpy
import numpy as np
# Create matrix using NumPy
mat=np.mat([[2,4],[5,7]])
print("Input Matrix:\n",mat)
# Find matrix inverse
inverse = np.linalg.inv(mat)
print("Inverse:\n",inverse)
这将产生以下输出:
Input Matrix:
[[2 4]
[5 7]]
Inverse:
[[-1.16666667 0.66666667]
[ 0.83333333 -0.33333333]]
在前面的代码块中,我们使用numpy.linalg子包的inv()函数计算了矩阵的逆。
如果给定的输入矩阵不是方阵或是奇异矩阵,它将引发LinAlgError错误。如果你愿意,可以手动测试inv()函数。我将把这个任务留给你自己完成。
使用 NumPy 求解线性方程
矩阵操作可以将一个向量转换为另一个向量。这些操作将帮助我们找到线性方程的解。NumPy 提供了solve()函数来求解形式为 Ax = B 的线性方程,其中 A 是 n*n 矩阵,B 是一个一维数组,x 是未知的一维向量。我们还将使用dot()函数来计算两个浮点数数组的点积。
让我们来解一个线性方程的例子,如下所示:
- 为给定方程创建矩阵 A 和数组 B,如下所示:
x1 + x2 = 200
3x1 + 2x2 = 450
这在下面的代码块中进行了说明
# Create matrix A and Vector B using NumPy
A=np.mat([[1,1],[3,2]])
print("Matrix A:\n",A)
B = np.array([200,450])
print("Vector B:", B)
这将产生以下输出:
Matrix A:
[[1 1]
[3 2]]
Vector B: [200 450]
在前面的代码块中,我们创建了一个 2*2 矩阵和一个向量。
- 使用
solve()函数求解线性方程,如下所示:
# Solve linear equations
solution = np.linalg.solve(A, B)
print("Solution vector x:", solution)
这将产生以下输出:
Solution vector x: [ 50\. 150.]
在前面的代码块中,我们使用numpy.linalg子包的solve()函数求解了一个线性方程。
- 使用
dot()函数检查解,如下所示:
# Check the solution
print("Result:",np.dot(A,solution))
这将产生以下输出:
Result: [[200\. 450.]]
在前面的代码块中,我们使用dot()函数评估了解决方案。你可以看到,A 和解的点积等于 B。到目前为止,我们已经看到了行列式、秩、逆矩阵以及如何解线性方程。接下来,我们将讨论用于矩阵分解的 SVD。
使用 SVD 分解矩阵
矩阵分解是将一个矩阵拆分为多个部分的过程,也称为矩阵因式分解。常见的矩阵分解方法包括下三角-上三角(LU)分解、QR分解(其中Q是正交矩阵,R是上三角矩阵)、Cholesky 分解和 SVD。
特征分析将矩阵分解为向量和值。SVD 将矩阵分解为以下几部分:奇异向量和奇异值。SVD 在信号处理、计算机视觉、自然语言处理(NLP)和机器学习中被广泛应用——例如在主题建模和推荐系统中,SVD 在现实商业解决方案中被广泛接受和实现。请看以下内容:
这里,A是一个m x n的左奇异矩阵,Σ是一个n x n的对角矩阵,V是一个m x n的右奇异矩阵,V^T是 V 的转置矩阵。numpy.linalg子包提供了svd()函数来分解矩阵。我们来看一个 SVD 的例子,如下所示:
# import required libraries
import numpy as np
from scipy.linalg import svd
# Create a matrix
mat=np.array([[5, 3, 1],[5, 3, 0],[1, 0, 5]])
# Perform matrix decomposition using SVD
U, Sigma, V_transpose = svd(mat)
print("Left Singular Matrix:",U)
print("Diagonal Matrix: ", Sigma)
print("Right Singular Matrix:", V_transpose)
这将产生以下输出:
Left Singular Matrix: [[-0.70097269 -0.06420281 -0.7102924 ]
[-0.6748668 -0.26235919 0.68972636]
[-0.23063411 0.9628321 0.14057828]]
Diagonal Matrix: [8.42757145 4.89599358 0.07270729]
Right Singular Matrix: [[-0.84363943 -0.48976369 -0.2200092]
[-0.13684207 -0.20009952 0.97017237]
[ 0.51917893 -0.84858218 -0.10179157]]
在前面的代码块中,我们使用scipy.linalg子包的svd()函数将给定的矩阵分解成三个部分:左奇异矩阵、对角矩阵和右奇异矩阵。
使用 NumPy 计算特征向量和特征值
特征向量和特征值是理解线性映射和变换所需的工具。特征值是方程 Ax = λx 的解,其中 A 是方阵,x 是特征向量,λ是特征值。numpy.linalg子包提供了两个函数,eig()和eigvals()。eig()函数返回特征值和特征向量的元组,而eigvals()返回特征值。
特征向量和特征值是线性代数的核心基础。特征向量和特征值被广泛应用于 SVD、谱聚类和 PCA。
让我们计算一个矩阵的特征向量和特征值,如下所示:
- 使用 NumPy 的
mat()函数创建矩阵,如下所示:
# Import numpy
import numpy as np
# Create matrix using NumPy
mat=np.mat([[2,4],[5,7]])
print("Matrix:\n",mat)
这将产生以下输出:
Matrix: [[2 4]
[5 7]]
- 使用
eig()函数计算特征向量和特征值,如下所示:
# Calculate the eigenvalues and eigenvectors
eigenvalues, eigenvectors = np.linalg.eig(mat)
print("Eigenvalues:", eigenvalues)
print("Eigenvectors:", eigenvectors)
这将产生以下输出:
Eigenvalues: [-0.62347538 9.62347538]
Eigenvectors: [[-0.83619408 -0.46462222]
[ 0.54843365 -0.885509 ]]
在前面的两个代码块中,我们创建了一个 2*2 的矩阵,并使用numpy.linalg子包的eig()函数计算了特征向量和特征值。
- 使用
eigvals()函数计算特征值,如下所示:
# Compute eigenvalues
eigenvalues= np.linalg.eigvals(mat)
print("Eigenvalues:", eigenvalues)
这将产生以下输出:
Eigenvalues: [-0.62347538 9.62347538]
在前面的代码片段中,我们使用numpy.linalg子包的eigvals()函数计算了特征值。完成特征分解后,我们将看到如何生成随机数和矩阵。
生成随机数
随机数在许多应用中都有使用,比如蒙特卡罗模拟、加密学、密码初始化和随机过程。生成真正的随机数并不容易,因此实际上大多数应用程序使用伪随机数。伪随机数对于大多数目的都是足够的,除非遇到一些极少数的特殊情况。随机数可以从离散和连续数据中生成。numpy.random()函数将为给定输入矩阵的大小生成一个随机数矩阵。
核心随机数生成器基于梅森旋转算法(参考 en.wikipedia.org/wiki/Mersenne_twister)。
让我们看一个生成随机数的示例,如下所示:
# Import numpy
import numpy as np
# Create an array with random values
random_mat=np.random.random((3,3))
print("Random Matrix: \n",random_mat)
这将产生以下输出:
Random Matrix: [[0.90613234 0.83146869 0.90874706]
[0.59459996 0.46961249 0.61380679]
[0.89453322 0.93890312 0.56903598]]
在前面的示例中,我们使用 numpy.random.random() 函数生成了一个 3*3 的随机矩阵。让我们尝试其他分布来生成随机数,例如二项分布和正态分布。
二项分布
二项分布模型描述了在每次试验中都有相同概率的重复试验的次数。在这里,每次试验都是独立的,且每次试验有两个可能的结果——成功和失败——这些结果可能出现在每个客户上。以下公式表示二项分布:
在这里,p 和 q 分别是成功和失败的概率,n 是试验次数,X 是期望的输出数量。
numpy.random 子包提供了一个 binomial() 函数,用于基于二项分布生成样本,该分布需要指定参数:试验次数和成功概率。
让我们考虑一个 17 世纪的赌博馆,你可以在这里对八个投掷物和九个硬币的翻转进行下注。如果你得到五个或更多的正面朝上,则你获胜,否则你将失败。让我们编写代码,模拟 1,000 个硬币的投掷,使用 binomial() 函数,如下所示:
# Import required libraries
import numpy as np
import matplotlib.pyplot as plt
# Create an numpy vector of size 5000 with value 0
cash_balance = np.zeros(5000)
cash_balance[0] = 500
# Generate random numbers using Binomial
samples = np.random.binomial(9, 0.5, size=len(cash_balance))
# Update the cash balance
for i in range(1, len(cash_balance)):
if samples[i] < 5:
cash_balance[i] = cash_balance[i - 1] - 1
else:
cash_balance[i] = cash_balance[i - 1] + 1
# Plot the updated cash balance
plt.plot(np.arange(len(cash_balance)), cash_balance)
plt.show()
这将产生以下输出:
在前面的代码块中,我们首先创建了一个大小为 500 且初始值为 0 的 cash_balance 数组,并将第一个值更新为 500。然后,我们使用 binomial() 函数生成了 0 到 9 之间的值。之后,我们根据掷硬币的结果更新了 cash_balance 数组,并使用 Matplotlib 库绘制了现金余额。
在每次执行中,代码将生成不同的结果或随机行走。如果你希望行走保持一致,你需要在 binomial() 函数中使用种子值。让我们尝试另一种形式的分布来生成随机数:正态分布。
正态分布
正态分布在现实生活中经常出现。正态分布也被称为钟形曲线,因为它的特征形状。概率密度函数描述了连续分布。numpy.random 子包提供了许多连续分布,如贝塔分布、伽马分布、逻辑分布、指数分布、多元正态分布和正态分布。normal() 函数可以从高斯分布或正态分布中生成样本。
让我们编写代码,通过 normal() 函数可视化正态分布,如下所示:
# Import required library
import numpy as np
import matplotlib.pyplot as plt
sample_size=225000
# Generate random values sample using normal distribution
sample = np.random.normal(size=sample_size)
# Create Histogram
n, bins, patch_list = plt.hist(sample, int(np.sqrt(sample_size)), density=True)
# Set parameters
mu, sigma=0,1
x= bins
y= 1/(sigma * np.sqrt(2 * np.pi)) * np.exp( - (bins - mu)**2 / (2 * sigma**2) )
# Plot line plot(or bell curve)
plt.plot(x,y,color='red',lw=2)
plt.show()
这将产生以下输出:
在这里,我们使用numpy.random子包的normal()函数生成随机值,并使用直方图和线性图或钟形曲线(即理论上的概率密度函数(PDF))将值进行展示,均值为 0,标准差为 1。
使用 SciPy 进行数据的正态性检验
正态分布在科学和统计操作中广泛应用。根据中心极限定理,随着样本量的增加,样本分布趋近于正态分布。正态分布因其已知且易于使用而广为人知。在大多数情况下,建议确认数据的正态性,特别是在假设数据符合高斯分布的参数方法中。文献中存在许多正态性检验方法,如 Shapiro-Wilk 检验、Anderson-Darling 检验和 D'Agostino-Pearson 检验。scipy.stats包提供了大多数正态性检验方法。
在本节中,我们将学习如何对数据应用正态性检验。我们使用三种样本:小型样本、中型样本和大型样本的随机数据。我们将使用normal()函数为这三种样本生成数据,如下所示:
# Import required library
import numpy as np
# create small, medium, and large samples for normality test
small_sample = np.random.normal(loc=100, scale=60, size=15)
medium_sample = np.random.normal(loc=100, scale=60, size=100)
large_sample = np.random.normal(loc=100, scale=60, size=1000)
我们现在将探索多种方法来检查数据的正态性:
- 使用直方图: 直方图是检查数据正态性的最简单和最快捷的方法。它将数据划分为多个区间,并统计每个区间中的观测值。最后,它将数据可视化。在这里,我们使用来自
seaborn库的distplot()来绘制直方图和核密度估计。让我们来看一个关于小型样本的直方图示例,如下所示:
# Histogram for small
import seaborn as sns
import matplotlib.pyplot as plt
# Create distribution plot
sns.distplot(small_sample)
sns.distplot(small_sample)
plt.show()
这将产生以下输出:
让我们来看一个关于中型样本的直方图示例,如下所示:
# Histogram for medium
import seaborn as sns
import matplotlib.pyplot as plt
# Create distribution plot
sns.distplot(medium_sample)
plt.show()
这将产生以下输出:
让我们来看一个关于大型样本的直方图示例,如下所示:
# Histogram for large
import seaborn as sns
import matplotlib.pyplot as plt
# Create distribution plot
sns.distplot(large_sample)
plt.show()
这将产生以下输出:
在前面的三个图中,我们可以观察到,随着样本量的增加,曲线逐渐变成正态分布曲线。直方图可以是检验数据正态性的一种有效工具。
- Shapiro-Wilk 检验: 此检验用于评估数据的正态性。在 Python 中,可以使用
scipy.stats子包中的shapiro()函数来进行正态性检验。shapiro()函数将返回两个值的元组:检验统计量和 p 值。让我们来看以下示例:
# Import shapiro function
from scipy.stats import shapiro
# Apply Shapiro-Wilk Test
print("Shapiro-Wilk Test for Small Sample: ",shapiro(small_sample))
print("Shapiro-Wilk Test for Medium Sample: ",shapiro(medium_sample))
print("Shapiro-Wilk Test for Large Sample: ",shapiro(large_sample))
这将产生以下输出:
Shapiro-Wilk Test for Small Sample: (0.9081739783287048, 0.2686822712421417)
Shapiro-Wilk Test for Medium Sample: (0.9661878347396851, 0.011379175819456577)
Shapiro-Wilk Test for Large Sample: (0.9991633892059326, 0.9433153867721558)
在前面的代码块中,你可以看到小型和大型数据集的 p 值都大于 0.05,因此由于原假设未被拒绝,这意味着样本看起来像是高斯分布或正态分布;而对于中型数据集,p 值小于 0.05,因此原假设被拒绝,这意味着样本看起来不像高斯分布或正态分布。
同样,我们可以使用 scipy.stats 子包中的 anderson() 和 normaltest() 函数,尝试 Anderson-Darling 检验和 D'Agostino-Pearson 正态性检验。我将这个留给你作为练习。在可视化方面,我们也可以尝试箱线图和 分位数-分位数 (QQ) 图技术来评估数据的正态性。我们将在接下来的章节 第五章,数据可视化 中学习箱线图技术。接下来我们将讨论掩码数组的概念。
使用 numpy.ma 子包创建掩码数组
在大多数情况下,现实数据是嘈杂且杂乱的。数据中通常会有很多空缺或缺失的字符。掩码数组在这种情况下非常有用,能够处理这个问题。掩码数组可能包含无效和缺失值。numpy.ma 子包提供了所有掩码数组所需的功能。在本章的这一部分中,我们将使用面部图像作为原始图像源,并执行对数掩码操作。
看一下以下的代码块:
# Import required library
import numpy as np
from scipy.misc import face
import matplotlib.pyplot as plt
face_image = face()
mask_random_array = np.random.randint(0, 3, size=face_image.shape)
fig, ax = plt.subplots(nrows=2, ncols=2)
# Display the Original Image
plt.subplot(2,2,1)
plt.imshow(face_image)
plt.title("Original Image")
plt.axis('off')
# Display masked array
masked_array = np.ma.array(face_image, mask=mask_random_array)
plt.subplot(2,2,2)
plt.title("Masked Array")
plt.imshow(masked_array)
plt.axis('off')
# Log operation on original image
plt.subplot(2,2,3)
plt.title("Log Operation on Original")
plt.imshow(np.ma.log(face_image).astype('uint8'))
plt.axis('off')
# Log operation on masked array
plt.subplot(2,2,4)
plt.title("Log Operation on Masked")
plt.imshow(np.ma.log(masked_array).astype('uint8'))
plt.axis('off')
# Display the subplots
plt.show()
这将产生以下输出:
在前面的代码块中,我们首先从 scipy.misc 子包加载了面部图像,并使用 randint() 函数创建了一个随机掩码。然后,我们将随机掩码应用于面部图像。之后,我们对原始面部图像和掩码面部图像进行了对数操作。最后,我们将所有图像显示在 2*2 的子图中。你还可以尝试对图像进行一系列来自 numpy.ma 子包的掩码操作。这里,我们只关注掩码数组的对数操作。这就是基本线性代数概念的全部内容。接下来是时候进入数据可视化的概念了,我们将在下一章学习。
总结
最后,我们可以得出结论,像线性代数这样的数学学科是所有机器学习算法的核心支柱。在本章中,我们专注于基础的线性代数概念,旨在提升你作为数据专业人士的能力。在这一章中,你学习了许多使用 NumPy 和 SciPy 子包的线性代数概念。我们主要关注了多项式、行列式、矩阵求逆;解线性方程;特征值和特征向量;奇异值分解(SVD);随机数;二项分布和正态分布;正态性检验;以及掩码数组。
下一章,第五章,数据可视化,将介绍如何使用 Python 进行数据可视化这一重要主题。数据可视化是我们在开始分析数据时经常进行的操作,它有助于展示数据中变量之间的关系。通过数据可视化,我们还可以更好地了解数据的统计属性。
第五章:第二节:探索性数据分析与数据清理
本节的主要目标是培养学习者的探索性数据分析(EDA)和数据清理技能。这些技能包括数据可视化、数据提取和预处理。本节将主要使用 matplotlib、seaborn、Bokeh、pandas、scikit-learn、NumPy 和 SciPy,并重点关注信号处理和时间序列分析。
本节包括以下章节:
-
第五章,数据可视化
-
第六章,数据的获取、处理和存储
-
第七章,清理杂乱数据
-
第八章,信号处理与时间序列
第六章:数据可视化
数据可视化是数据分析系统中帮助轻松理解和传达信息的初步步骤。它通过使用图表、图形、图表和地图等可视化元素将信息和数据以图形形式表示。这有助于分析师理解模式、趋势、异常值、分布和关系。数据可视化是一种有效处理大量数据集的方式。
Python 提供了多种用于数据可视化的库,如 Matplotlib、Seaborn 和 Bokeh。在本章中,我们将首先关注 Matplotlib,它是用于可视化的基础 Python 库。然后我们将探讨 Seaborn,Seaborn 基于 Matplotlib,并提供了高级的统计图表。最后,我们将使用 Bokeh 进行交互式数据可视化。我们还将探讨 pandas 绘图。以下是本章将要涵盖的主题列表:
-
使用 Matplotlib 进行可视化
-
使用 Seaborn 包进行高级可视化
-
使用 Bokeh 进行交互式可视化
技术要求
本章具有以下技术要求:
-
你可以在以下 GitHub 链接找到代码和数据集:
github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter05。 -
所有代码块都可以在
ch5.ipynb文件中找到。 -
本章仅使用一个 CSV 文件(
HR_comma_sep.csv)进行练习。 -
在本章中,我们将使用 Matplotlib、
pandas、Seaborn 和 Bokeh Python 库。
使用 Matplotlib 进行可视化
正如我们所知道的,一图胜千言。人类对视觉信息的理解更好。可视化有助于向任何类型的观众展示事物,并可以用通俗的语言轻松解释复杂的现象。Python 提供了几种可视化库,如 Matplotlib、Seaborn 和 Bokeh。
Matplotlib 是最流行的 Python 数据可视化模块。它是大多数高级 Python 可视化模块(如 Seaborn)的基础库。它提供了灵活且易于使用的内置函数,用于创建图形和图表。
在 Anaconda 中,Matplotlib 已经安装。如果你仍然遇到错误,可以通过以下方式安装它。
我们可以通过 pip 安装 Matplotlib,方法如下:
pip install matplotlib
对于 Python 3,我们可以使用以下命令:
pip3 install matplotlib
你也可以通过终端或命令提示符使用以下命令简单地安装 Matplotlib:
conda install matplotlib
要在 Matplotlib 中创建一个非常基础的图表,我们需要调用 plot() 函数,该函数位于 matplotlib.pyplot 子包中。此函数为已知 x 和 y 坐标的单个列表或多个列表的点生成一个二维图表。
以下示例代码位于本书代码包中的 ch5.ipynb 文件中,您可以通过以下 GitHub 链接找到该文件:github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/blob/master/Chapter05/Ch5.ipynb。
让我们看看一个小的示例代码,用于可视化折线图:
# Add the essential library matplotlib
import matplotlib.pyplot as plt
import numpy as np
# create the data
a = np.linspace(0, 20)
# Draw the plot
plt.plot(a, a + 0.5, label='linear')
# Display the chart
plt.show()
这将产生以下输出:
在前面的代码块中,首先,我们导入了 Matplotlib 和 NumPy 模块。之后,我们使用 NumPy 的 linespace() 函数创建数据,并使用 Matplotlib 的 plot() 函数绘制这些数据。最后,我们使用 show() 函数显示图形。
图表有两个基本组件:图形和坐标轴。图形是一个容器,所有内容都绘制在上面。它包含如图表、子图、坐标轴、标题和图例等组件。在下一节中,我们将重点介绍这些组件,它们就像图表的配件。
图表的配件
在 matplotlib 模块中,我们可以向图表添加标题和坐标轴标签。我们可以使用 plt.title() 添加标题,使用 plt.xlabel() 和 plt.ylabel() 添加标签。
多个图形意味着多个对象,如折线、柱状图和散点图。不同系列的点可以显示在同一个图表上。图例或图表系列反映 y 轴。图例是一个框,通常出现在图表的右侧或左侧,显示每个图形元素的含义。让我们看看一个示例,展示如何在图表中使用这些配件:
# Add the required libraries
import matplotlib.pyplot as plt
# Create the data
x = [1,3,5,7,9,11]
y = [10,25,35,33,41,59]
# Let's plot the data
plt.plot(x, y,label='Series-1', color='blue')
# Create the data
x = [2,4,6,8,10,12]
y = [15,29,32,33,38,55]
# Plot the data
plt.plot(x, y, label='Series-2', color='red')
# Add X Label on X-axis
plt.xlabel("X-label")
# Add X Label on X-axis
plt.ylabel("Y-label")
# Append the title to graph
plt.title("Multiple Python Line Graph")
# Add legend to graph
plt.legend()
# Display the plot
plt.show()
这将产生以下输出:
在前面的图表中,两个折线显示在同一个图表上。我们在 plot() 函数中使用了两个额外的参数 —— label 和 color。label 参数定义了系列的名称,color 定义了折线的颜色。在接下来的章节中,我们将重点介绍不同类型的图表。我们将在下一节中探讨散点图。
散点图
散点图使用笛卡尔坐标绘制数据点,显示数值的大小。它们还表示两个数值之间的关系。我们可以使用 Matplotlib 中的 scatter() 函数创建散点图,如下所示:
# Add the essential library matplotlib
import matplotlib.pyplot as plt
# create the data
x = [1,3,5,7,9,11]
y = [10,25,35,33,41,59]
# Draw the scatter chart
plt.scatter(x, y, c='blue', marker='*',alpha=0.5)
# Append the label on X-axis
plt.xlabel("X-label")
# Append the label on X-axis
plt.ylabel("Y-label")
# Add the title to graph
plt.title("Scatter Chart Sample")
# Display the chart
plt.show()
这将产生以下输出:
在前面的散点图中,scatter() 函数接受 x 轴和 y 轴的值。在我们的示例中,我们绘制了两个列表:x 和 y。我们还可以使用一些可选参数,例如 c 来设置颜色,alpha 来设置标记的透明度(范围从 0 到 1),以及 marker 来设置散点图中点的形状,如 *、o 或任何其他符号。在下一节中,我们将重点介绍折线图。
折线图
折线图是一种显示两变量之间关系的图表,它由一系列数据点连接而成:
# Add the essential library matplotlib
import matplotlib.pyplot as plt
# create the data
x = [1,3,5,7,9,11]
y = [10,25,35,33,41,59]
# Draw the line chart
plt.plot(x, y)
# Append the label on X-axis
plt.xlabel("X-label")
# Append the label on X-axis
plt.ylabel("Y-label")
# Append the title to chart
plt.title("Line Chart Sample")
# Display the chart
plt.show()
这会生成如下输出:
在之前的折线图程序中,plot() 函数接受 x 轴和 y 轴的数值。在接下来的章节中,我们将学习如何绘制饼图。
饼图
饼图是一个圆形图表,被分成楔形的部分。每一部分的大小与它所代表的数值成正比。饼图的总值为 100 百分比:
# Add the essential library matplotlib
import matplotlib.pyplot as plt
# create the data
subjects = ["Mathematics","Science","Communication Skills","Computer Application"]
scores = [85,62,57,92]
# Plot the pie plot
plt.pie(scores,
labels=subjects,
colors=['r','g','b','y'],
startangle=90,
shadow= True,
explode=(0,0.1,0,0),
autopct='%1.1f%%')
# Add title to graph
plt.title("Student Performance")
# Draw the chart
plt.show()
这会生成如下输出:
在之前的饼图代码中,我们指定了 values、labels、colors、startangle、shadow、explode 和 autopct。在我们的例子中,values 是学生在四个科目中的成绩,labels 是科目名称的列表。我们还可以为每个科目的成绩指定颜色列表。startangle 参数指定第一个值的角度,默认为 90 度;这意味着第一个线条是垂直的。
可选地,我们还可以使用 shadow 参数来指定饼图切片的阴影,使用 explode 参数来突出显示某些饼图切片的二进制值。如果我们想突出显示第二个饼图切片,则值的元组为 (0, 0.1, 0, 0)。接下来我们跳到条形图部分。
条形图
条形图是一种比较不同组值的可视化工具,可以水平或垂直绘制。我们可以使用 bar() 函数创建条形图:
# Add the essential library matplotlib
import matplotlib.pyplot as plt
# create the data
movie_ratings = [1,2,3,4,5]
rating_counts = [21,45,72,89,42]
# Plot the data
plt.bar(movie_ratings, rating_counts, color='blue')
# Add X Label on X-axis
plt.xlabel("Movie Ratings")
# Add X Label on X-axis
plt.ylabel("Rating Frequency")
# Add a title to graph
plt.title("Movie Rating Distribution")
# Show the plot
plt.show()
这会生成如下输出:
在之前的条形图程序中,bar() 函数接受 x 轴值、y 轴值和颜色。在我们的例子中,我们绘制的是电影评分及其频率。电影评分位于 x 轴上,评分频率位于 y 轴上。我们还可以使用 color 参数为条形图的条形指定颜色。接下来,让我们看看条形图的另一种变体。
直方图
直方图显示的是一个数值变量的分布情况。我们使用 hist() 方法创建直方图,它显示的是连续变量的概率分布。直方图只适用于单一变量,而条形图适用于两个变量:
# Add the essential library
import matplotlib.pyplot as plt
# Create the data
employee_age = [21,28,32,34,35,35,37,42,47,55]
# Create bins for histogram
bins = [20,30,40,50,60]
# Plot the histogram
plt.hist(employee_age, bins, rwidth=0.6)
# Add X Label on X-axis
plt.xlabel("Employee Age")
# Add X Label on X-axis
plt.ylabel("Frequency")
# Add title to graph
plt.title("Employee Age Distribution")
# Show the plot
plt.show()
这会生成如下输出:
在之前的直方图中,hist() 函数接受 values、bins 和 rwidth。在我们的例子中,我们绘制的是员工的年龄,并使用 10 年的区间。我们从 20 岁到 60 岁开始,每个区间的大小为 10 年。我们使用 0.6 的相对条形宽度,但你可以选择任何大小来调整宽度的粗细。现在,我们将跳转到气泡图,它可以在二维图中处理多个变量。
气泡图
气泡图是一种散点图。它不仅使用笛卡尔坐标绘制数据点,还在数据点上创建气泡。气泡显示了图表的第三维度。它展示了三个数值:两个数值位于 x 和 y 轴上,第三个数值则是数据点(或气泡)的大小:
# Import the required modules
import matplotlib.pyplot as plt
import numpy as np
# Set figure size
plt.figure(figsize=(8,5))
# Create the data
countries = ['Qatar','Luxembourg','Singapore','Brunei','Ireland','Norway','UAE','Kuwait']
populations = [2781682, 604245,5757499,428963,4818690,5337962,9630959,4137312]
gdp_per_capita = [130475, 106705, 100345, 79530, 78785, 74356,69382, 67000]
# scale GDP per capita income to shoot the bubbles in the graph
scaled_gdp_per_capita = np.divide(gdp_per_capita, 80)
colors = np.random.rand(8)
# Draw the scatter diagram
plt.scatter(countries, populations, s=scaled_gdp_per_capita, c=colors, cmap="Blues",edgecolors="grey", alpha=0.5)
# Add X Label on X-axis
plt.xlabel("Countries")
# Add Y Label on X-axis
plt.ylabel("Population")
# Add title to graph
plt.title("Bubble Chart")
# rotate x label for clear visualization
plt.xticks(rotation=45)
# Show the plot
plt.show()
这将产生以下输出:
在前面的图表中,使用散点图函数创建了一个气泡图。这里,重要的是散点图函数的 s(大小)参数。我们将第三个变量 scaled_gdp_per_capita 分配给了 size 参数。在前面的气泡图中,国家位于 x 轴上,人口位于 y 轴上,而人均 GDP 通过散点或气泡的大小来展示。我们还为气泡分配了随机颜色,以使其更具吸引力并易于理解。从气泡的大小,可以很容易看出卡塔尔的人均 GDP 最高,而科威特的人均 GDP 最低。在前面的所有部分中,我们集中讨论了大部分 Matplotlib 图表。现在,我们将看看如何使用 pandas 模块绘制图表。
pandas 绘图
pandas 库提供了 plot() 方法,它是 Matplotlib 库的封装。plot() 方法允许我们直接在 pandas DataFrame 上创建图表。以下是用于创建图表的 plot() 方法参数:
-
kind: 用于图表类型的字符串参数,例如:line、bar、barh、hist、box、KDE、pie、area 或 scatter。 -
figsize: 这定义了图表的尺寸,采用 (宽度, 高度) 的元组形式。 -
title: 这定义了图表的标题。 -
grid: 布尔参数,表示轴的网格线。 -
legend: 这定义了图例。 -
xticks: 这定义了 x 轴刻度的序列。 -
yticks: 这定义了 y 轴刻度的序列。
让我们使用 pandas plot() 函数创建一个散点图:
# Import the required modules
import pandas as pd
import matplotlib.pyplot as plt
# Let's create a Dataframe
df = pd.DataFrame({
'name':['Ajay','Malala','Abhijeet','Yming','Desilva','Lisa'],
'age':[22,72,25,19,42,38],
'gender':['M','F','M','M','M','F'],
'country':['India','Pakistan','Bangladesh','China','Srilanka','UK'],
'income':[2500,3800,3300,2100,4500,5500]
})
# Create a scatter plot
df.plot(kind='scatter', x='age', y='income', color='red', title='Age Vs Income')
# Show figure
plt.show()
这将产生以下输出:
在前面的图表中,plot() 函数使用了 kind、x、y、color 和 title 参数。在我们的示例中,我们使用 kind 参数为 'scatter' 来绘制年龄与收入之间的散点图。age 和 income 列分别分配给 x 和 y 参数。散点的颜色和图表的标题被分配给 color 和 title 参数:
import matplotlib.pyplot as plt
import pandas as pd
# Create bar plot
df.plot(kind='bar',x='name', y='age', color='blue')
# Show figure
plt.show()
这将产生以下输出:
在前面的图表中,plot() 函数使用 kind、x、y、color 和 title 参数。在我们的示例中,我们使用 kind 参数为 'bar' 来绘制年龄与收入之间的柱状图。name 和 age 列分别分配给 x 和 y 参数。散点的颜色被分配给 color 参数。这就是关于 pandas 绘图的内容。从下一部分开始,我们将看到如何使用 Seaborn 库可视化数据。
使用 Seaborn 包进行高级可视化
可视化有助于轻松理解复杂的模式和概念。它以图像的形式表示洞察。在前面的部分中,我们学习了如何使用 Matplotlib 进行可视化。现在,我们将探索新的 Seaborn 库,它可以进行高级统计图表的绘制。Seaborn 是一个开源的 Python 库,用于高阶互动性和吸引人的统计可视化。Seaborn 以 Matplotlib 为基础库,提供了更简单、易懂、互动性强且美观的可视化效果。
在 Anaconda 软件包中,您可以通过以下方式安装 Seaborn 库:
使用 pip 安装 Seaborn:
pip install seaborn
对于 Python 3,请使用以下命令:
pip3 install seaborn
您可以通过终端或命令提示符使用以下命令轻松安装 Seaborn:
conda install seaborn
如果您是在 Jupyter Notebook 中安装,则需要在 pip 命令前加上 ! 符号。以下是示例:
!pip install seaborn
让我们跳转到 Seaborn 的 lm 图。
lm 图
lm 图绘制了散点图并在其上拟合回归模型。散点图是理解两个变量之间关系的最佳方式。它的输出可视化表示了两个变量的联合分布。lmplot() 接受两个列名——x 和 y——作为字符串和 DataFrame 变量。让我们来看以下示例:
# Import the required libraries
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Create DataFrame
df=pd.DataFrame({'x':[1,3,5,7,9,11],'y':[10,25,35,33,41,59]})
# Create lmplot
sns.lmplot(x='x', y='y', data=df)
# Show figure
plt.show()
这将产生以下输出:
默认情况下,lmplot() 会拟合回归线。我们也可以通过将 fit_reg 参数设置为 False 来移除回归线:
# Create lmplot
sns.lmplot(x='x', y='y', data=df, fit_reg=False)
# Show figure
plt.show()
这将产生以下输出:
让我们使用 HR Analytics 数据集并尝试绘制 lmplot():
# Load the dataset
df=pd.read_csv("HR_comma_sep.csv")
# Create lmplot
sns.lmplot(x='satisfaction_level', y='last_evaluation', data=df, fit_reg=False, hue='left')
# Show figure
plt.show()
这将产生以下输出:
在前面的示例中,last_evaluation 是员工的评估表现,satisfaction_level 是员工在公司的满意度,left 表示员工是否离开公司。satisfaction_level 和 last_evaluation 分别绘制在 x 和 y 轴上。第三个变量 left 被传递到 hue 参数中。hue 属性用于颜色阴影。我们将 left 变量作为 hue。从图表中我们可以清楚地看到,已经离职的员工分散成三组。接下来我们来看条形图。
条形图
barplot() 显示了分类变量和连续变量之间的关系。它使用不同长度的矩形条形图:
# Import the required libraries
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Create DataFrame
df=pd.DataFrame({'x':['P','Q','R','S','T','U'],'y':[10,25,35,33,41,59]})
# Create lmplot
sns.barplot(x='x', y='y', data=df)
# Show figure
plt.show()
这将产生以下输出:
在前面的示例中,条形图是通过 bar() 函数创建的。它接受两个列——x 和 y——以及一个 DataFrame 作为输入。在接下来的部分中,我们将看到如何绘制分布图。
分布图
这绘制了一个单变量的分布图。它是默认箱体大小的直方图与核密度估计(KDE)图的结合。在我们的示例中,distplot()将接受satisfaction_level输入列并绘制其分布。在这里,satisfaction_level的分布有两个峰值:
# Create a distribution plot (also known as Histogram)
sns.distplot(df.satisfaction_level)
# Show figure
plt.show()
这将产生以下输出:
在前面的代码块中,我们使用distplot()创建了分布图。现在是时候跳转到箱型图了。
箱型图
箱型图,又称箱形须图,是理解每个变量分布及其四分位数的最佳图表之一。它可以是水平的也可以是垂直的。它通过一个箱子显示四分位数分布,该箱子被称为须。它还显示数据的最小值、最大值和异常值。我们可以使用 Seaborn 轻松创建箱型图:
# Create boxplot
sns.boxplot(data=df[['satisfaction_level','last_evaluation']])
# Show figure
plt.show()
这将产生以下输出:
在前面的示例中,我们使用了两个变量来绘制箱型图。这里,箱型图表明satisfaction_level的范围高于last_evaluation(表现)。接下来,我们来看看 Seaborn 中的 KDE 图。
KDE 图
kde()函数绘制给定连续变量的概率密度估计。这是一种非参数估计方法。在我们的示例中,kde()函数接受一个参数满意度并绘制 KDE:
# Create density plot
sns.kdeplot(df.satisfaction_level)
# Show figure
plt.show()
这将产生以下输出:
在前面的代码块中,我们使用kdeplot()创建了一个密度图。在下一节中,我们将看到另一种分布图,它是密度图和箱型图的结合,称为小提琴图。
小提琴图
小提琴图是箱型图和 KDE 的结合形式,能够提供易于理解的分布分析:
# Create violin plot
sns.violinplot(data=df[['satisfaction_level','last_evaluation']])
# Show figure
plt.show()
这将产生以下输出:
在前面的示例中,我们使用了两个变量来绘制小提琴图。在这里,我们可以得出结论,satisfaction_level的范围高于last_evaluation(表现),且这两个变量的分布中都有两个峰值。完成分布图的分析后,我们将看到如何将groupby操作和箱型图结合成一个图表,使用计数图来展示。
计数图
countplot()是一个特殊类型的条形图。它显示每个分类变量的频率。它也被称为分类变量的直方图。与 Matplotlib 相比,它简化了操作。在 Matplotlib 中,要创建一个计数图,首先需要按类别列进行分组,并计算每个类别的频率。之后,Matplotlib 的条形图会使用这个计数。然而,Seaborn 的计数图只需要一行代码就可以绘制分布:
# Create count plot (also known as Histogram)
sns.countplot(x='salary', data=df)
# Show figure
plt.show()
这将产生以下输出:
在上面的示例中,我们正在统计salary变量。count()函数接受一个单列和 DataFrame。因此,从图表中我们可以很容易地得出结论,大多数员工的工资都在低到中等范围内。我们还可以将hue作为第二个变量。让我们看看以下示例:
# Create count plot (also known as Histogram)
sns.countplot(x='salary', data=df, hue='left')
# Show figure
plt.show()
这将产生以下输出:
在上述示例中,我们可以看到left被用作色调或颜色阴影。这表明大多数薪资最低的员工离开了公司。接下来,我们来看另一个用于可视化两个变量关系和分布的重要图表。
联合图
联合图是一种多面板可视化,显示了双变量关系以及单个变量的分布。我们还可以使用jointplot()的kind参数绘制 KDE 图。通过将kind参数设置为"kde",我们可以绘制 KDE 图。让我们看以下示例:
# Create joint plot using kernel density estimation(kde)
sns.jointplot(x='satisfaction_level', y='last_evaluation', data=df, kind="kde")
# Show figure
plt.show()
这将产生以下输出:
在上述图中,我们使用jointplot()创建了联合图,并通过kind参数设置为"kde"来添加了kde图。接下来让我们来看热力图,进行更丰富的可视化。
热力图
热力图提供了二维网格表示。网格的每个单元格包含矩阵的一个值。热力图功能还提供了对每个单元格的注释:
# Import required library
import seaborn as sns
# Read iris data using load_dataset() function
data = sns.load_dataset("iris")
# Find correlation
cor_matrix=data.corr()
# Create heatmap
sns.heatmap(cor_matrix, annot=True)
# Show figure
plt.show()
这将产生以下输出:
在上述示例中,使用load_dataset()加载了 Iris 数据集,并通过corr()函数计算了相关性。corr()函数返回相关性矩阵。然后,使用heatmap()函数绘制相关性矩阵的网格视图。它接受两个参数:相关性矩阵和annot。annot参数设置为True。在图中,我们可以看到一个对称矩阵,所有对角线上的值都是 1,这表示一个变量与自身的完美相关性。我们还可以通过cmap参数设置新的颜色映射以实现不同的颜色:
# Create heatmap
sns.heatmap(cor_matrix, annot=True, cmap="YlGnBu")
# Show figure
plt.show()
这将产生以下输出:
在上述热力图中,我们通过cmap参数为不同的颜色设置了颜色映射。这里,我们使用了YlGnBu(黄色、绿色和蓝色)组合作为cmap。现在,我们将进入对角矩阵图(pair plot)以进行更快速的探索性分析。
对角矩阵图
Seaborn 提供了快速的探索性数据分析,通过对角矩阵图展示变量间的关系以及单独的分布。对角矩阵图使用直方图显示单一分布,并通过散点图展示联合分布:
# Load iris data using load_dataset() function
data = sns.load_dataset("iris")
# Create a pair plot
sns.pairplot(data)
# Show figure
plt.show()
这将产生以下输出:
在前面的示例中,Iris 数据集是通过load_dataset()加载的,并将该数据集传递给pairplot()函数。在图表中,它创建了一个n乘n的矩阵或图形网格。对角线展示了各列的分布,网格的非对角元素展示了散点图,以便理解所有变量之间的关系。
在前面的几个部分中,我们已经看到了如何使用 Seaborn 绘图。现在,我们将转到另一个重要的可视化库——Bokeh。在接下来的部分中,我们将使用 Bokeh 库绘制互动和多功能的图表。
使用 Bokeh 进行互动式可视化
Bokeh 是一个互动性强、高质量、功能多样、专注且更强大的可视化库,适用于大数据量和流式数据。它为现代 Web 浏览器提供互动丰富的图表、图形、布局和仪表板。其输出可以映射到笔记本、HTML 或服务器。
Matplotlib 和 Bokeh 库有不同的用途。Matplotlib 专注于静态、简单和快速的可视化,而 Bokeh 则专注于高度互动、动态、基于 Web 的高质量可视化。Matplotlib 通常用于出版物中的图像,而 Bokeh 则面向 Web 用户。在本章的后续部分,我们将学习如何使用 Bokeh 进行基础绘图。我们可以利用 Bokeh 为数据探索创建更多互动的可视化效果。
安装 Bokeh 库的最简单方法是通过 Anaconda 发行包。要安装 Bokeh,请使用以下命令:
conda install bokeh
我们还可以使用pip来安装它。要使用pip安装 Bokeh,请使用以下命令:
pip install bokeh
绘制一个简单的图形
让我们用 Bokeh 绘制一个简单的图形。首先,我们需要导入基本的bokeh.plotting模块。output_notebook()函数定义了图表将在 Jupyter Notebook 上渲染。figure对象是绘制图表和图形的核心对象之一。figure对象关注图表的标题、大小、标签、网格和样式。figure对象还处理图表样式、标题、坐标轴标签、坐标轴、网格以及添加数据的各种方法:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
# Create the data
x = [1,3,5,7,9,11]
y = [10,25,35,33,41,59]
# Output to notebook
output_notebook()
# Instantiate a figure
fig= figure(plot_width = 500, plot_height = 350)
# Create scatter circle marker plot by rendering the circles
fig.circle(x, y, size = 10, color = "red", alpha = 0.7)
# Show the plot
show(fig)
这将产生如下输出:
在设置完figure对象后,我们将使用 circle 函数创建一个散点圆形标记图。circle()函数将接受x和y值。它还接受大小、颜色和透明度(alpha)参数。最后,show()函数将在所有特性和数据添加到图表后,绘制输出结果。
符号
Bokeh 使用视觉符号(glyph),它指的是圆圈、线条、三角形、正方形、条形、菱形以及其他形状的图形。符号是一种独特的标记,用于以图像形式传达信息。让我们使用line()函数创建一条线性图:
# Import the required modules
from bokeh.plotting import figure, output_notebook, show
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
# Create the data
x_values = [1,3,5,7,9,11]
y_values = [10,25,35,33,41,59]
# Output to notebook
output_notebook()
# Instantiate a figure
p = figure(plot_width = 500, plot_height = 350)
# create a line plot
p.line(x_values, y_values, line_width = 1, color = "blue")
# Show the plot
show(p)
这将产生如下输出:
在上面的示例中,line() 函数接受x和y轴值。它还接受线的line_width和color值。在下一节中,我们将重点介绍多图表的布局。
布局
Bokeh 提供了用于组织图和小部件的布局。布局将多个图表组织在单个面板中,用于交互式可视化。它们还允许根据面板大小设置调整图表和小部件的大小调整模式。布局可以是以下类型之一:
-
行布局:这将所有图表以行或水平方式组织。
-
列布局:这将所有图表以列或垂直方式组织。
-
嵌套布局:这是行和列布局的组合。
-
网格布局:这为您提供了一个网格矩阵,用于排列图表。
让我们看一个行布局的例子:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook, show
from bokeh.layouts import row, column
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure
fig1 = figure(plot_width = 300, plot_height = 300)
fig2 = figure(plot_width = 300, plot_height = 300)
fig3 = figure(plot_width = 300, plot_height = 300)
# Create scatter marker plot by render the circles
fig1.circle(df['petal_length'], df['sepal_length'], size=8, color = "green", alpha = 0.5)
fig2.circle(df['petal_length'], df['sepal_width'], size=8, color = "blue", alpha = 0.5)
fig3.circle(df['petal_length'], df['petal_width'], size=8, color = "red", alpha = 0.5)
# Create row layout
row_layout = row(fig1, fig2, fig3)
# Show the plot
show(row_layout)
这导致以下输出:
在此布局图中,我们导入了行和列布局,从 Bokeh 示例数据加载了鸢尾花数据,用图表宽度和高度实例化了三个 figure 对象,在每个图表对象上创建了三个散点圆圈标记,并创建了行布局。此行布局将以 figure 对象作为输入,并使用 show() 函数绘制。我们也可以通过创建列布局来创建列布局,如下所示:
# Create column layout
col_layout = column(fig1, fig2, fig3)
# Show the plot
show(col_layout)
这导致以下输出:
在前面的图中,我们创建了三个图表的列布局。让我们跳转到嵌套布局,以进行更强大的可视化。
使用行和列布局进行嵌套布局
嵌套布局是多行和列布局的组合。让我们看看这里给出的示例,以便更好地实际理解:
# Import the required modules
from bokeh.plotting import figure, output_notebook, show
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.layouts import row, column
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure
fig1 = figure(plot_width = 300, plot_height = 300)
fig2 = figure(plot_width = 300, plot_height = 300)
fig3 = figure(plot_width = 300, plot_height = 300)
# Create scatter marker plot by render the circles
fig1.circle(df['petal_length'], df['sepal_length'], size=8, color = "green", alpha = 0.5)
fig2.circle(df['petal_length'], df['sepal_width'], size=8, color = "blue", alpha = 0.5)
fig3.circle(df['petal_length'], df['petal_width'], size=8, color = "red", alpha = 0.5)
# Create nested layout
nasted_layout = row(fig1, column(fig2, fig3))
# Show the plot
show(nasted_layout)
这导致以下输出:
在这里,您可以看到行布局有两行。在第一行中,分配了 fig1,第二行有 fig2 和 fig3 的列布局。因此,此布局变为 2*2 布局,第一列仅有一个组件,第二列有两个组件。
多个图表
还可以使用网格布局创建多个图表和对象。网格布局以行列矩阵方式排列图表和小部件对象。它接受每行的图形对象列表。我们还可以使用 None 作为占位符:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.layouts import gridplot
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure
fig1 = figure(plot_width = 300, plot_height = 300)
fig2 = figure(plot_width = 300, plot_height = 300)
fig3 = figure(plot_width = 300, plot_height = 300)
# Create scatter marker plot by render the circles
fig1.circle(df['petal_length'], df['sepal_length'], size=8, color = "green", alpha = 0.5)
fig2.circle(df['petal_length'], df['sepal_width'], size=8, color = "blue", alpha = 0.5)
fig3.circle(df['petal_length'], df['petal_width'], size=8, color = "red", alpha = 0.5)
# Create a grid layout
grid_layout = gridplot([[fig1, fig2], [None,fig3]])
# Show the plot
show(grid_layout)
这导致以下输出:
前面的布局类似于嵌套布局。这里,我们导入了 gridplot()。它将组件排列在行和列中。网格图采用一列行图。列表中的第一项是 fig1 和 fig2。第二项是 None 和 fig3。每个项目都是网格矩阵中的一行。None 占位符用于使单元格保持空白或没有组件。
尺寸模式可以帮助我们配置具有可调整大小选项的图形。Bokeh 提供了以下尺寸模式:
-
fixed:保持原始宽度和高度不变。 -
stretch_width:根据其他组件的类型,拉伸到可用宽度。它不保持纵横比。 -
stretch_height:根据其他组件的类型,拉伸到可用高度。它不保持纵横比。 -
stretch_both:根据其他组件的类型,拉伸宽度和高度,同时不保持原始纵横比。 -
scale_width:根据其他组件的类型,拉伸到可用宽度,同时保持原始纵横比。 -
scale_height:根据其他组件的类型,拉伸到可用高度,同时保持原始纵横比。 -
scale_both:根据其他组件的类型,拉伸宽度和高度,同时保持原始纵横比。
在了解了布局和多个图表之后,接下来是学习互动可视化的交互。
交互
Bokeh 提供了交互式图例,用于运行时可操作的图表。可以通过点击符号图表来隐藏或静音图例。我们可以通过激活click_policy属性并点击图例项来启用这些模式。
隐藏点击策略
隐藏点击策略通过点击图例项来隐藏所需的符号。让我们看一个隐藏点击策略的例子:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models import CategoricalColorMapper
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure object
fig = figure(plot_width = 500, plot_height = 350, title="Petal length Vs. Petal Width",
x_axis_label='petal_length', y_axis_label='petal_width')
# Create scatter marker plot by render the circles
for specie, color in zip(['setosa', 'virginica','versicolor'], ['blue', 'green', 'red']):
data = df[df.species==specie]
fig.circle('petal_length', 'petal_width', size=8, color=color, alpha = 0.7, legend_label=specie, source=data)
# Set the legend location and click policy
fig.legend.location = 'top_left'
fig.legend.click_policy="hide"
# Show the plot
show(fig)
这将产生以下输出:
在这里,我们可以通过figure对象的legend.click_policy参数设置点击策略。此外,我们需要对每种类型的符号或图例元素运行for循环,在这些元素上进行点击。在我们的示例中,我们正在为物种和颜色类型运行for循环。在点击图例中的任何物种时,它会过滤数据并隐藏该符号。
静音点击策略
静音点击策略通过点击图例项来静音符号。在这里,以下代码显示了高强度的所需符号,而不感兴趣的符号则使用较低强度,而不是隐藏整个符号。让我们看一个静音点击策略的例子:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models import CategoricalColorMapper
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure object
fig = figure(plot_width = 500, plot_height = 350, title="Petal length Vs. Petal Width",
x_axis_label='petal_length', y_axis_label='petal_width')
# Create scatter marker plot by render the circles
for specie, color in zip(['setosa', 'virginica','versicolor'], ['blue', 'green', 'red']):
data = df[df.species==specie]
fig.circle('petal_length', 'petal_width', size=8, color=color, alpha = 0.7,legend_label=specie,source=data,
muted_color=color, muted_alpha=0.2)
# Set the legend location and click policy
fig.legend.location = 'top_left'
fig.legend.click_policy="mute"
# Show the plot
show(fig)
这将产生以下输出:
在这里,我们可以通过legend.click_policy参数设置静音点击策略来静音图形对象。此外,我们需要对每种类型的符号或图例元素运行for循环,在这些元素上进行点击。在我们的示例中,我们正在为物种和颜色类型运行for循环。在点击图例中的任何物种时,它会过滤数据并隐藏该符号。此外,我们需要为散点圆形标记添加muted_color和muted_alpha参数。
注解
Bokeh 提供了多种注解,用于为可视化提供补充信息。它通过添加以下信息来帮助查看者:
-
标题:这个注释为图表提供一个名称。
-
轴标签:这个注释为轴提供标签,帮助我们理解x轴和y轴表示的内容。
-
图例:这个注释通过颜色或形状表示第三个变量,并帮助我们将特征链接在一起,便于解释。
-
颜色条:颜色条是通过使用 ColorMapper 和颜色调色板创建的。
让我们看一个注释的例子:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models import CategoricalColorMapper
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Create color mapper for categorical column
color_mapper = CategoricalColorMapper(factors=['setosa', 'virginica', 'versicolor'], palette=['blue', 'green', 'red'])
color_dict={'field': 'species','transform': color_mapper }
# Instantiate a figure object
p = figure(plot_width = 500, plot_height = 350, title="Petal length Vs. Petal Width",
x_axis_label='petal_length', y_axis_label='petal_width')
# Create scatter marker plot by render the circles
p.circle('petal_length', 'petal_width', size=8, color=color_dict, alpha = 0.5, legend_group='species', source=df)
# Set the legend location
p.legend.location = 'top_left'
# Show the plot
show(p)
这将生成以下输出:
在前面的例子中,导入了CategoricalColorMapper并通过定义鸢尾花品种中的因子或唯一项及其相应的颜色来创建对象。通过为映射器定义field和transform参数来创建颜色字典。我们需要定义图表的标题;x_axis_label和y_axis_label是在figure对象中定义的。图例是在圆形散点标记函数中定义的,使用品种列并通过figure对象的top_left位置属性定义其位置。
悬停工具
悬停工具会在鼠标指针悬停在特定区域时显示相关信息。让我们看一些例子来理解悬浮图:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Create color mapper for categorical column
mapper = CategoricalColorMapper(factors=['setosa', 'virginica', 'versicolor'],
palette=['blue', 'green', 'red'])
color_dict={'field': 'species','transform': mapper}
# Create hovertool and specify the hovering information
hover = HoverTool(tooltips=[('Species type','@species'),
('IRIS Petal Length','@petal_length'),
('IRIS Petal Width', '@petal_width')])
# Instantiate a figure object
p = figure(plot_width = 500, plot_height = 350, title="Petal length Vs. Petal Width",
x_axis_label='petal_length', y_axis_label='petal_width',
tools=[hover, 'pan', 'wheel_zoom'])
# Create scatter marker plot by render the circles
p.circle('petal_length', 'petal_width', size=8, color=color_dict, alpha = 0.5,legend_group='species',source=df)
# Set the legend location
p.legend.location = 'top_left'
# Show the plot
show(p)
这将生成以下输出:
在前面的例子中,我们从bokeh.models导入了HoverTool并通过定义在鼠标悬停时显示的信息来创建它的对象。在我们的例子中,我们在元组列表中定义了信息。每个元组有两个参数,第一个是字符串标签,第二个是实际值(前面加上@)。这个悬停对象被传递到figure对象的tools参数中。
小部件
小部件提供了前端的实时交互。小部件能够在运行时修改和更新图表。它们可以运行 Bokeh 服务器或独立的 HTML 应用程序。使用小部件时,您需要指定功能。它可以嵌套在布局中。将小部件功能添加到程序中有两种方法:
-
CustomJS 回调
-
使用 Bokeh 服务器和设置事件处理程序,如
onclick或onchange事件
标签面板
标签面板使我们能够在一个窗口中创建多个图表和布局。让我们看一个标签面板的例子:
# Import the required modules
from bokeh.plotting import figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models.widgets import Tabs
from bokeh.models.widgets import Panel
# Import iris flower dataset as pandas DataFrame
from bokeh.sampledata.iris import flowers as df
# Output to notebook
output_notebook()
# Instantiate a figure
fig1 = figure(plot_width = 300, plot_height = 300)
fig2 = figure(plot_width = 300, plot_height = 300)
# Create scatter marker plot by render the circles
fig1.circle(df['petal_length'], df['sepal_length'], size=8, color = "green", alpha = 0.5)
fig2.circle(df['petal_length'], df['sepal_width'], size=8, color = "blue", alpha = 0.5)
# Create panels
tab1 = Panel(child=fig1, title='tab1')
tab2 = Panel(child=fig2, title='tab2')
# Create tab by putting panels into it
tab_layout = Tabs(tabs=[tab1,tab2])
# Show the plot
show(tab_layout)
这将生成以下输出:
在前面的代码中,我们通过将figure对象传递给child参数,并将title传递给title参数,创建了两个面板。两个面板被组合成一个列表,并传递给Tabs布局对象。通过show()函数显示此Tabs对象。您只需点击标签即可更改标签。
滑块
滑块是一个图形化的轨迹条,它通过在水平刻度上移动来控制值。我们可以在不影响图表格式的情况下更改图表的值。让我们来看一个滑块的例子:
# Import the required modules
from bokeh.plotting import Figure
from bokeh.plotting import output_notebook
from bokeh.plotting import show
from bokeh.models import CustomJS
from bokeh.models import ColumnDataSource
from bokeh.models import Slider
from bokeh.layouts import column
# Show output in notebook
output_notebook()
# Create list of data
x = [x for x in range(0, 100)]
y = x
# Create a DataFrame
df = ColumnDataSource(data={"x_values":x, "y_values":y})
# Instantiate the Figure object
fig = Figure(plot_width=350, plot_height=350)
# Create a line plot
fig.line('x_values', 'y_values', source=df, line_width=2.5, line_alpha=0.8)
# Create a callback using CustomJS
callback = CustomJS(args=dict(source=df), code="""
var data = source.data;
var f = cb_obj.value
var x_values = data['x_values']
var y_values = data['y_values']
for (var i = 0; i < x_values.length; i++) {
y_values[i] = Math.pow(x_values[i], f)
}
source.change.emit();
""")
slider_widget = Slider(start=0.0, end=10, value=1, step=.1, title="Display power of x")
slider_widget.js_on_change('value', callback)
# Create layout
slider_widget_layout = column(fig,slider_widget)
# Display the layout
show(slider_widget_layout)
这将产生以下输出:
在前面的代码中,Bokeh 的slider()函数接受start、end、value、step、title和 CustomJS 回调作为输入。在我们的例子中,我们创建了一个折线图,并通过滑动条根据x变量的幂来改变其y值。我们可以通过将start、end、value、step、title和 CustomJS 回调传递给Slider对象来创建滑块。我们需要关注 CustomJS 回调。它获取源数据框,通过cb_obj.value获取滑块的值,并使用change.emit()函数更新其值。我们在for循环中更新y_value,通过找到其幂次来使用滑块值。
总结
在本章中,我们讨论了如何使用 Matplotlib、pandas、Seaborn 和 Bokeh 进行数据可视化。我们介绍了各种图表类型,如折线图、饼图、条形图、直方图、散点图、箱线图、气泡图、热图、KDE 图、提琴图、计数图、联合图和配对图。我们重点介绍了图表的附加功能,如标题、标签、图例、布局、子图和注释。此外,我们还学习了使用 Bokeh 布局、交互、悬停工具和小部件进行交互式可视化。
下一章,第六章,数据的检索、处理与存储,将教授我们如何从各种来源(如文件、对象、关系型数据库和 NoSQL 数据库)读取和写入数据的技能。虽然有些人认为这些技能不适用于数据分析,但独立或辅助的数据分析师必须了解如何从不同的文件格式和数据库中获取数据用于分析。
第七章:检索、处理和存储数据
数据无处不在,呈现各种形态和形式。我们可以从网络、物联网传感器、电子邮件、FTP 和数据库中获取数据。我们还可以通过实验室实验、选举民调、市场调查和社会调查等方式收集数据。作为数据专业人员,你应该知道如何处理各种数据集,因为这是一个非常重要的技能。本章将讨论如何检索、处理和存储不同类型的数据。本章概述了如何获取不同格式的数据,如 CSV、Excel、JSON、HDF5、Parquet 和 pickle。
有时候,我们需要在数据分析之前或之后存储或保存数据。我们还将学习如何访问来自关系型和NoSQL(非关系型数据库)数据库的数据,如 sqlite3、MySQL、MongoDB、Cassandra 和 Redis。在 21 世纪的网络世界中,NoSQL 数据库在大数据和 Web 应用程序中正在经历快速增长。它们提供了更灵活、更快速、无需架构的数据库。NoSQL 数据库可以存储各种格式的数据,如文档风格、列式存储、对象、图形、元组或它们的组合。
本章涵盖的主题如下:
-
使用 NumPy 读取和写入 CSV 文件
-
使用 pandas 读取和写入 CSV 文件
-
从 Excel 读取和写入数据
-
从 JSON 读取和写入数据
-
从 HDF5 读取和写入数据
-
从 HTML 表格读取和写入数据
-
从 Parquet 读取和写入数据
-
从
pickle pandas对象读取和写入数据 -
使用
sqlite3进行轻量级访问 -
从 MySQL 读取和写入数据
-
从 MongoDB 读取和写入数据
-
从 Cassandra 读取和写入数据
-
从 Redis 读取和写入数据
-
PonyORM
技术要求
本章有以下技术要求:
-
你可以在以下 GitHub 链接中找到代码和数据集:
github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter06。 -
所有代码块都可以在
ch6.ipynb文件中找到。 -
本章使用以下文件进行实践:CSV 文件(
demo.csv、product.csv、demo_sample_df.csv、my_first_demo.csv和employee.csv)、Excel 文件(employee.xlsx、employee_performance.xlsx和new_employee_details.xlsx)、JSON 文件(employee.json和employee_demo.json)、HTML 文件(country.html)、pickle文件(demo_obj.pkl)、HDF5 文件(employee.h5)和 Parquet 文件(employee.parquet)。 -
本章将使用以下 Python 库:
pandas、pickle、pyarrow、sqlite3、pymysql、mysql-connector、pymongo、cassandra-driver和redis。
使用 NumPy 读取和写入 CSV 文件
在第二章,《NumPy 和 pandas》中,我们详细研究了 NumPy 库并探索了许多功能。NumPy 也有读取和写入 CSV 文件的功能,并能以 NumPy 数组的形式输出结果。genfromtxt()函数将帮助我们读取数据,而savetxt()函数将帮助我们将数据写入文件。由于其两阶段操作,genfromtxt()函数比其他函数慢。第一阶段,它将数据以字符串类型读取,第二阶段,它将字符串类型转换为适当的数据类型。genfromtxt()具有以下参数:
-
fname:字符串;文件名或文件路径。 -
delimiter:字符串;可选,分隔字符串值。默认情况下,它采用连续的空白字符。 -
skip_header:整数;可选,表示要跳过的文件开头的行数。
让我们看一个读取和写入 CSV 文件的例子:
# import genfromtxt function
from numpy import genfromtxt
# Read comma separated file
product_data = genfromtxt('demo.csv', delimiter=',')
# display initial 5 records
print(product_data)
这将产生以下输出:
[[14\. 32\. 33.]
[24\. 45\. 26.]
[27\. 38\. 39.]]
在前面的代码示例中,我们使用 NumPy 模块的genfromtxt()方法读取了demo.csv文件:
# import numpy
import numpy as np
# Create a sample array
sample_array = np.asarray([ [1,2,3], [4,5,6], [7,8,9] ])
# Write sample array to CSV file
np.savetxt("my_first_demo.csv", sample_array, delimiter=",")
在前面的代码示例中,我们使用 NumPy 模块的savetxt()方法写入了my_first_demo.csv文件。
让我们在下一节中看看如何使用pandas模块读取 CSV 文件。
使用 pandas 读取和写入 CSV 文件
pandas库提供了多种文件读取和写入选项。在本节中,我们将学习如何读取和写入 CSV 文件。为了读取 CSV 文件,我们将使用read_csv()方法。让我们看一个例子:
# import pandas
import pandas as pd
# Read CSV file
sample_df=pd.read_csv('demo.csv', sep=',' , header=None)
# display initial 5 records
sample_df.head()
这将产生以下输出:
现在我们可以使用以下代码将数据框保存为 CSV 文件:
# Save DataFrame to CSV file
sample_df.to_csv('demo_sample_df.csv')
在前面的示例代码中,我们使用pandas模块的read_csv()和to_csv(0)方法读取和保存了 CSV 文件。
read_csv()方法有以下重要参数:
-
filepath_or_buffer:提供作为字符串的文件路径或 URL,用于读取文件。 -
sep:提供字符串中的分隔符,例如逗号为',',分号为';'。默认分隔符是逗号','。 -
delim_whitespace:用于空白分隔符的备用参数。它是一个布尔变量。delim_whitespace的默认值为False。 -
header:用于标识列名。默认值为infer。 -
names:可以传递一个列名列表。names的默认值为None。
在pandas中,可以使用to_csv()方法将 DataFrame 导出为 CSV 文件。CSV 文件是逗号分隔值文件。此方法可以仅使用一个参数(文件名作为字符串)运行:
-
path_or_buf:文件将导出的文件路径或位置。 -
sep:用于输出文件的分隔符。 -
header:包含列名或列别名列表(默认值:True)。 -
index:将索引写入文件(默认值:True)。
更多参数和详细描述,请访问pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_csv.html。接下来,我们将看看如何使用pandas模块读取 Excel 文件。
从 Excel 读取和写入数据
Excel 文件是商业领域中广泛使用的文件类型。在 Python 中,Excel 文件可以通过pandas的read_excel()函数轻松读取。read_excel()函数需要传入文件路径和sheet_name参数来读取数据:
# Read excel file
df=pd.read_excel('employee.xlsx',sheet_name='performance')
# display initial 5 records
df.head()
这将产生以下输出:
DataFrame 对象可以写入 Excel 工作表中。我们可以使用to_excel()函数将 DataFrame 对象导出到 Excel 工作表中。通常,to_excel()函数的参数与to_csv()相同,除了sheet_name参数:
df.to_excel('employee_performance.xlsx')
在前面的代码示例中,我们将一个单独的 DataFrame 导出到了 Excel 工作表中。我们还可以将多个 DataFrame 导出到一个文件中,并使用不同的工作表名称。我们还可以使用ExcelWriter在一个 Excel 文件中写入多个 DataFrame(每个 DataFrame 在不同的工作表上),如下所示:
# Read excel file
emp_df=pd.read_excel('employee.xlsx',sheet_name='employee_details')
# write multiple dataframes to single excel file
with pd.ExcelWriter('new_employee_details.xlsx') as writer:
emp_df.to_excel(writer, sheet_name='employee')
df.to_excel(writer, sheet_name='perfromance')
在前面的代码示例中,我们将多个 DataFrame 写入了一个 Excel 文件。这里,每个 DataFrame 存储在不同的工作表上,使用了ExcelWriter函数。接下来,我们将看看如何使用pandas模块读取 JSON 文件。
从 JSON 读取和写入数据
JSON(JavaScript 对象表示法)文件是用于 Web 应用和服务器之间交换数据的广泛使用的格式。它作为数据交换格式,比 XML 更易读。pandas提供了read_json函数来读取 JSON 数据,以及to_json()函数来写入 JSON 数据:
# Reading JSON file
df=pd.read_json('employee.json')
# display initial 5 records
df.head()
这将产生以下输出:
在前面的代码示例中,我们使用read_json()方法读取了 JSON 文件。接下来,我们将看看如何写入一个 JSON 文件:
# Writing DataFrame to JSON file
df.to_json('employee_demo.json',orient="columns")
在前面的代码示例中,我们使用to_json()方法写入了 JSON 文件。在to_json()方法中,orient参数用于处理输出字符串格式。orient提供了 record、column、index 和 value 等格式。你可以在官方网页上查看更多详细信息,网址是:pandas.pydata.org/pandas-docs/version/0.24.2/reference/api/pandas.DataFrame.to_json.html。接下来,我们将进入 HDF5 文件部分,在下一节中,我们将学习如何使用pandas模块读取和写入 HDF5 文件。
从 HDF5 读取和写入数据
HDF 代表 层次化数据格式。HDF 旨在以高性能存储和管理大量数据。它提供了快速的 I/O 处理和异构数据的存储。有多种 HDF 文件格式可用,如 HDF4 和 HDF5。HDF5 与读取和写入 pandas DataFrame 的字典对象相同。它使用 PyTables 库的 read_hdf() 函数来读取 HDF5 文件,使用 to_hdf() 函数来写入:
# Write DataFrame to hdf5
df.to_hdf('employee.h5', 'table', append=True)
在前面的代码示例中,我们使用 to_hdf() 方法写入了 HDF 文件格式。'table' 是用于表格格式的格式参数。表格格式可能会较慢,但提供了更灵活的操作,例如搜索和选择。append 参数用于将输入数据追加到现有数据文件中:
# Read a hdf5 file
df=pd.read_hdf('employee.h5', 'table')
# display initial 5 records
df.head()
这将生成以下输出:
在前面的代码示例中,我们使用 read_hdf() 方法读取了 HDF 文件格式。接下来让我们看看如何从网站读取和写入 HTML 表格。
从 HTML 表格读取和写入数据
HTML 表格将行存储在 <tr>...</tr> 标签中,每行都有相应的 <td>...</td> 单元格来存储值。在 pandas 中,我们还可以从文件或 URL 中读取 HTML 表格。read_html() 函数从文件或 URL 中读取 HTML 表格,并将 HTML 表格返回为 pandas DataFrame 列表:
# Reading HTML table from given URL
table_url = 'https://en.wikipedia.org/wiki/List_of_sovereign_states_and_dependent_territories_in_North_America'
df_list = pd.read_html(table_url)
print("Number of DataFrames:",len(df_list))
这将生成以下输出:
Number of DataFrames: 7
在前面的代码示例中,我们使用 read_html() 方法从给定的网页读取了 HTML 表格。read_html() 将返回所有表格,作为 DataFrame 列表。接下来让我们检查列表中的一个 DataFrame:
# Check first DataFrame
df_list[0].head()
这将生成以下输出:
在前面的代码示例中,我们展示了给定网页上第一个表格的前五条记录。类似地,我们还可以使用 to_html() 将 DataFrame 对象写入 HTML 表格。to_html() 将内容渲染为 HTML 表格:
# Write DataFrame to raw HTML
df_list[1].to_html('country.html')
通过前面的代码示例,我们可以将任何 DataFrame 转换为一个包含 DataFrame 作为表格的 HTML 页面。
从 Parquet 读取和写入数据
Parquet 文件格式为 pandas DataFrame 提供了列式序列化。它在存储和性能方面高效地读取和写入 DataFrame,并且能够在分布式系统之间共享数据而不丢失信息。Parquet 文件格式不支持重复列和数值列。
pandas 使用两个引擎来读取和写入 Parquet 文件:pyarrow 和 fastparquet 引擎。pandas 的默认 Parquet 引擎是 pyarrow;如果 pyarrow 不可用,则使用 fastparquet。在我们的示例中,我们使用的是 pyarrow。让我们使用 pip 安装 pyarrow:
pip install pyarrow
你还可以通过在 pip 关键词前加上 ! 来在 Jupyter Notebook 中安装 pyarrow 引擎。以下是一个示例:
!pip install pyarrow
让我们使用 pyarrow 引擎写入一个文件:
# Write to a parquet file.
df.to_parquet('employee.parquet', engine='pyarrow')
在前面的代码示例中,我们使用to_parquet() Parquet 文件和pyarrow引擎进行写入:
# Read parquet file
employee_df = pd.read_parquet('employee.parquet', engine='pyarrow')
# display initial 5 records
employee_df.head()
这将产生以下输出:
在前面的代码示例中,我们使用read_parquet()和pyarrow引擎读取了 Parquet 文件。read_parquet()有助于读取 Parquet 文件格式。接下来,我们将在下一部分了解如何读取和写入pickle文件中的数据。
从 Pickle pandas 对象中读取和写入数据
在数据准备步骤中,我们将使用各种数据结构,如字典、列表、数组或 DataFrame。有时,我们可能希望将它们保存以备将来参考,或将它们发送给其他人。在这种情况下,pickle对象就派上用场了。pickle将对象序列化以保存它们,并可以随时加载。pandas提供了两个函数:read_pickle()用于加载pandas对象,to_pickle()用于保存 Python 对象:
# import pandas
import pandas as pd
# Read CSV file
df=pd.read_csv('demo.csv', sep=',' , header=None)
# Save DataFrame object in pickle file
df.to_pickle('demo_obj.pkl')
在前面的代码中,我们使用read_csv()方法读取了demo.csv文件,并设置了sep和header参数。在这里,我们将sep设置为逗号,将header设置为None。最后,我们使用to_pickle()方法将数据集写入pickle对象。接下来,让我们看看如何使用pandas库读取pickle对象:
#Read DataFrame object from pickle file
pickle_obj=pd.read_pickle('demo_obj.pkl')
# display initial 5 records
pickle_obj.head()
这将产生以下输出:
在前面的代码中,我们使用read_pickle()方法读取了pickle对象。
使用 sqllite3 轻量级访问
SQLite 是一个开源数据库引擎。它提供了多种特性,如更快的执行速度、轻量级处理、无服务器架构、ACID 兼容性、更少的管理工作、高稳定性和可靠的事务。它是移动设备和计算机世界中最流行、最广泛部署的数据库。它也被称为嵌入式关系型数据库,因为它作为应用程序的一部分运行。SQLite 是一个更轻量的数据库,功能上没有完整的功能。它主要用于存储和处理小型数据,比如移动应用和桌面应用。SQLite 的主要优点是易于使用、高效、轻便,并且可以嵌入到应用程序中。
我们可以使用sqlite3模块在 Python 中读取和写入数据。我们不需要下载和安装sqlite3,因为它已经包含在所有标准 Python 发行版中。使用sqlite3,我们可以将数据库存储在文件中或保存在内存中。sqlite3允许我们使用 SQL 编写任何数据库,而不需要第三方应用程序服务器。让我们通过以下示例了解数据库连接:
# Import sqlite3
import sqlite3
# Create connection. This will create the connection with employee database. If the database does not exist it will create the database
conn = sqlite3.connect('employee.db')
# Create cursor
cur = conn.cursor()
# Execute SQL query and create the database table
cur.execute("create table emp(eid int,salary int)")
# Execute SQL query and Write the data into database
cur.execute("insert into emp values(105, 57000)")
# commit the transaction
con.commit()
# Execute SQL query and Read the data from the database
cur.execute('select * from emp')
# Fetch records
print(cur.fetchall())
# Close the Database connection
conn.close()
Output: [(105, 57000)]
这里,我们使用sqlite3模块。首先,我们导入该模块并使用connect()方法创建一个连接。connect()方法将接收数据库名称和路径;如果数据库不存在,它将使用给定的名称和路径创建该数据库。一旦与数据库建立连接,您需要创建Cursor对象,并使用execute()方法执行 SQL 查询。我们可以在execute()方法中创建表,例如在员工数据库中创建的emp表。类似地,我们可以使用execute()方法和insert查询参数写入数据,并使用commit()方法将数据提交到数据库。也可以通过execute()方法传递select查询作为参数来提取数据,使用fetchall()和fetchone()方法进行提取。fetchone()提取一条记录,fetchall()提取数据库表中的所有记录。
从 MySQL 读取和写入数据
MySQL 是一个快速、开源、易于使用的关系型数据库,适用于小型和大型商业应用。它与数据库驱动的 Web 开发应用非常兼容。Python 中有很多方式可以访问 MySQL 中的数据。像 MySQLdb、mysqlconnector和pymysql等连接器可用于 MySQL 数据库连接。为了实现这种连接,您需要安装 MySQL 关系型数据库和mysql-python连接器。MySQL 的安装详情可以在其官网上找到:www.mysql.com/downloads/。
您可以使用pymysql连接器作为客户端库,可以通过pip安装:
pip install pymysql
我们可以通过以下步骤建立连接:
-
导入库。
-
创建数据库连接。
-
创建游标对象。
-
执行 SQL 查询。
-
获取记录或响应以更新或插入记录。
-
关闭连接。
在我们的示例中,我们尝试使用mysqlconnecter和pymysql进行数据库连接。在运行数据库连接脚本之前,第一步是设计并创建一个数据库,然后在 MySQL 中创建一个表。
让我们使用以下查询来创建一个数据库:
>> create database employee
将数据库更改为员工数据库:
>> use employee
在数据库中创建表:
>> create table emp(eid int, salary int);
现在我们可以插入和获取 MySQL 表中的记录。让我们看一下以下示例来理解数据库连接:
# import pymysql connector module
import pymysql
# Create a connection object using connect() method
connection = pymysql.connect(host='localhost', # IP address of the MySQL database server
user='root', # user name
password='root',# password
db='emp', # database name
charset='utf8mb4', # character set
cursorclass=pymysql.cursors.DictCursor) # cursor type
try:
with connection.cursor() as cur:
# Inject a record in database
sql_query = "INSERT INTO `emp` (`eid`, `salary`) VALUES (%s, %s)"
cur.execute(sql_query, (104,43000))
# Commit the record insertion explicitly.
connection.commit()
with connection.cursor() as cur:
# Read records from employee table
sql_query = "SELECT * FROM `emp`"
cur.execute(sql_query )
table_data = cur.fetchall()
print(table_data)
except:
print("Exception Occurred")
finally:
connection.close()
这里,我们使用pymysql模块。首先,我们导入该模块并创建一个连接。connect()函数将接收主机地址,在我们的案例中是localhost(我们也可以使用远程数据库的 IP 地址)、用户名、密码、数据库名称、字符集和游标类。
在建立连接之后,我们可以读取或写入数据。在我们的例子中,我们使用 insert SQL 查询写入数据,并使用 select 查询检索数据。在插入查询中,我们执行查询并传递要插入数据库的参数,然后使用 commit() 方法将结果提交到数据库。当我们使用选择查询读取记录时,将得到一些记录。我们可以使用 fetchone() 和 fetchall() 函数提取这些记录。fetchone() 方法仅提取单条记录,而 fetchall() 方法则提取数据库表中的多条记录。
还有一件事;在这里,所有的读写操作都在 try 块中执行,连接则在最终块中关闭。我们还可以尝试另一个模块 mysql.connector 来实现 MySQL 和 Python 的连接。它可以通过 pip 安装:
pip install mysql-connector-python
让我们看一个例子来理解数据库连接:
# Import the required connector
import mysql.connector
import pandas as pd
# Establish a database connection to mysql
connection=mysql.connector.connect(user='root',password='root',host='localhost',database='emp')
# Create a cursor
cur=connection.cursor()
# Running sql query
cur.execute("select * from emp")
# Fetch all the records and print it one by one
records=cur.fetchall()
for i in records:
print(i)
# Create a DataFrame from fetched records.
df = pd.DataFrame(records)
# Assign column names to DataFrame
df.columns = [i[0] for i in cur.description]
# close the connection
connection.close()
在前面的代码示例中,我们使用 mysql.connector 模块连接 Python 和 MySQL 数据库,提取数据的方式和步骤与使用 pymysql 模块相同。我们还通过将提取的记录传递到 pandas DataFrame 对象中,并从游标描述中分配列名来写入数据。
将整个 DataFrame 插入数据库
在前面的程序中,使用 insert 命令插入单个记录。如果我们想要插入多个记录,则需要运行一个循环,将多个记录插入数据库。我们还可以使用 to_sql() 函数在一行代码中插入多个记录:
# Import the sqlalchemy engine
from sqlalchemy import create_engine
# Instantiate engine object
en = create_engine("mysql+pymysql://{user}:{pw}@localhost/{db}"
.format(user="root",
pw="root",
db="emp"))
# Insert the whole dataframe into the database
df.to_sql('emp', con=en, if_exists='append',chunksize=1000, index= False)
在前面的代码示例中,我们将为数据库连接创建一个引擎,包含用户名、密码和数据库参数。to_sql() 函数将多个记录从 DataFrame 写入 SQL 数据库。它需要表名、con 参数(用于连接引擎对象)、if_exists 参数(检查数据是追加到新表还是替换为新表),以及 chunksize(用于批量写入数据)。
从 MongoDB 读取和写入数据
MongoDB 是一个面向文档的非关系型(NoSQL)数据库。它使用类似 JSON 的符号,BSON(二进制对象符号)来存储数据。MongoDB 提供以下功能:
-
它是一个免费的、开源的、跨平台的数据库软件。
-
它易于学习,能够构建更快的应用程序,支持灵活的模式,处理多种数据类型,并且具备在分布式环境中扩展的能力。
-
它基于文档的概念工作。
-
它包含数据库、集合、文档、字段和主键。
我们可以通过pymongo连接器在 Python 中从 MongoDB 读取和写入数据。为了实现这个连接,我们需要安装 MongoDB 和pymongo连接器。你可以从其官方网站下载 MongoDB:www.mongodb.com/download-center/community。PyMongo 是一个纯 Python 的 MongoDB 客户端库,可以通过pip安装:
pip install pymongo
让我们尝试使用pymongo进行数据库连接:
# Import pymongo
import pymongo
# Create mongo client
client = pymongo.MongoClient()
# Get database
db = client.employee
# Get the collection from database
collection = db.emp
# Write the data using insert_one() method
employee_salary = {"eid":114, "salary":25000}
collection.insert_one(employee_salary)
# Create a dataframe with fetched data
data = pd.DataFrame(list(collection.find()))
在这里,我们通过创建 Mongo 客户端、插入数据、提取集合详情并将其分配给 DataFrame,尝试从 MongoDB 的数据库集合中提取数据。接下来,我们将展示如何在下一节中使用列式数据库 Cassandra 建立数据库连接。
从 Cassandra 读取和写入数据
Cassandra 是一个可扩展、高可用、耐久和容错的列式数据库,具有较低的管理开销、更快的读写速度,并且能够提供强大的弹性。它容易学习和配置,能够为复杂问题提供解决方案,并且支持跨多个数据中心的复制。许多大型公司,例如苹果、eBay 和 Netflix,都在使用 Cassandra。
我们可以通过cassandra-driver连接器在 Python 中从 Cassandra 读取和写入数据。为了实现这个连接,我们需要安装 Cassandra 和cassandra-driver连接器。你可以从其官方网站下载 Cassandra:cassandra.apache.org/download/。cassandra-driver是一个纯 Python 的 Cassandra 客户端库,可以通过pip安装:
pip install cassandra-driver
让我们尝试使用cassandra-driver进行数据库连接:
# Import the cluster
from cassandra.cluster import Cluster
# Creating a cluster object
cluster = Cluster()
# Create connections by calling Cluster.connect():
conn = cluster.connect()
# Execute the insert query
conn.execute("""INSERT INTO employee.emp_details (eid, ename, age) VALUES (%(eid)s, %(ename)s, %(age)s)""", {'eid':101, 'ename': "Steve Smith", 'age': 42})
# Execute the select query
rows = conn.execute('SELECT * FROM employee.emp_details')
# Print the results
for emp_row in rows:
print(emp_row.eid, emp_row.ename, emp_row.age)
# Create a dataframe with fetched data
data = pd.DataFrame(rows)
在这里,我们通过创建一个集群对象、使用connect()方法建立连接、执行插入操作以及选择查询数据,尝试从 Cassandra 数据库中提取数据。运行查询后,我们打印结果并将提取的记录分配给pandas DataFrame。接下来,让我们进入另一个 NoSQL 数据库:Redis。
从 Redis 读取和写入数据
Redis 是一个开源的 NoSQL 数据库。它是一个键值数据库,存储在内存中,速度极快,并且高可用。它还可以用作缓存或消息代理。内存存储意味着它使用 RAM 来存储数据,并通过虚拟内存处理更大的数据。Redis 提供缓存服务或永久存储。Redis 支持多种数据结构,如字符串、集合、列表、位图、地理空间索引和超日志。Redis 能够处理地理空间、流式数据和时间序列数据。它还可以与云服务如 AWS 和 Google Cloud 一起使用。
我们可以通过 Redis 连接器在 Python 中从 Redis 读取和写入数据。为了实现这个连接,我们需要安装 Redis 和 Redis 连接器。你可以通过以下链接下载 Redis:github.com/rgl/redis/downloads。Redis 是一个纯 Python 的 Redis 客户端库,可以通过pip安装:
pip install redis
让我们尝试使用 Redis 进行数据库连接:
# Import module
import redis
# Create connection
r = redis.Redis(host='localhost', port=6379, db=0)
# Setting key-value pair
r.set('eid', '101')
# Get value for given key
value=r.get('eid')
# Print the value
print(value)
这里,我们尝试从 Redis 键值数据库中提取数据。首先,我们与数据库建立了连接。我们使用 set() 方法将键值对设置到 Redis 数据库中,并且通过给定的键参数使用 get() 方法提取值。
最后,进入本章的最后一个主题,即用于对象关系映射(ORM)的 PonyORM。
PonyORM
PonyORM 是一个强大的 ORM 包,使用纯 Python 编写。它快速、易于使用,并且能以最小的努力执行操作。它提供自动查询优化和图形界面数据库模式编辑器。它还支持自动事务管理、自动缓存和复合键。PonyORM 使用 Python 生成器表达式,这些表达式会被翻译成 SQL。我们可以通过 pip 安装它:
$ pip install pony
让我们来看一个使用 pony 的 ORM 示例:
# Import pony module
from pony.orm import *
# Create database
db = Database()
# Define entities
class Emp(db.Entity):
eid = PrimaryKey(int,auto=True)
salary = Required(int)
# Check entity definition
show(Emp)
# Bind entities to MySQL database
db.bind('mysql', host='localhost', user='root', passwd='12345', db='employee')
# Generate required mappings for entities
db.generate_mapping(create_tables=True)
# turn on the debug mode
sql_debug(True)
# Select the records from Emp entities or emp table
select(e for e in Emp)[:]
# Show the values of all the attribute
select(e for e in Emp)[:].show()
Output:
eid|salary
---+------
104|43000
104|43000
在前面的代码示例中,我们正在执行 ORM。首先,我们创建了一个 Database 对象,并使用 Emp 类定义了实体。接着,我们通过 db.bind() 方法将实体绑定到数据库。我们可以将其绑定到四个数据库:sqlite、mysql、postgresql 和 oracle。在我们的示例中,我们使用 MySQL,并传递其凭证信息,如用户名、密码和数据库名称。我们可以使用 generate_mapping() 来执行实体与数据的映射。create_tables=True 参数在表格不存在时会创建表。sql_debug(True) 会启用调试模式。select() 函数将 Python 生成器翻译成 SQL 查询,并返回一个 pony 对象。这个 pony 对象将通过切片操作符([:])转换为实体列表,show() 函数将以表格形式显示所有记录。
总结
在这一章中,我们学习了如何以不同格式检索、处理和存储数据。我们查看了如何从各种文件格式和来源读取和写入数据,如 CSV、Excel、JSON、HDF5、HTML、pickle、表格和 Parquet 文件。我们还学习了如何从各种关系型和 NoSQL 数据库中读取和写入数据,如 SQLite3、MySQL、MongoDB、Cassandra 和 Redis。
下一章,第七章,清理混乱数据,讲述了数据预处理和特征工程在 Python 中的关键主题。本章从探索性数据分析开始,接着介绍了数据过滤、处理缺失值和异常值。清理之后,将重点讨论数据转换,如编码、缩放和拆分。