Python-数据分析第三版-三-

84 阅读1小时+

Python 数据分析第三版(三)

原文:annas-archive.org/md5/74a7b24994c40ad3a90c290c07b529df

译者:飞龙

协议:CC BY-NC-SA 4.0

第八章:清理杂乱的数据

数据分析师和科学家大部分时间都在清理数据和预处理杂乱的数据集。虽然这项活动较少被讨论,但它是最常执行的活动之一,也是任何数据专业人士必须具备的重要技能。掌握数据清理技巧是每个有抱负的数据科学家必备的技能。数据清理和预处理是识别、更新和删除损坏或不正确数据的过程。清理和预处理的结果是高质量的数据,能够支持强大且无误的分析。优质数据能够击败复杂的算法,并超越简单和不复杂的算法。在这个背景下,高质量意味着准确、完整和一致的数据。数据清理包括处理缺失值、移除异常值、特征编码、缩放、转换和拆分等一系列活动。

本章重点讲解数据清理、处理和整理。数据准备、处理、整理和清洗是同一件事情的不同说法,主要目标是清理数据,以便获得有价值的洞察。我们将从探索员工数据开始,然后过滤数据并处理缺失值和异常值。清理完数据后,我们将集中进行数据转换操作,如编码、缩放和拆分。本章大部分内容将使用pandasscikit-learn

在本章中,我们将涵盖以下主题:

  • 探索数据

  • 过滤数据以剔除噪声

  • 处理缺失值

  • 处理异常值

  • 特征编码技术

  • 特征缩放

  • 特征转换

  • 特征拆分

让我们开始吧!

技术要求

以下是本章的技术要求:

探索数据

在本节中,我们将通过进行探索性数据分析EDA)来探索数据。EDA 是数据分析过程中最关键和最重要的组成部分。EDA 带来以下好处:

  • 它提供了数据及其背景的初步了解。

  • 它可以快速捕捉洞察,并识别出数据中可能影响预测分析的潜在驱动因素。它可以发现那些有助于决策的查询和问题。

  • 它评估数据质量,帮助我们为数据清理和预处理制定路线图。

  • 它可以找到缺失值、异常值,以及分析中各特征的重要性。

  • EDA(探索性数据分析)使用描述性统计和可视化技术来探索数据。

在 EDA 中,第一步是读取数据集。我们可以使用pandas来读取数据集。pandas库提供了多种读取数据的选项。它可以读取多种格式的文件,如 CSV、Excel、JSON、parquet、HTML 和 pickle。所有这些方法在前一章节中都有讲解。读取数据后,我们可以对数据进行探索。这一初步探索将帮助我们理解数据并获得一些领域洞察。让我们开始 EDA 过程吧。

首先,我们将读取employee.csv文件(你可以在本书 GitHub 仓库的Chapter-7文件夹中找到该文件,链接为github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/blob/master/Chapter07/employee.csv):

# import pandas
import pandas as pd

# Read the data using csv
data=pd.read_csv('employee.csv')

让我们使用head()方法查看文件中的前五条记录:

# See initial 5 records
data.head()

这将产生以下输出:

同样,让我们使用head()方法查看文件中的最后五条记录:

# See last 5 records
data.tail()

这将产生以下输出:

我们可以通过使用columns属性查看列的列表:

# Print list of columns in the data
print(data.columns)

这将产生以下输出:

Index(['name', 'age', 'income', 'gender', 'department', 'grade',
 'performance_score'], dtype='object')

让我们通过使用shape属性查看数据框的列列表:

# Print the shape of a DataFrame
print(data.shape)

这将产生以下输出:

(9, 7)

如我们所见,数据集包含9行和7列。

我们可以通过以下代码检查数据框的表模式、列、行、数据类型和缺失值:

# Check the information of DataFrame
data.info()

这将产生以下输出:

在前面的输出中,你可以看到数据中有 7 列。在这 7 列中,有 3 列(年龄、收入和性别)包含缺失值。这 7 列中,4 列是对象类型,2 列是浮动类型,1 列是整数类型。

现在,让我们通过使用describe函数查看数据的描述性统计信息。该函数将描述数值型数据。在我们的例子中,年龄、收入和表现分数将描述计数、均值、标准差、最小值和最大值,以及第一个、第二个和第三个四分位数:

# Check the descriptive statistics
data.describe()

这将产生以下输出:

在前面的代码块中,我们使用describe()函数检查了数据的描述性统计值。从这些结果我们可以解读出员工的年龄范围是从 23 岁到 54 岁。在这里,平均年龄是 40 岁,中位年龄是 45 岁。同样,我们也可以对收入和表现分数得出类似的结论。现在我们已经描述了数据,让我们来学习如何从数据中过滤噪声。

过滤数据以剔除噪声

在过去的二十年里,随着数字化的发展,企业和政府机构的数据量不断增加。这也导致了一致性、错误和缺失值的增加。数据过滤负责处理这些问题,并优化它们以用于管理、报告和预测。过滤过程通过处理脏数据、杂乱无章的数据或粗糙数据集,提升了数据的准确性、相关性、完整性、一致性和质量。这是任何数据管理中非常关键的步骤,因为它能够决定一个企业的竞争优势。数据科学家需要掌握数据过滤的技巧。不同类型的数据需要不同的处理方法。正因如此,数据过滤需要采取系统化的方法。

在上一节中,我们学习了数据探索,而在本节中,我们将学习数据过滤。数据可以按列或按行过滤。我们一一探讨这两种方法。

按列过滤

在这一小节中,我们将学习如何过滤按列排列的数据。我们可以使用filter()方法来过滤列数据。slicing []. filter()方法在列作为列列表传递时选择这些列。看看下面的例子:

# Filter columns
data.filter(['name', 'department'])

这将产生如下输出:

类似地,我们也可以通过切片来过滤列数据。在切片中,单个列不需要列表,但是当我们要过滤多个列时,它们应放在一个列表中。单列的输出是一个 pandas Series。如果我们希望输出为 DataFrame,则需要将单个列的名称放入列表中。看看下面的例子:

# Filter column "name"
data['name']

0       Allen Smith
1           S Kumar
2       Jack Morgan
3         Ying Chin
4     Dheeraj Patel
5     Satyam Sharma
6      James Authur
7        Josh Wills
8          Leo Duck
Name: name, dtype: object

在前面的例子中,我们选择了单个列而没有将其放入列表中,输出是一个 pandas Series。

现在,让我们使用 Python 列表选择单个列:

# Filter column "name"
data[['name']]

这将产生如下输出:

如你所见,单个列可以使用 Python 列表进行选择。此过滤的输出是一个包含单列的 pandas DataFrame。

现在,让我们从 pandas DataFrame 中过滤多个列:

# Filter two columns: name and department
data[['name','department']]

这将产生如下输出:

如你所见,我们在没有使用filter()函数的情况下对两列数据进行了过滤。

按行过滤

现在,让我们来过滤按行排列的数据。我们可以通过索引、切片和条件进行数据过滤。在索引中,你需要传递记录的索引,而在切片中,我们需要传递切片范围。看看下面的例子:

# Select rows for the specific index
data.filter([0,1,2],axis=0)

这将产生如下输出:

在前面的例子中,我们是基于索引来过滤数据的。

以下是通过切片过滤数据的例子:

# Filter data using slicing
data[2:5]

这将产生如下输出:

在基于条件的筛选中,我们必须将一些条件传递给方括号[ ]或圆括号( )。对于单一值,我们使用==(双等于)条件,而对于多个值,我们使用isin()函数并传递值的列表。让我们看一下以下示例:

# Filter data for specific value
data[data.department=='Sales']

这将得到以下输出:

在前面的代码中,我们在代码的第一行使用==(双等于)作为条件筛选了销售部门。现在,让我们使用isin()函数筛选多个列:

# Select data for multiple values
data[data.department.isin(['Sales','Finance'])]

这将得到以下输出:

在前面的例子中,我们使用isin()函数筛选了销售部门和财务部门。

现在,让我们来看一下>=<=条件,适用于连续变量。我们可以使用单个或多个条件。让我们看一下以下示例:

# Filter employee who has more than 700 performance score
data[(data.performance_score >=700)]

这将得到以下输出:

在前面的例子中,我们根据员工的绩效评分(performance_score >=700)进行了筛选。现在,让我们使用多个条件来筛选数据:

# Filter employee who has more than 500 and less than 700 performance score
data[(data.performance_score >=500) & (data.performance_score < 700)]

这将得到以下输出:

我们还可以尝试使用query()方法。这个方法使用布尔表达式查询列。让我们看一个例子:

# Filter employee who has performance score of less than 500
data.query('performance_score<500')

这将得到以下输出:

在前面的例子中,我们筛选了绩效分数低于 500 的员工。现在,让我们学习如何处理缺失值。

处理缺失值

缺失值是数据中缺失的值。缺失值可能由于人为错误、隐私问题,或调查填写者未填写该值而出现。这是数据科学中最常见的问题,也是数据预处理的第一步。缺失值会影响机器学习模型的表现。处理缺失值的方法有以下几种:

  • 删除缺失值记录。

  • 手动填充缺失值。

  • 使用集中趋势的测量值填充缺失值,例如均值、中位数和众数。均值用于填充数值特征,中位数用于填充序数特征,而众数或最高频次值用于填充分类特征。

  • 使用机器学习模型,如回归、决策树、KNN,填充最可能的值。

需要理解的是,在某些情况下,缺失值不会影响数据。例如,驾驶执照号码、社会保障号码或任何其他唯一的身份证号码不会影响机器学习模型,因为它们无法作为模型中的特征使用。

在接下来的子章节中,我们将更详细地了解如何处理缺失值。首先,我们将学习如何删除缺失值。

删除缺失值

在 Python 中,缺失值可以使用 dropna() 函数删除。dropna 接受一个参数:howhow 可以取两个值:allanyany 会删除包含 NAN 或缺失值的某些行,而 all 会删除包含 NAN 或缺失值的所有行:

# Drop missing value rows using dropna() function
# Read the data

data=pd.read_csv('employee.csv')
data=data.dropna()
data

这会产生以下输出:

这将数据集总结为一个数据框。

填充缺失值

在 Python 中,缺失值可以使用 fillna() 函数填充。fillna() 函数接受我们希望填充的值来替代缺失值。我们可以使用均值、中位数和众数来填充缺失值:

# Read the data
data=pd.read_csv('employee.csv')

# Fill all the missing values in the age column with mean of the age column
data['age']=data.age.fillna(data.age.mean())
data

这会产生以下输出:

在前面的示例中,年龄列的缺失值已经使用年龄列的均值填充。接下来我们将学习如何使用中位数填充缺失值:

# Fill all the missing values in the income column with a median of the income column
data['income']=data.income.fillna(data.income.median())
data

这会产生以下输出:

在前面的示例中,收入列的缺失值已经使用收入列的中位数填充。接下来我们将学习如何使用众数填充缺失值:

# Fill all the missing values in the gender column(category column) with the mode of the gender column
data['gender']=data['gender'].fillna(data['gender'].mode()[0])
data

这会产生以下输出:

在前面的代码示例中,性别列的缺失值已经使用性别列的众数进行了填充。正如你所见,均值、中位数和众数帮助我们在 pandas DataFrame 中处理缺失值。在接下来的部分,我们将重点讨论如何处理异常值。

处理异常值

异常值是那些与大多数相似数据点相距较远的数据点——换句话说,我们可以说,异常值是与大多数数据不同的实体。当建立预测模型时,异常值会引发问题,例如训练时间过长、准确度差、误差方差增大、正态性下降,以及统计检验的效能降低。

异常值有两种类型:单变量异常值和多变量异常值。单变量异常值可以在单一变量分布中找到,而多变量异常值可以在 n 维空间中找到。我们可以通过以下方法检测和处理异常值:

  • 箱型图:我们可以使用箱型图通过四分位数生成一组数据点。它将数据点分组在第一四分位数和第三四分位数之间,形成一个矩形框。箱型图还通过四分位距显示异常值作为单独的点。

  • 散点图:散点图在二维图表上展示点(或两个变量)。一个变量放在 x 轴上,另一个变量放在 y 轴上。

  • Z-Score:Z-Score 是一种检测异常值的参数方法。它假设数据服从正态分布。异常值位于正态曲线分布的尾部,远离均值:

  • 四分位距 (IQR):IQR 是一种稳健的统计数据离散度量。它是第三四分位数与第一四分位数之间的差值。这些四分位数可以通过箱线图可视化。这也被称为中间离差、中间 50% 或 H-离差:

  • 百分位数:百分位数是一种统计度量,将数据分为 100 个相等大小的组。它的值表示该值以下的人群百分比。例如,第 95 百分位意味着 95% 的人处于此类别下。

让我们通过标准差和均值来去除一些异常值:

# Dropping the outliers using Standard Deviation
# Read the data
data=pd.read_csv('employee.csv')

# Dropping the outliers using Standard Deviation
upper_limit= data['performance_score'].mean () + 3 * data['performance_score'].std ()
lower_limit = data['performance_score'].mean () - 3 * data['performance_score'].std ()
data = data[(data['performance_score'] < upper_limit) & (data['performance_score'] > lower_limit)]
data

这将产生以下输出:

在上面的例子中,我们使用标准差和均值来处理异常值。我们使用 作为上限,并使用 作为下限来筛选异常值。我们也可以尝试使用百分位数来去除异常值。让我们看一下以下示例:

# Read the data
data=pd.read_csv('employee.csv')

# Drop the outlier observations using Percentiles
upper_limit = data['performance_score'].quantile(.99)
lower_limit = data['performance_score'].quantile(.01)
data = data[(data['performance_score'] < upper_limit) & (data['performance_score'] > lower_limit)]
data

这将产生以下输出:

在上面的代码示例中,我们通过使用百分位数来处理异常值。我们通过使用 1 的百分位数作为下限,99 的百分位数作为上限来去除异常值。这有助于我们处理 pandas DataFrame 中的异常值。在接下来的部分,我们将重点介绍如何进行特征编码。

特征编码技术

机器学习模型是数学模型,需要数值型和整数型数据进行计算。此类模型无法处理类别特征。因此,我们通常需要将类别特征转换为数值型特征。机器学习模型的性能受我们使用的编码技术的影响。类别值的范围从 0 到 N-1 类。

One-hot 编码

One-hot 编码将类别列转换为标签,并将该列拆分为多个列。数字会被二进制值如 1 或 0 替代。例如,假设在 color 变量中有三类,即 redgreenblue。这三类将被标记并编码为二进制列,如下图所示:

One-hot 编码也可以使用 get_dummies() 函数进行。我们以 get_dummies() 函数为例:

# Read the data
data=pd.read_csv('employee.csv')
# Dummy encoding
encoded_data = pd.get_dummies(data['gender'])

# Join the encoded _data with original dataframe
data = data.join(encoded_data)

# Check the top-5 records of the dataframe
data.head()

这将产生以下输出:

在这里,我们可以看到两个额外的列,F 和 M。这两列是布尔编码器添加的虚拟列。我们也可以使用 scikit-learn 模块中的 OneHotEncoder 来执行相同的任务。让我们看一下使用 OneHotEncoder 的示例:

# Import one hot encoder
from sklearn.preprocessing import OneHotEncoder

# Initialize the one-hot encoder object
onehotencoder = OneHotEncoder()

# Fill all the missing values in income column(category column) with mode of age column
data['gender']=data['gender'].fillna(data['gender'].mode()[0])

# Fit and transforms the gender column
onehotencoder.fit_transform(data[['gender']]).toarray()

这将产生以下输出:

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

在前面的代码示例中,我们导入了OneHotEncoder,初始化了它的对象,然后对性别列进行了拟合和转换。我们可以看到,输出数组为女性和男性员工各有一列。

标签编码

标签编码也被称为整数编码。整数编码将分类值替换为数值。在这里,变量中的唯一值被替换为一系列整数值。例如,假设有三个类别:红色、绿色和蓝色。这三个类别已经用整数值进行了编码;也就是说,red是 0,green是 1,blue是 2。

让我们来看一个标签编码的例子:

# Import pandas
import pandas as pd

# Read the data
data=pd.read_csv('employee.csv')

# Import LabelEncoder
from sklearn.preprocessing import LabelEncoder

# Instantiate the Label Encoder Object
label_encoder = LabelEncoder()

# Fit and transform the column
encoded_data = label_encoder.fit_transform(data['department'])

# Print the encoded
print(encoded_data)

这将产生以下输出:

[2 1 0 0 2 1 2 1 0 2]

在前面的例子中,我们进行了简单的标签编码。

在以下例子中,我们使用LabelEncoder类对部门列进行编码。首先,我们必须导入并初始化LabelEncoder对象,然后拟合并转换我们想要编码的列。让我们对已编码的标签执行反向转换:

# Perform inverse encoding
inverse_encode=label_encoder.inverse_transform([0, 0, 1, 2])

# Print inverse encode
print(inverse_encode)

这将产生以下输出:

['Finance' 'Finance' 'Operations' 'Sales']

在前面的例子中,我们使用inverse_transformation()方法反转了已编码值的编码。我们还可以对数值变量使用独热编码。在这里,每个唯一的数值都被编码为一个等效的二进制变量。

序数编码器

序数编码与标签编码类似,唯一的区别是编码是有顺序的。输出编码从 0 开始,到类别数量减 1 为止。我们来看一个包含员工等级的例子,例如 G0、G1、G2、G3 和 G4。这五个等级已经用序数整数值进行了编码;也就是说,G0是 0,G1是 1,G2是 2,G3是 3,G4是 4。我们可以将值的顺序定义为一个列表,并将其传递给类别参数。序数编码器使用整数或数值来进行编码。在这里,整数和数值是有序的。这种编码有助于机器学习算法利用这种序数关系。

让我们来看一个OrdinalEncoder的例子:

# Import pandas and OrdinalEncoder
import pandas as pd
from sklearn.preprocessing import OrdinalEncoder

# Load the data
data=pd.read_csv('employee.csv')

# Initialize OrdinalEncoder with order
order_encoder=OrdinalEncoder(categories=['G0','G1','G2','G3','G4'])

# fit and transform the grade
data['grade_encoded'] = label_encoder.fit_transform(data['grade'])

# Check top-5 records of the dataframe
data.head()

这将产生以下输出:

前面的例子与LabelEncoder的例子类似,唯一的区别是在初始化OrdinalEncoder对象时传递的值的顺序。在这个例子中,categories参数与grade顺序一起在初始化时传递。

特征缩放

在现实生活中,大多数特征有不同的范围、大小和单位,比如年龄在 0 到 200 之间,薪资从几千到几百万不等。从数据分析师或数据科学家的角度来看,当这些特征处于不同的尺度时,我们如何进行比较呢?大规模的特征会在机器学习模型中比小规模的特征权重更大。幸运的是,特征缩放或特征归一化可以解决这些问题。

特征缩放将所有特征的量级调整到相同水平。这对于所有类型的算法并非强制性的;有些算法显然需要缩放数据,例如那些依赖于欧几里得距离度量的算法,如 K 近邻算法和 K-means 聚类算法。

特征缩放方法

现在,让我们来看一下我们可以使用的各种特征缩放方法:

  • 标准化缩放或 Z 得分归一化:该方法通过使用特征的均值和标准差来计算特征的缩放值。它最适用于正态分布的数据。假设![]是特征列的均值,![]是标准差。这将导致以下公式:

让我们来看一下以下的标准化缩放示例:

# Import StandardScaler(or z-score normalization)
from sklearn.preprocessing import StandardScaler

# Initialize the StandardScaler
scaler = StandardScaler()

# To scale data
scaler.fit(data['performance_score'].values.reshape(-1,1))
data['performance_std_scaler']=scaler.transform(data['performance_score'].values.reshape(-1,1))
data.head()

这将产生以下输出:

在这里,我们需要导入并初始化StandardScaler对象。初始化后,我们必须对要缩放的列执行拟合和转换操作。

  • 最小-最大缩放:该方法将原始数据线性转换为给定范围。它保留了缩放数据与原始数据之间的关系。如果分布不是正态分布,并且标准差值非常小,则最小-最大缩放器效果更好,因为它对异常值更为敏感。假设![]是特征列的最小值,![]是最大值,而是新的最小值和最大值。这将导致以下公式:

让我们来看一下以下的最小-最大缩放示例:

# Import MinMaxScaler
from sklearn.preprocessing import MinMaxScaler

# Initialise the MinMaxScaler
scaler = MinMaxScaler()

# To scale data
scaler.fit(data['performance_score'].values.reshape(-1,1))
data['performance_minmax_scaler']=scaler.transform(data['performance_score'].values.reshape(-1,1))
data.head()

这将产生以下输出:

在这里,我们需要导入并初始化MinMaxScaler对象。初始化后,我们必须对要缩放的列执行拟合和转换操作。

  • 鲁棒缩放:该方法类似于最小-最大缩放方法。与最小-最大不同,使用的是四分位数范围。因此,它对异常值具有鲁棒性。假设是 x 列的第一四分位数和第三四分位数。这将导致以下公式:

让我们来看一下以下的鲁棒缩放示例:

# Import RobustScaler
from sklearn.preprocessing import RobustScaler

# Initialise the RobustScaler
scaler = RobustScaler()

# To scale data
scaler.fit(data['performance_score'].values.reshape(-1,1))
data['performance_robust_scaler']=scaler.transform(data['performance_score'].values.reshape(-1,1))

# See initial 5 records
data.head()

这将产生以下输出:

在这里,我们需要导入并初始化RobustScaler对象。初始化后,我们必须对要缩放的列进行拟合和转换操作。

特征变换

特征变换改变特征的形式,使其符合要求。它还减少了异常值的影响,处理了偏态数据,并使模型更加稳健。以下是不同类型的特征变换:

  • 对数变换是最常用的数学变换,用于将偏态数据转换为正态分布。在应用对数变换之前,确保所有数据值仅包含正值;否则,这会抛出异常或错误信息。

  • 平方和立方变换对分布形状有中等的影响。它可以用于减少左偏。

  • 平方和立方根变换对分布形状有相当强的变换效果,但其效果比对数变换弱。它可以应用于右偏数据。

  • 离散化也可以用来转换数字列或属性。例如,一组候选人的年龄可以分组为 0-10 岁、11-20 岁等区间。我们还可以使用离散化来分配概念标签,而不是区间,例如青年、成人和老年。

如果特征是右偏或正偏,或者在较低值处聚集,那么我们可以应用平方根、立方根和对数变换;而如果特征是左偏或负偏,或者在较高值处聚集,那么我们可以应用立方、平方等变换。

让我们看一个离散化变换的例子:

# Read the data
data=pd.read_csv('employee.csv')

# Create performance grade function
def performance_grade(score):
    if score>=700:
        return 'A'
    elif score<700 and score >= 500:
        return 'B'
    else:
        return 'C'

# Apply performance grade function on whole DataFrame using apply() function.
data['performance_grade']=data.performance_score.apply(performance_grade)

# See initial 5 records
data.head()

这会产生以下输出:

在前面的例子中,我们加载了数据集并创建了performance_grade()函数。performance_grade()函数接受表现分数并将其转换为等级;即ABC

特征拆分

特征拆分帮助数据分析师和数据科学家为建模创造更多的新特征。它使机器学习算法能够理解特征并揭示决策过程中的潜在信息;例如,将姓名特征拆分为名、中间名和姓,或将地址拆分为门牌号、地区、地标、区域、城市、国家和邮政编码。

诸如字符串和日期列之类的复合特征违反了整洁数据原则。如果你希望从复合特征中生成更多特征,特征拆分是一个不错的选择。我们可以利用列的组件来做到这一点。例如,从一个日期对象中,我们可以轻松获得年份、月份和星期几。这些特征可能直接影响预测模型。拆分特征成组件时没有固定规则;这取决于特征的具体特点:

# Split the name column in first and last name
data['first_name']=data.name.str.split(" ").map(lambda var: var[0])
data['last_name']=data.name.str.split(" ").map(lambda var: var[1])

# Check top-5 records
data.head()

这会产生以下输出:

在前面的示例中,我们使用 split()map() 函数拆分了姓名列。split() 函数使用空格拆分姓名列,而 map() 函数将拆分后的第一个字符串分配给名字,将第二个字符串分配给姓氏。

总结

在本章中,我们探讨了使用 Python 进行数据预处理和特征工程。这帮助你获得了数据分析中重要的技能。本章的主要重点是清理和过滤脏数据。我们从 EDA(探索性数据分析)开始,讨论了数据过滤、处理缺失值和异常值。之后,我们重点介绍了特征工程任务,如数据变换、特征编码、特征缩放和特征分割。接着,我们探索了可以用于特征工程的各种方法和技术。

在下一章,第八章,信号处理与时间序列,我们将重点讨论信号处理和时间序列数据在 Python 中的重要性。我们将从分析时间序列数据开始,讨论移动平均、自相关、回归模型和 ARMA 模型。然后,我们将研究信号处理,讨论傅里叶变换、谱变换以及信号的滤波。

第九章:信号处理与时间序列

信号处理是电气工程和应用数学的一个子领域。它涵盖了时间相关变量或随时间变化的变量的分析和处理,例如模拟信号和数字信号。模拟信号是非数字化的信号,例如广播或电话信号。数字信号是数字化的、离散的、按时间采样的信号,例如计算机和数字设备信号。时间序列分析是信号处理的一个类别,处理的是有序或按顺序排列的观察列表。这些数据可以按小时、日、周、月或年排序。时间序列中的时间因素非常重要。我们需要提取数据中所有与时间相关的关系。与时间序列分析相关的例子有很多,例如产品的生产和销售、按小时或每天预测股价、经济预测和人口普查分析。

在本章中,我们的主要关注点是使用 NumPy、SciPy、pandasstatsmodels库进行信号处理和时间序列操作。本章将对数据分析师理解趋势和模式,以及预测销售、股价、生产、人口、降水量和气温等有所帮助。

本章将涵盖以下主题:

  • statsmodels模块

  • 移动平均

  • 窗口函数

  • 定义协整

  • STL 分解

  • 自相关

  • 自回归模型

  • ARMA 模型

  • 生成周期信号

  • 傅里叶分析

  • 谱分析滤波

技术要求

本章有以下技术要求:

statsmodels 模块

statsmodels是一个开源的 Python 模块,提供了多种统计操作的功能,例如中心值(均值、众数和中位数)、离散度量(标准差和方差)、相关性和假设检验。

让我们使用pip安装statsmodels并运行以下命令:

pip3 install statsmodels

statsmodels提供了statsmodels.tsa子模块用于时间序列操作。statsmodels.tsa提供了有用的时间序列方法和技术,例如自回归、 autocorrelation、部分自相关、移动平均、简单指数平滑、霍尔特线性法、霍尔特-温特斯法、ARMA、ARIMA、向量自回归VAR)模型和许多助手函数,我们将在接下来的章节中探讨这些。

移动平均

移动平均或滚动均值是时间序列滤波器,通过对一组或窗口的观测值进行平均,滤除冲动响应。它使用窗口大小的概念,并计算每个周期连续窗口滑动的平均值。简单移动平均可以表示如下:

有多种类型的移动平均可用,例如居中、双重和加权移动平均。让我们使用rolling()函数找到移动平均值,但在此之前,我们将首先加载数据并可视化:

# import needful libraries
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt

# Read dataset
sales_data = pd.read_csv('sales.csv')

# Setting figure size
plt.figure(figsize=(10,6))

# Plot original sales data
plt.plot(sales_data['Time'], sales_data['Sales'], label="Sales-Original")

# Rotate xlabels
plt.xticks(rotation=60)

# Add legends
plt.legend()

#display the plot
plt.show()

这将产生以下输出:

在前面的代码中,我们读取了 2017 年 1 月到 2019 年 12 月 36 个月的销售数据,并使用 Matplotlib 绘制了图表。现在,我们将使用滚动函数计算移动平均值:

# Moving average with window 3
sales_data['3MA']=sales_data['Sales'].rolling(window=3).mean()

# Moving average with window 5
sales_data['5MA']=sales_data['Sales'].rolling(window=5).mean()

# Setting figure size
plt.figure(figsize=(10,6))

# Plot original sales data
plt.plot(sales_data['Time'], sales_data['Sales'], label="Sales-Original", color="blue")

# Plot 3-Moving Average of sales data
plt.plot(sales_data['Time'], sales_data['3MA'], label="3-Moving Average(3MA)", color="green")

# Plot 5-Moving Average of sales data
plt.plot(sales_data['Time'], sales_data['5MA'], label="5-Moving Average(5MA)", color="red")

# Rotate xlabels
plt.xticks(rotation=60)

# Add legends
plt.legend()

# Display the plot
plt.show()

这将产生以下输出:

在前面的代码中,我们使用滚动均值计算了 3 和 5 的移动平均值,并使用 Matplotlib 显示了线形图。现在,让我们在下一节中看看不同类型的移动平均窗口函数。

窗口函数

NumPy 提供了多种窗口选项,可以计算滚动窗口中的权重,正如我们在前一节中所做的那样。

窗口函数用于光谱分析和滤波器设计的间隔(更多背景信息,请参见en.wikipedia.org/wiki/Window_function)。箱型窗口是一个矩形窗口,其公式如下:

w(n) = 1

三角窗口的形状像一个三角形,其公式如下:

在这里,L可以等于NN+1 或N–1。

如果L的值为N–1,则称为 Bartlett 窗口,其公式如下:

pandas模块中,DataFrame.rolling()函数使用win_type参数提供相同的功能,以实现不同的窗口函数。另一个参数是窗口,用于定义窗口的大小,如前一节所示,这非常容易设置。让我们使用win_type参数并尝试不同的窗口函数:

# import needful libraries
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt

# Read dataset
sales_data = pd.read_csv('sales.csv', index_col ="Time")

# Apply all the windows on given DataFrame
sales_data['boxcar']=sales_data.Sales.rolling(3, win_type ='boxcar').mean()
sales_data['triang']=sales_data.Sales.rolling(3, win_type ='triang').mean()
sales_data['hamming']=sales_data.Sales.rolling(3, win_type ='hamming').mean()
sales_data['blackman']=sales_data.Sales.rolling(3, win_type ='blackman').mean()

#Plot the rolling mean of all the windows
sales_data.plot(kind='line',figsize=(10,6))

这将产生以下输出:

在前面的代码块中,我们使用rolling()函数中的win_type参数绘制了不同窗口函数的滚动均值,如箱型、三角形、汉明窗口和布莱克曼窗口。现在,让我们学习如何使用协整找到两个时间序列之间的相关性。

定义协整

协整就像是相关性,可以看作是定义两个时间序列相关性的更优指标。协整是两个时间序列线性组合的平稳行为。这样,以下方程的趋势必须是平稳的:

y(t) - a x(t)

想象一个醉汉带着他的狗在散步。相关性告诉我们他们是否朝同一方向走。协整则告诉我们男人与狗之间的距离随时间的变化。我们将使用随机生成的时间序列和实际数据来展示协整。增强型迪基-福勒ADF)检验用于检验时间序列中的单位根,并可用来判断时间序列的平稳性。

让我们通过一个例子来理解两个时间序列的协整。

你可以通过以下 GitHub 链接查看完整的代码:github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/blob/master/Chapter08/Ch8.ipynb

让我们开始协整演示:

  1. 导入所需的库并定义以下函数来计算 ADF 统计量:
# Import required library
import statsmodels.api as sm
import pandas as pd
import statsmodels.tsa.stattools as ts
import numpy as np

# Calculate ADF function 
def calc_adf(x, y):
    result = sm.OLS(x, y).fit()
    return ts.adfuller(result.resid)
  1. 将太阳黑子数据加载到一个 NumPy 数组中:
# Read the Dataset
data = sm.datasets.sunspots.load_pandas().data.values
N = len(data)
  1. 生成一个正弦波并计算正弦与自身的协整:
# Create Sine wave and apply ADF test  
t = np.linspace(-2 * np.pi, 2 * np.pi, N)
sine = np.sin(np.sin(t))
print("Self ADF", calc_adf(sine, sine))

代码应该打印以下内容:

Self ADF (-5.0383000037165746e-16, 0.95853208606005591, 0, 308,
{'5%': -2.8709700936076912, '1%': -3.4517611601803702, '10%':
-2.5717944160060719}, -21533.113655477719)

在打印的结果中,第一个值代表 ADF 指标,第二个值代表 p 值。如你所见,p 值非常高。接下来的值为滞后和样本大小。最后的字典给出了此样本大小对应的 t 分布值。

  1. 现在,给正弦波加入噪声,以演示噪声如何影响信号:
# Apply ADF test on Sine and Sine with noise 
noise = np.random.normal(0, .01, N)
print("ADF sine with noise", calc_adf(sine, sine + noise))

有了噪声,我们得到以下结果:

ADF sine with noise (-7.4535502402193075, 5.5885761455106898e- 11, 3, 305, {'5%': -2.8710633193086648, '1%': -3.4519735736206991, '10%': -2.5718441306100512}, -1855.0243977703672)

p 值已经大幅下降。这里的 ADF 指标-7.45低于字典中的所有临界值。所有这些都是强有力的理由来拒绝协整。

  1. 让我们生成一个幅度更大的余弦并进行偏移。再次,加入噪声:
# Apply ADF test on Sine and Cosine with noise 
cosine = 100 * np.cos(t) + 10

print("ADF sine vs cosine with noise", calc_adf(sine, cosine + noise))

以下值将被打印出来:

ADF sine vs cosine with noise (-17.927224617871534, 2.8918612252729532e-30, 16, 292, {'5%': -2.8714895534256861, '1%': -3.4529449243622383, '10%': -2.5720714378870331}, -11017.837238220782) 

同样,我们有充分的理由拒绝协整。检查正弦与太阳黑子之间的协整,得到以下输出:

print("Sine vs sunspots", calc_adf(sine, data))

以下值将被打印出来:

Sine vs sunspots (-6.7242691810701016, 3.4210811915549028e-09, 16, 292,
{'5%': -2.8714895534256861, '1%': -3.4529449243622383, 
'10%': -2.5720714378870331}, -1102.5867415291168)

这里使用的配对的置信水平大致相同,因为它们依赖于数据点的数量,而这一点变化不大。结果总结在以下表格中:

配对统计量p 值5%1%10%拒绝
自身的正弦-5.03E-160.95-2.87-3.45-2.57
噪声影响下的正弦与正弦-7.455.58E-11-2.87-3.45-2.57
噪声影响下的正弦与余弦-17.922.89E-30-2.87-3.45-2.57
正弦与太阳黑子-6.723.42E-09-2.87-3.45-2.57

在前面的表格中,汇总了所有四个正弦波的结果,并讨论了它们的显著性水平以及拒绝/接受的标准。现在让我们进入本章的另一个重要话题,即任何时间序列的 STL 分解。

STL 分解

STL 代表 季节性 和趋势分解 使用 LOESS。STL 是一种时间序列分解方法,可以将观测信号分解为趋势、季节性和残差。它能够估计非线性关系并处理任何类型的季节性。statsmodels.tsa.seasonal子包提供了seasonal_decompose方法,用于将给定的输入信号分解为趋势、季节性和残差。

让我们看以下示例来理解 STL 分解:

# import needful libraries
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose

# Read the dataset
data = pd.read_csv('beer_production.csv')
data.columns= ['date','data']

# Change datatype to pandas datetime
data['date'] = pd.to_datetime(data['date'])
data=data.set_index('date')

# Decompose the data
decomposed_data = seasonal_decompose(data, model='multiplicative')

# Plot decomposed data
decomposed_data.plot()

# Display the plot
plt.show()

这将产生以下输出:

在前面的代码块中,给定的时间序列信号通过statsmodels模块的seasonal_decompose()函数被分解为趋势、季节性和残差组件。现在让我们跳到自相关,理解时间序列与其滞后序列之间的关系。

自相关

自相关,或滞后相关,是时间序列与其滞后序列之间的相关性。它指示数据集中的趋势。自相关公式可以定义如下:

我们可以使用 NumPy 的correlate()函数来计算日冕周期的实际自相关。我们还可以直接使用autocorrelation_plot()函数可视化自相关图。让我们计算自相关并可视化它:

# import needful libraries
import pandas as pd
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt

# Read the dataset
data = sm.datasets.sunspots.load_pandas().data

# Calculate autocorrelation using numpy
dy = data.SUNACTIVITY - np.mean(data.SUNACTIVITY)
dy_square = np.sum(dy ** 2)

# Cross-correlation
sun_correlated = np.correlate(dy, dy, mode='full')/dy_square
result = sun_correlated[int(len(sun_correlated)/2):]

# Diplay the Chart
plt.plot(result)

# Display grid
plt.grid(True)

# Add labels
plt.xlabel("Lag")

plt.ylabel("Autocorrelation")
# Display the chart
plt.show()

这将产生以下输出:

在前面的代码块中,我们使用 NumPy 模块看到了一个自相关示例。现在让我们计算由pandas生成的自相关图:

from pandas.plotting import autocorrelation_plot

# Plot using pandas function
autocorrelation_plot(data.SUNACTIVITY)

这将产生以下输出:

在前面的代码块中,我们使用pandas库的autocorrelation_plot()函数生成了自相关图。与 NumPy 库相比,使用pandas库更容易绘制自相关图。现在让我们跳到自回归模型进行时间序列预测。

自回归模型

自回归模型是用于预测未来事件的时间序列模型。以下公式展示了这一点:

在前面的公式中,c是常数,最后一项是随机成分,也称为白噪声。

让我们使用statsmodels.tsa子包构建自回归模型:

  1. 导入库并读取数据集:
# import needful libraries
from statsmodels.tsa.ar_model import AR
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
import statsmodels.api as sm
from math import sqrt

# Read the dataset
data = sm.datasets.sunspots.load_pandas().data
  1. 将日冕数据拆分为训练集和测试集:
# Split data into train and test set
train_ratio=0.8

train=data[:int(train_ratio*len(data))]
test=data[int(train_ratio*len(data)):]
  1. 训练并拟合自回归模型:
# AutoRegression Model training
ar_model = AR(train.SUNACTIVITY)
ar_model = ar_model.fit()

# print lags and
print("Number of Lags:", ar_model.k_ar)
print("Model Coefficients:\n", ar_model.params)

这将产生以下输出:

Number of Lags: 15
Model Coefficients:
const            9.382322
L1.SUNACTIVITY   1.225684
L2.SUNACTIVITY  -0.512193
L3.SUNACTIVITY  -0.130695
L4.SUNACTIVITY   0.193492
L5.SUNACTIVITY  -0.168907
L6.SUNACTIVITY   0.054594
L7.SUNACTIVITY  -0.056725
L8.SUNACTIVITY   0.109404
L9.SUNACTIVITY   0.108993
L10.SUNACTIVITY -0.117063
L11.SUNACTIVITY  0.200454
L12.SUNACTIVITY -0.075111
L13.SUNACTIVITY -0.114437
L14.SUNACTIVITY  0.177516
L15.SUNACTIVITY -0.091978
dtype: float64

在前面的代码中,我们读取了 Sunspot 数据集并将其分成了两部分:训练集和测试集。然后,我们通过创建实例并拟合模型构建了自回归模型。接下来,我们进行预测并评估模型的性能。

  1. 进行预测并评估模型:
# make predictions
start_point = len(train)
end_point = start_point + len(test)-1
pred = ar_model.predict(start=start_point, end=end_point, dynamic=False)

# Calculate errors
mae = mean_absolute_error(test.SUNACTIVITY, pred)
mse = mean_squared_error(test.SUNACTIVITY, pred)
rmse = sqrt(mse)
print("MAE:",mae)
print("MSE:",mse)
print("RMSE:",rmse)

这将产生以下输出:

MAE: 31.17846098350052
MSE: 1776.9463826165913
RMSE: 42.15384184883498

在前面的代码块中,我们对测试数据集进行了预测,并使用平均绝对误差MAE)、均方误差MSE)和均方根误差RMSE)评估了模型的性能。接下来,我们绘制原始序列和预测序列的折线图。

  1. 让我们绘制预测序列和原始序列,以便更好地理解预测结果:
# Setting figure size
plt.figure(figsize=(10,6))

# Plot test data
plt.plot(test.SUNACTIVITY, label='Original-Series')

# Plot predictions
plt.plot(pred, color='red', label='Predicted Series')

# Add legends
plt.legend()

# Display the plot
plt.show()

这将产生以下输出:

在前面的图中,我们可以看到使用自回归模型得到的原始序列和预测序列。在生成了自回归模型后,我们需要进入时间序列预测的另一个高级方法——自回归移动平均ARMA)。

ARMA 模型

ARMA 模型结合了自回归和移动平均。ARMA 模型通常称为 ARMA(p,q),其中p是自回归部分的阶数,q是移动平均部分的阶数:

在前面的公式中,就像在自回归模型公式中一样,我们有一个常数项和一个白噪声分量;但是,我们还尝试拟合滞后的噪声分量:

  1. 导入库并读取数据集:
# import needful libraries
import statsmodels.api as sm
from statsmodels.tsa.arima_model import ARMA
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
from math import sqrt

# Read the dataset
data = sm.datasets.sunspots.load_pandas().data
data.drop('YEAR',axis=1,inplace=True)
  1. 将 Sunspot 数据集分成训练集和测试集:
# Split data into train and test set
train_ratio=0.8
train=data[:int(train_ratio*len(data))]
test=data[int(train_ratio*len(data)):]
  1. 训练并拟合自回归模型:
# AutoRegression Model training
arma_model = ARMA(train, order=(10,1))
arma_model = arma_model.fit()
  1. 进行预测并评估模型:
# make predictions
start_point = len(train)
end_point = start_point + len(test)-1
pred = arma_model.predict(start_point,end_point)

# Calculate errors
mae = mean_absolute_error(test.SUNACTIVITY, pred)
mse = mean_squared_error(test.SUNACTIVITY, pred)
rmse = sqrt(mse)
print("MAE:",mae)
print("MSE:",mse)
print("EMSE:",rmse)

这将产生以下输出:

MAE: 33.95457845540467
MSE: 2041.3857010355755
EMSE: 45.18169652675268
  1. 让我们绘制预测序列和原始序列,以便更好地理解预测结果:
# Setting figure size
plt.figure(figsize=(10,6))

# Plot test data
plt.plot(test, label='Original-Series')

# Plot predictions
plt.plot(pred, color='red', label='Predicted Series')

# Add legends
plt.legend()

# Display the plot
plt.show()

这将产生以下输出:

在前面的代码中,我们读取了 Sunspot 数据集并将其分成了两部分:训练集和测试集。然后,我们通过创建实例并拟合模型构建了 ARMA 模型。我们对测试数据集进行了预测,并使用 MAE、MSE 和 RMSE 评估了模型性能。最后,我们查看了原始序列和预测序列的折线图。接下来,我们将讨论另一个重要主题——生成周期性信号。

生成周期性信号

许多自然现象是规律和可靠的,比如准确的时钟。有些现象展现出看似规律的模式。一组科学家发现,利用 Hilbert-Huang 变换(参见en.wikipedia.org/wiki/Hilbert%E2%80%93Huang_transform)可以发现太阳黑子活动有三个周期,分别为大约 11 年、22 年和 100 年。通常,我们会使用三角函数,如正弦函数,来模拟周期信号。你可能记得高中时学过一点三角学。对于这个例子来说,这些知识就足够了。因为我们有三个周期,所以看起来合理的是创建一个由三个正弦函数线性组合而成的模型。这只需要对自回归模型的代码进行一点小的调整:

  1. 创建模型、误差和拟合函数:
# Import required libraries
import numpy as np
import statsmodels.api as sm
from scipy.optimize import leastsq
import matplotlib.pyplot as plt

# Create model function
def model(p, t):
    C, p1, f1, phi1 , p2, f2, phi2, p3, f3, phi3 = p
    return C + p1 * np.sin(f1 * t + phi1) + p2 * np.sin(f2 * t + phi2) +p3 * np.sin(f3 * t + phi3)

# Create error function
def error(p, y, t):
    return y - model(p, t)

# Create fit function
def fit(y, t):
    p0 = [y.mean(), 0, 2 * np.pi/11, 0, 0, 2 * np.pi/22, 0, 0, 2 * np.pi/100, 0]
    params = leastsq(error, p0, args=(y, t))[0]
    return params
  1. 让我们加载数据集:
# Load the dataset
data_loader = sm.datasets.sunspots.load_pandas()
sunspots = data_loader.data["SUNACTIVITY"].values
years = data_loader.data["YEAR"].values
  1. 应用并拟合模型:
# Apply and fit the model
cutoff = int(.9 * len(sunspots))
params = fit(sunspots[:cutoff], years[:cutoff])
print("Params", params)

pred = model(params, years[cutoff:])
actual = sunspots[cutoff:]
  1. 打印结果:
print("Root mean square error", np.sqrt(np.mean((actual - pred) ** 2)))
print("Mean absolute error", np.mean(np.abs(actual - pred)))
print("Mean absolute percentage error", 100 *
np.mean(np.abs(actual - pred)/actual))
mid = (actual + pred)/2
print("Symmetric Mean absolute percentage error", 100 *
       np.mean(np.abs(actual - pred)/mid))
print("Coefficient of determination", 1 - ((actual - pred) 
        **2).sum()/ ((actual - actual.mean()) ** 2).sum())

这将产生以下输出:

Params [47.1880006  28.89947462   0.56827279 6.51178464  4.55214564
 0.29372076 -14.30924768 -18.16524123 0.06574835 -4.37789476]
Root mean square error 59.56205597915569
Mean absolute error 44.58158470150657
Mean absolute percentage error 65.16458348768887
Symmetric Mean absolute percentage error 78.4480696873044
Coefficient of determination -0.3635315489903188

第一行显示了我们尝试的模型的系数。我们的 MAE 是 44,意味着我们平均偏离这个值无论是正向还是反向。我们还希望决定系数尽可能接近 1,这样拟合效果才好。然而,我们得到的是一个负值,这是不理想的。让我们绘制一张图表,详细了解这些结果。

  1. 绘制原始数据和预测数据:
year_range = data_loader.data["YEAR"].values[cutoff:]

# Plot the actual and predicted data points
plt.plot(year_range, actual, 'o', label="Sunspots")
plt.plot(year_range, pred, 'x', label="Prediction")
plt.grid(True)

# Add labels
plt.xlabel("YEAR")
plt.ylabel("SUNACTIVITY")

# Add legend
plt.legend()

# Display the chart
plt.show()

这将产生以下输出:

从前面的图表可以得出结论,模型未能捕捉到序列的实际模式。这就是为什么我们得到负的决定系数或 R 平方值的原因。现在,我们将看另一种重要的时间序列分析技术——傅里叶分析。

傅里叶分析

傅里叶分析使用了数学家约瑟夫·傅里叶提出的傅里叶级数概念。傅里叶级数是一种将函数表示为正弦和余弦项的无限级数的数学方法。这里的函数可以是实数值或复数值的:

对于傅里叶分析,最有效的算法是快速 傅里叶变换FFT)。FFT 将信号分解为不同频率的信号。这意味着它生成了给定信号的频谱。SciPy 和 NumPy 库提供了 FFT 的相关函数。

rfft()函数对实值数据执行 FFT。我们也可以使用fft()函数,但在这个太阳黑子数据集上会给出警告。fftshift()函数将零频率成分移动到频谱的中间。

让我们通过以下示例来理解 FFT:

  1. 导入库并读取数据集:
# Import required library
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt
from scipy.fftpack import rfft
from scipy.fftpack import fftshift

# Read the dataset
data = sm.datasets.sunspots.load_pandas().data

# Create Sine wave
t = np.linspace(-2 * np.pi, 2 * np.pi, len(data.SUNACTIVITY.values))
mid = np.ptp(data.SUNACTIVITY.values)/2
sine = mid + mid * np.sin(np.sin(t))

2. 计算正弦波和太阳黑子的 FFT:

# Compute FFT for Sine wave
sine_fft = np.abs(fftshift(rfft(sine)))
print("Index of max sine FFT", np.argsort(sine_fft)[-5:])

# Compute FFT for sunspots dataset
transformed = np.abs(fftshift(rfft(data.SUNACTIVITY.values)))
print("Indices of max sunspots FFT", np.argsort(transformed)[-5:])
  1. 创建子图:
# Create subplots
fig, axs = plt.subplots(3,figsize=(12,6),sharex=True)
fig.suptitle('Power Specturm')
axs[0].plot(data.SUNACTIVITY.values, label="Sunspots")
axs[0].plot(sine, lw=2, label="Sine")
axs[0].legend() # Set legends
axs[1].plot(transformed, label="Transformed Sunspots")
axs[1].legend() # Set legends
axs[2].plot(sine_fft, lw=2, label="Transformed Sine")
axs[2].legend() # Set legends

# Display the chart
plt.show()

这将产生以下输出:

在前面的代码中,首先,我们读取了太阳黑子数据集并创建了正弦波。之后,我们计算了正弦波和SUNACTIVITY列的 FFT。最后,我们绘制了原始序列、正弦波以及变换后的太阳黑子和正弦波的三张图。

谱分析滤波

在前一节中,我们讨论了数据集的幅度谱。现在是时候探索功率谱了。任何物理信号的功率谱都可以显示信号的能量分布。我们可以通过以下语法轻松地修改代码并通过对变换信号进行平方来显示功率谱:

plt.plot(transformed ** 2, label="Power Spectrum")

我们还可以使用以下 Python 语法绘制相位谱:

plt.plot(np.angle(transformed), label="Phase Spectrum")

让我们看一下完整的代码,用于计算太阳黑子数据集的功率谱和相位谱:

  1. 导入库并读取数据集:
# Import required library
import numpy as np
import statsmodels.api as sm
from scipy.fftpack import rfft
from scipy.fftpack import fftshift
import matplotlib.pyplot as plt

# Read the dataset
data = sm.datasets.sunspots.load_pandas().data
  1. 计算 FFTSpectrumPhase
# Compute FFT
transformed = fftshift(rfft(data.SUNACTIVITY.values))

# Compute Power Spectrum
power=transformed ** 2

# Compute Phase
phase=np.angle(transformed)
  1. 创建子图:
# Create subplots
fig, axs = plt.subplots(3,figsize=(12,6),sharex=True)
fig.suptitle('Power Specturm')
axs[0].plot(data.SUNACTIVITY.values, label="Sunspots")
axs[0].legend() # Set legends
axs[1].plot(power, label="Power Spectrum")
axs[1].legend() # Set legends
axs[2].plot(phase, label="Phase Spectrum")
axs[2].legend() # Set legends

# Display the chart
plt.show()

这将产生以下输出:

在前面的代码中,首先,我们读取了太阳黑子数据集并计算了 SUNACTIVITY 列的 FFT。然后,我们计算了变换后 FFT 的功率谱和相位谱。最后,我们使用子图绘制了原始序列、功率谱和相位谱的三张图。

总结

在本章中,我们使用的时间序列示例包括年度太阳黑子周期数据、销售数据和啤酒生产数据。我们学到,在同一时间序列中,尝试推导一个值与另一个数据点或一组数据点在过去固定周期内的关系是常见的做法。我们了解到,移动平均通过使用窗口大小将随机变化趋势转换为平滑趋势。我们还学到了 DataFrame.rolling() 函数如何为不同的窗口函数提供 win_type 字符串参数。协整与相关性类似,是用来定义两个时间序列之间关系的度量指标。我们还重点讲解了 STL 分解、自相关、自动回归、ARMA 模型、傅里叶分析和谱分析滤波。

下一章,第九章,监督学习 – 回归分析,将重点讲解回归分析和逻辑回归在 Python 中的重要主题。章节首先介绍了多元线性回归、多重共线性、虚拟变量和模型评估指标。在后面的部分,将重点讨论逻辑回归。

第三部分:深入了解机器学习

本节的主要目标是深入研究机器学习算法并开发预测模型。本节重点讲解回归分析、分类、主成分分析(PCA)和聚类方法。本节将主要使用 pandas 和 scikit-learn。

本节包含以下章节:

  • 第九章,有监督学习 – 回归分析

  • 第十章,有监督学习 – 分类技术

  • 第十一章,无监督学习 – 主成分分析与聚类

第十章:监督学习 - 回归分析

回归是统计学和机器学习中最受欢迎的算法。在机器学习和数据科学领域,回归分析是监督式机器学习领域的一个成员,它帮助我们预测连续变量,如股价、房价、销售额、降雨量和温度。例如,作为一家电子商店的销售经理,假设你需要预测未来几周所有类型产品的销售情况,如电视、空调、笔记本电脑、冰箱等。许多因素可能影响你的销售情况,如天气条件、节假日、促销策略、竞争对手的优惠等。回归分析是帮助你识别这些因素的重要性,从而做出商店决策的工具之一。

回归分析用于识别因变量如何依赖于自变量。例如,假设作为一名教育官员,你希望识别体育活动、智能课堂、师生比、额外课程和教师培训对学生成绩的影响。普通最小二乘法 (OLS) 通过最小化平方误差和(或误差方差)来找出最佳拟合函数。它预测在给定条件下最可能的结果。本章的主要目标是学习多重线性回归 (MLR) 的基础知识、多重共线性、虚拟变量、回归以及模型评估指标,如 R 平方、均方误差 (MSE)、平均绝对误差 (MAE) 和均方根误差 (RMSE)。另一个目标是创建一个逻辑回归分类模型。

本章涵盖的主题如下:

  • 线性回归

  • 理解多重共线性

  • 虚拟变量

  • 开发线性回归模型

  • 评估回归模型性能

  • 拟合多项式回归

  • 用于分类的回归模型

  • 逻辑回归

  • 使用 scikit-learn 实现逻辑回归

技术要求

本章有以下技术要求:

线性回归

线性回归是一种曲线拟合和预测算法,用于发现因变量(或目标列)与一个或多个自变量(或预测变量)之间的线性关系。这种关系是确定性的,意味着它以一定的误差预测因变量。在回归分析中,因变量是连续的,而自变量可以是连续的或离散的。线性回归已广泛应用于各种商业和科学问题,如股票价格、原油价格、销售额、房产价格和 GDP 增长率的预测。在下图中,我们可以看到线性回归如何在二维空间中拟合数据:

主要目标是找到最佳拟合线,以最小的误差理解变量之间的关系。回归中的误差是预测值与实际值之间的差异。回归系数是通过 OLS 方法估计的。OLS 试图最小化残差平方和。我们来看回归模型的方程:

这里,x 是自变量,y 是因变量。 截距是 x 的系数,(希腊字母发音为 epsilon)是作为随机变量的误差项。

线性回归的参数是通过 OLS 估计的。OLS 是一种广泛用于估计回归截距和系数的方法。它通过减少残差平方和(或误差)来优化,这个误差是预测值与实际值之间的差异。

在了解了线性回归之后,现在是时候学习 MLR 了。

多重线性回归

多重线性回归(MLR)是简单线性回归的推广形式。它是一种统计方法,用于根据多个特征或解释变量预测连续的目标变量。MLR 的主要目标是估计多个特征与目标变量之间的线性关系。MLR 在现实生活中的应用非常广泛。MLR 模型可以表示为数学方程:

这里,![] 是自变量, 是因变量。 截距是 x 的系数,(希腊字母发音为 epsilon)是作为随机变量的误差项。

现在我们知道什么是线性回归,让我们继续讨论多重共线性。

理解多重共线性

多重共线性表示自变量(或预测变量)之间高度的相互相关性或相互关系。

多重共线性发生在多元回归分析中的自变量彼此高度相关时。这种关联是由于自变量之间的高相关性造成的。这种高相关性会导致线性回归模型预测结果出现问题。在进行线性回归分析时,避免多重共线性是基本假设,以获得更好的结果:

  • 它是由于虚拟变量的不当使用而发生的。

  • 它还可能是由于相似变量的重复出现引起的。

  • 它还可能是由于从数据中的其他变量合成的变量引起的。

  • 它可能是由于变量之间的高相关性引起的。

多重共线性会导致以下问题:

  • 它会导致回归系数的精确估计变得困难,并且系数对模型中的微小变化变得更加敏感。

  • 它还可能导致系数的符号和大小发生变化。

  • 它使得评估自变量相对重要性变得困难。

移除多重共线性

可以使用以下方法检测多重共线性:

  • 自变量之间的相关系数(或相关矩阵)

  • 方差膨胀因子VIF

  • 特征值

相关系数或相关矩阵有助于我们识别自变量之间的高度相关性。通过相关系数,我们可以通过检查相关系数的大小来轻松检测多重共线性:

# Import pandas
import pandas as pd

# Read the blood pressure dataset
data = pd.read_csv("bloodpress.txt",sep='\t')

# See the top records in the data
data.head()

这会导致以下输出:

在前面的代码块中,我们使用read_csv()函数读取了bloodpress.txt数据。我们还检查了数据集的初始记录。这个数据集包含了BPAgeWeightBSADurPulseStress字段。让我们使用相关矩阵来检查数据集中的多重共线性:

# Import seaborn and matplotlib
import seaborn as sns
import matplotlib.pyplot as plt

# Correlation matrix
corr=data.corr()

# Plot Heatmap on correlation matrix 
sns.heatmap(corr, annot=True, cmap='YlGnBu')

# display the plot
plt.show()

这会导致以下输出:

在前面的示例中,我们使用相关矩阵查找多个变量之间的相关性。我们加载了bloodpress.txt文件,并使用corr()函数找到了相关性。最后,我们使用heatmap()函数可视化了相关矩阵。

这里,BP血压)是因变量或目标变量,其他列是自变量或特征。我们可以看到,WeightBSA体表面积)之间有很高的相关性。我们需要移除其中一个变量(WeightBSA),以消除多重共线性。在我们的例子中,体重比体表面积更容易测量,因此专家会选择体重并移除体表面积。

虚拟变量

虚拟变量是回归分析中使用的分类自变量。它也被称为布尔值、指示变量、定性变量、分类变量和二元变量。虚拟变量将具有N个不同值的分类变量转换为N–1 个虚拟变量。它只取 1 和 0 这两个二进制值,分别代表存在和不存在。

pandas提供了get_dummies()函数来生成虚拟值。让我们通过一个例子来理解get_dummies()函数:

# Import pandas module
import pandas as pd

# Create pandas DataFrame
data=pd.DataFrame({'Gender':['F','M','M','F','M']})

# Check the top-5 records
data.head()

这将产生以下输出:

Gender
0F
1M
2M
3F
4M

在前面的代码块中,我们创建了包含Gender列的 DataFrame,并使用get_dummies()函数生成了虚拟变量。让我们通过以下代码看一个例子:

# Dummy encoding
encoded_data = pd.get_dummies(data['Gender'])

# Check the top-5 records of the dataframe
encoded_data.head()

这将产生以下输出:

 F M
0 1 0
1 0 1
2 0 1
3 1 0
4 0 1

在前面的例子中,get_dummies()函数生成了两列,这意味着每个值都有一个单独的列。

我们可以通过使用drop_first=True参数,去掉一列,避免共线性问题,首先删除N个类别中的第一列虚拟变量:

# Dummy encoding
encoded_data = pd.get_dummies(data['Gender'], drop_first=True)

# Check the top-5 records of the dataframe
encoded_data.head()

这将产生以下输出:

  M
0 0
1 1
2 1
3 0
4 1

在前面的代码块中,我们使用get_dummies()函数并设置drop_first=True参数,为Gender列创建了虚拟变量。这将删除第一列,剩下*N–*1 列。现在,让我们学习如何使用scikit-learn库实现线性回归模型。

开发线性回归模型

在理解回归分析、多重共线性和虚拟变量的概念之后,是时候通过实际操作体验回归分析了。让我们学习如何使用科学机器学习工具包(scikit-learn)构建回归模型:

  1. 我们将首先使用read_csv()函数加载数据集:
# Import pandas
import pandas as pd

# Read the dataset using read_csv method
df = pd.read_csv("Advertising.csv")

# See the top-5 records in the data
df.head()

这将产生以下输出:

现在我们已经使用read_csv()加载了Advertising.csv数据集,并使用head()函数查看了初始记录,我们将数据拆分为两部分:因变量或目标变量和自变量或特征变量。

  1. 在这一步,我们将数据拆分两次:
  • 将数据分为两部分:因变量或目标变量与自变量或特征变量。

  • 将数据拆分为训练集和测试集。这可以使用以下代码完成:

# Independent variables or Features
X = df[['TV', 'Radio', 'Newspaper']]

# Dependent or Target variable
y = df.Sales

在将列分为因变量和自变量部分之后,我们将使用train_test_split()函数按 75:25 的比例将数据拆分为训练集和测试集。这个比例可以通过test_size参数指定,random_state用作种子值,确保每次拆分的数据相同。如果random_stateNone,则每次都会随机拆分记录,可能会得到不同的性能度量:

# Lets import the train_test_split method
from sklearn.model_selection import train_test_split

# Distribute the features(X) and labels(y) into two parts training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)

在之前的代码块中,我们已经将数据分为两部分——训练集和测试集——比例为 75:25 或 3:1。

  1. 让我们导入LinearRegression模型,创建它的对象,并将其拟合到训练数据集(X_train, y_train)。在拟合模型后,我们可以预测测试数据(X_test)的值。通过intercept_coef_属性,我们可以看到回归方程的截距和系数:
# Import linear regression model
from sklearn.linear_model import LinearRegression
# Create linear regression model
lin_reg = LinearRegression()

# Fit the linear regression model
lin_reg.fit(X_train, y_train)

# Predict the values given test set
predictions = lin_reg.predict(X_test)

# Print the intercept and coefficients
print("Intercept:",lin_reg.intercept_)
print("Coefficients:",lin_reg.coef_)

这将产生以下输出:

Intercept: 2.8925700511511483
Coefficients: [0.04416235 0.19900368 0.00116268]

在之前的代码中,我们已经准备了线性回归模型,对测试集进行了预测,并显示了截距和系数。在接下来的部分,我们将使用回归评估指标(如 R 平方和误差函数)评估回归模型的性能。

评估回归模型性能

在这一部分,我们将回顾回归模型评估指标,以了解回归模型的性能水平。模型评估是任何机器学习模型构建过程中的关键方面之一。它帮助我们评估当模型投入生产时的表现。我们将使用以下指标进行模型评估:

  • R 平方

  • MSE

  • MAE

  • RMSE

R 平方

R 平方(或决定系数)是一个统计学模型评估指标,用于评估回归模型的拟合优度。它帮助数据分析师解释模型相较于基准模型的表现。其值介于 0 和 1 之间。接近 0 的值表示模型较差,而接近 1 的值表示完美拟合。有时,R 平方结果可能为负值,这意味着你的模型比平均基准模型还差。我们可以通过以下公式解释 R 平方:

让我们逐一理解所有组件:

  • 回归平方和SSR):这是预测值与数据均值之间差异的估算。

  • 误差平方和SSE):这是原始值与预测值之间变化的估算。

  • 总平方和SST):这是原始值与数据均值之间的变化。

MSE

MSE 是均方误差(Mean Squared Error)的缩写。它的定义为原始值与预测值之间变化的平方,以及所有值之间的平均值:

这里, 是原始值, 是预测值。

MAE

MAE 是均绝对误差(Mean Absolute Error)的缩写。它的定义为原始值与预测值之间的绝对变化,以及所有值之间的平均值:

这里, 是原始值, 是预测值。

RMSE

RMSE 是均方根误差的缩写。它可以解释为 MSE 的平方根:

让我们在测试数据集上评估模型性能。在前一部分,我们预测了测试集的值。现在,我们将预测值与测试集的实际值(y_test)进行比较。scikit-learn 提供了 metrics 类来评估模型。对于回归模型评估,我们有 R 平方值、MSE、MAE 和 RMSE 的评估方法。每个方法都需要两个输入:测试集的实际值和预测值(y_testy_pred)。让我们评估线性回归模型的表现:

# Import the required libraries
import numpy as np
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

# Evaluate mean absolute error
print('Mean Absolute Error(MAE):', mean_absolute_error(y_test,predictions))

# Evaluate mean squared error
print("Mean Squared Error(MSE):", mean_squared_error(y_test, predictions))

# Evaluate root mean squared error
print("Root Mean Squared Error(RMSE):", np.sqrt(mean_squared_error(y_test, predictions)))

# Evaluate R-square
print("R-Square:",r2_score(y_test, predictions))

这将产生以下输出:

Mean Absolute Error(MAE): 1.300032091923545
Mean Squared Error(MSE): 4.0124975229171
Root Mean Squared Error(RMSE): 2.003121944095541
R-Square: 0.8576396745320893

在这个例子中,我们通过 MAE、MSE、RMSE 和 R 平方值评估了线性回归模型。在这里,R 平方值为 0.85,表示该模型解释了数据 85% 的变异性。

拟合多项式回归

多项式回归是一种回归分析方法,用于适应因变量与自变量之间的非线性关系。在这种回归类型中,变量被建模为 n 次多项式的形式。它用于理解各种现象的增长率,如流行病爆发和销售增长。让我们理解一下多项式回归的方程:

在这里, 是自变量, 是因变量。 截距,...x 的系数,(这个希腊字母发音为 epsilon)是误差项,作为随机变量起作用。

让我们看一个例子来详细理解多项式概念:

# import libraries
import matplotlib.pyplot as plt
import numpy as np

# Create X and Y lists
X=[1,2,3,4,5,6,7,8,9,10]
y=[9,10,12,16,22,28,40,58,102,200]

# Plot scatter diagram
plt.scatter(X,y, color = 'red')
plt.title('Polynomial Regression')
plt.xlabel('X-Axis')
plt.ylabel('y-Axis')

这将产生以下输出:

在前面的代码中,我们展示了一个具有多项式关系的数据集。让我们来看一下如何在回归分析中映射这个关系:

# import libraries
import pandas as pd
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

# Prepare dataset 
data = pd.DataFrame({"X":[1,2,3,4,5,6,7,8,9,10], 
"y":[9,10,12,16,22,28,40,58,102,200]}) 

X = data[['X']] y = data[['y']]

# Apply Polynomial Features 
polynomial_reg = PolynomialFeatures(degree = 6) 
X_polynomial = polynomial_reg.fit_transform(X) 

# Apply Linear Regression Model 
linear_reg = LinearRegression() 
linear_reg.fit(X_polynomial, y) predictions=linear_reg.predict(X_polynomial) 

# Plot the results 
plt.scatter(X,y, color = 'red') 
plt.plot(X, predictions, color = 'red') 
plt.title('Polynomial Regression') 
plt.xlabel('X-Axis') 
plt.ylabel('y-Axis')

这将产生以下输出:

在前面的代码中,我们读取了多项式关系数据集,使用 PolynomialFeatures()X 列转换为多项式 n 次方列,然后对 X_polynomiallabel 应用了线性回归。前面的输出图显示了结果模型的表现。现在,轮到我们转向另一种回归模型,这种模型可以用于分类目的。

用于分类的回归模型

分类是机器学习和统计学习领域中使用最多的技术。大多数机器学习问题都是分类问题,例如,垃圾邮件检测、金融风险分析、客户流失分析以及潜在客户发现等。

分类可以分为两种类型:二分类和多分类。二分类目标变量只有两个值:0 和 1,或者是是和否。例如,二分类的实例包括:客户是否会购买某商品,客户是否会转向其他品牌或流失,垃圾邮件检测,疾病预测,以及贷款申请者是否会违约等。多分类则有多个类别,例如,新闻文章的类别可以包括体育、政治、商业等多个类。

逻辑回归是其中一种分类方法,尽管它的名字以“回归”结尾。它是一种常用的二分类方法,是解决各种分类问题的基础机器学习算法。它找出因变量(或目标变量)与一组自变量(或特征)之间的关联。在接下来的部分中,我们将详细介绍逻辑回归。

逻辑回归

逻辑回归是一种有监督的机器学习算法,用于预测二元结果并进行观察分类。其因变量是一个二元变量,具有两个类别:0 或 1。例如,它可以用来检测贷款申请者是否会违约。它是一种特殊类型的回归,其中因变量是二元的。它计算目标变量的赔率比的对数,表示某事件发生的概率,例如,一个人患糖尿病的概率。

逻辑回归是一种简单的线性回归,其中因变量或目标变量是类别型的。它在线性回归的预测结果上使用了 sigmoid 函数。我们还可以使用逻辑回归算法来处理多个目标类别。在多类别问题中,它被称为多项逻辑回归。多项逻辑回归是对逻辑回归的一种修改;它使用 softmax 函数代替 sigmoid 激活函数:

Sigmoid 函数也叫做逻辑函数或 S 形曲线。它将输入值映射到 0 到 1 之间,这表示某事件发生的概率。如果曲线向正无穷延伸,则结果变为 1;如果曲线向负无穷延伸,则结果变为 0。让我们看看 Sigmoid 函数和逻辑回归方程的公式:

以下公式展示了逻辑回归方程:

log() 函数中的项称为赔率比或“赔率”。赔率比是事件发生的概率与事件不发生的概率之比。在下图中,您可以看到逻辑回归输出的表现:

我们可以看到这里的比率大致在 0.5 左右。接下来我们将在下面的小节中进一步探讨逻辑回归。

逻辑回归模型的特点

在本小节中,我们将重点讨论逻辑回归的基本特征和假设。让我们了解以下特征:

  • 因变量或目标变量应为二元类型。

  • 自变量之间不应存在多重共线性。

  • 系数通过最大似然法估计。

  • 逻辑回归遵循伯努利分布。

  • 该模型没有 R 平方值用于评估。模型通过一致性和 KS 统计量进行评估。

逻辑回归算法类型

不同的逻辑回归算法适用于不同的使用场景和情境。在本节中,我们将重点讨论二项逻辑回归、多项逻辑回归和顺序逻辑回归。让我们逐一了解这些模型,并理解它们的应用场景:

  • 二项逻辑回归模型

在二项逻辑回归模型中,因变量或目标列只有两个取值,例如贷款是否违约、电子邮件是否为垃圾邮件,或者患者是否为糖尿病患者。

  • 多项逻辑回归模型

在多项逻辑回归模型中,因变量或目标列有三个或更多的取值,例如预测鸢尾花的种类,或预测新闻文章的类别,如政治、商业和体育。

  • 顺序逻辑回归

在顺序逻辑回归模型中,因变量将具有顺序或序列类别,例如电影和酒店评分。

逻辑回归的优缺点

逻辑回归模型不仅提供预测(0 或 1),还给出结果的概率,这有助于我们理解预测的置信度。它易于实现和理解,并且具有可解释性。

如果自变量数量过多,将增加解释的方差,这会导致模型过拟合。逻辑回归无法处理非线性关系,并且在特征变量(或自变量)高度相关时表现不佳。

使用 scikit-learn 实现逻辑回归

现在您已经了解了逻辑回归的所有内容,接下来让我们使用 scikit-learn 库在 Python 中实现它。我们将使用朴素贝叶斯分类来创建模型。我们将通过以下步骤进行:

  1. 我们将首先导入数据集和所需的库,使用以下代码:
# Import libraries
import pandas as pd
# read the dataset
diabetes = pd.read_csv("diabetes.csv")

# Show top 5-records
diabetes.head()

这将产生以下输出:

在前面的示例中,我们正在读取 Pima Indians 糖尿病数据集。此数据集没有列名,因此我们需要手动添加列名。

  1. read_csv()函数中,我们将header设置为None,并将之前创建的列名列表传递给names参数:
# Split dataset in two parts: feature set and target label
feature_set = ['pregnant', 'insulin', 'bmi', 'age','glucose','bp','pedigree']

features = diabetes[feature_set]

target = diabetes.label

# Partition data into training and testing set
from sklearn.model_selection import train_test_split
feature_train, feature_test, target_train, target_test = train_test_split(features, target, test_size=0.3, random_state=1)

加载数据集后,我们需要将数据集分为独立(特征集)列特征和依赖(或标签)列目标。之后,数据集将被划分为训练集和测试集。现在,依赖列和独立列将使用train_test_split()函数分为训练集和测试集(feature_trainfeature_testtarget_traintarget_test)。train_test_split()接受依赖和独立的 DataFrame,test_sizerandom_state。其中,test_size决定训练-测试数据集的划分比例(例如,test_size0.3表示 30%的数据用于测试集,剩余的 70%用于训练集),而random_state用作种子值,以确保每次划分的数据集相同。如果random_stateNone,则每次都会随机划分记录,可能会得到不同的性能指标:

# import logistic regression scikit-learn model
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score 

# instantiate the model
logreg = LogisticRegression(solver='lbfgs')

# fit the model with data
logreg.fit(feature_train,target_train)

# Forecast the target variable for given test dataset
predictions = logreg.predict(feature_test)

# Assess model performance using accuracy measure
print("Logistic Regression Model Accuracy:",accuracy_score(target_test, predictions))

结果如下所示:

Logistic Regression Model Accuracy: 0.7835497835497836

现在,我们准备好创建一个逻辑回归模型。首先,我们将导入LogisticRegression类并创建其对象或模型。该模型将在训练数据集(X_trainy_train)上进行训练。训练完成后,模型即可使用predict()方法进行预测。scikit-learn 的metrics类提供了多种性能评估方法,如准确率。accuracy_score()方法将接受实际标签(y_test)和预测标签(y_pred)。

总结

在本章中,我们探讨了回归分析算法。这将帮助你获得进行预测数据分析的重要技能。你已经掌握了回归分析、多重共线性、虚拟变量、回归评估指标和逻辑回归等概念。本章从简单线性回归和多重回归开始,之后我们的主要重点是多重共线性、模型开发和模型评估指标。在后续部分,我们重点介绍了逻辑回归、回归的特点、回归类型及其实现。

下一章,第十章,监督学习 – 分类技术,将重点讨论分类及其技术、训练-测试数据集划分策略和性能评估指标。在后续部分,我们将重点介绍数据划分、混淆矩阵以及性能评估指标,如准确率、精确度、召回率、F1 分数、ROC 和 AUC。

第十一章:监督学习 - 分类技术

大多数现实世界中的机器学习问题都使用监督学习。在监督学习中,模型将从一个带标签的训练数据集中学习。标签是我们想要预测的目标变量。它是一个额外的信息,帮助做出决策或预测,例如,哪个贷款申请是安全的或有风险的,患者是否患有某种疾病,房价,以及信用资格分数。这些标签作为学习过程中的监督者或老师。监督学习算法可以分为两种类型:分类或回归。分类问题有一个分类目标变量,例如,贷款申请状态是安全的还是有风险的,患者是否患有“疾病”或“无疾病”,或顾客是否是“潜在的”或“非潜在的”。

本章重点介绍监督学习,特别是分类技术。本章将主要使用 scikit-learn。将深入讨论分类的基本技术,如朴素贝叶斯、支持向量机SVM)、K-最近邻KNN)和决策树。此外,还重点介绍训练集与测试集的划分策略以及模型评估方法和参数。

本章的主题如下:

  • 分类

  • 朴素贝叶斯分类

  • 决策树分类

  • KNN 分类

  • SVM 分类

  • 划分训练集和测试集

  • 评估分类模型的表现

  • ROC 曲线与 AUC

技术要求

本章的技术要求如下:

分类

作为一名医疗数据分析师,你的工作是识别那些患某种特定疾病(例如糖尿病或癌症)可能性较高的患者或病人。这些预测将帮助你在疾病发生之前对患者进行治疗。同样,销售和市场经理也希望预测那些有更高可能性购买产品的潜在客户。这就是将客户分类为两个或多个类别的过程,称为分类。分类模型预测类别标签,例如客户是否是潜在客户。在分类过程中,模型基于现有数据进行训练,做出预测,并评估模型的表现。开发出来的模型称为分类器。这意味着分类模型有三个阶段:训练、预测和评估。训练好的模型通过准确率、精确度、召回率、F1 分数和曲线下面积AUC)等参数来评估。分类在许多领域中有广泛的应用,如银行、金融、公共服务、医疗保健、文本分析、图像识别和物体检测等。

作为分析师,你首先需要定义你想通过分类解决的问题,然后确定能够准确预测标签的潜在特征。特征是负责预测的列或属性。在糖尿病预测问题中,健康分析师会收集患者的信息,例如年龄、锻炼习惯、垃圾食品摄入习惯、酒精消费和吸烟习惯等特征。这些特征将用于预测患者是否会患上糖尿病。你可以在下面的图示中看到,如何通过一条线将数据分类为两个类别:

机器学习和数据挖掘过程有多个步骤:数据收集、数据预处理、训练-测试拆分、模型生成和评估。我们已经看到了像 KDD、SEMMA 和 CRISP-DM 这样的数据分析模型。在分类中,我们只关注训练-测试拆分、模型生成和评估这几个步骤。

分类模型有三个阶段:训练-测试拆分、模型生成和模型评估。在训练-测试拆分阶段,数据被分为两部分:训练集和测试集。在训练阶段,使用训练集来生成模型,而在评估阶段,使用测试集来评估模型的表现,通过准确率、误差、精确度和召回率等评估指标。你可以在以下图示中看到分类过程:

在上面的图示中,展示了分类过程的各个步骤。现在我们已经理解了分类过程,接下来是学习分类技术。在下一节中,我们将重点介绍朴素贝叶斯分类算法。

朴素贝叶斯分类

朴素贝叶斯是一种基于贝叶斯定理的分类方法。贝叶斯定理以其发明者、统计学家托马斯·贝叶斯命名。它是一种快速、准确、稳健、易于理解和解释的技术。它还可以在大数据集上更快速地工作。朴素贝叶斯广泛应用于文本挖掘,如文档分类、客户评论情感预测和垃圾邮件过滤等。

朴素贝叶斯分类器被称为“朴素”,因为它假设类条件独立。类条件独立意味着每个特征列独立于其他特征。例如,在确定一个人是否患有糖尿病时,可能依赖于他们的饮食习惯、锻炼习惯、职业性质和生活方式。即使特征之间存在相关性或依赖关系,朴素贝叶斯仍然假设它们是独立的。让我们理解贝叶斯定理的公式:

这里,y 是目标,X 是特征集。p(y)p(X) 是不考虑证据的先验概率。这意味着在看到证据之前事件的概率。p(y|X) 是在看到证据 X 后事件 X 的后验概率。它是给定证据 Xy 的概率。p(X|y) 是在看到证据后事件 y 的后验概率。它是给定证据 yX 的概率。我们来看看前面的方程示例:

在这里,我们使用贝叶斯定理找出一个患者是否会因吸烟频率而患糖尿病的概率。

让我们看看朴素贝叶斯分类算法的工作原理。假设数据集 D 具有 X 特征和标签 y。特征可以是 n 维的,X = X1, X2, X3... Xn。标签 y 可能有 m 个类,C1, C2, C3... Cm。它将按以下方式工作:

  1. 计算给定类标签的先验概率,

  2. 计算后验概率,,每个类的每个属性:

  1. 乘以相同类的后验概率,

  1. 如果属性是分类的,那么应该有多个类 在具有 值的记录中,除以数据集中的 记录数。

  2. 如果属性是连续的,则使用高斯分布进行计算:

  1. 将先验概率 p(y) 乘以步骤 3中的后验概率:

  1. 找到给定输入特征集的最大概率类。这个类将作为我们的最终预测。

现在,让我们使用 Python 中的朴素贝叶斯分类创建一个模型:

  1. 使用以下代码行加载 Pima 印度糖尿病数据集(github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/blob/master/Chapter09/diabetes.csv):
# Import libraries
import pandas as pd
# read the dataset
diabetes = pd.read_csv("diabetes.csv")

# Show top 5-records
diabetes.head()

这将产生以下输出:

因此,我们已经导入了pandas并读取了数据集。在之前的示例中,我们正在读取 Pima 印度糖尿病数据集。

  1. 我们现在将数据集拆分成两部分,如下所示:
# split dataset in two parts: feature set and target label
feature_set = ['pregnant', 'insulin', 'bmi', 'age','glucose','bp','pedigree'] features = diabetes[feature_set]
target = diabetes.label

# partition data into training and testing set
from sklearn.model_selection import train_test_split

feature_train,feature_test, target_train, target_test = \
train_test_split(features, target, test_size=0.3, random_state=1)

加载数据集后,我们将数据集分为依赖列或标签列(target)和独立列或特征列(feature_set)。之后,数据集将被拆分为训练集和测试集。现在,依赖列和独立列将通过train_test_split()被拆分为训练集和测试集(feature_trainfeature_testtarget_traintarget_test)。train_test_split()接受依赖和独立的 DataFrame,test_sizerandom_state。其中,test_size决定了训练集和测试集的比例(例如,test_size 0.3意味着 30%是测试集,剩余的 70%数据是训练集),random_state用作种子值,用于每次重新生成相同的数据拆分。如果random_stateNone,则每次都会随机拆分记录,这会导致不同的性能度量。

  1. 我们现在将构建朴素贝叶斯分类模型:
# Import Gaussian Naive Bayes model
from sklearn.naive_bayes import GaussianNB
# Create a Gaussian Classifier
model = GaussianNB()

# Train the model using the training sets
model.fit(feature_train,target_train)

# Forecast the target variable for given test dataset
predictions = model.predict(feature_test)

在这里,我们创建了一个朴素贝叶斯模型。首先,我们将导入GaussianNB类并创建其对象或模型。这个模型将根据训练数据集(feature_traintarget_train)进行拟合。训练完成后,模型准备好使用predict()方法进行预测。

  1. 最后,我们将评估模型的性能:
# Import metrics module for performance evaluation
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
# Calculate model accuracy
print("Accuracy:",accuracy_score(target_test, predictions))

# Calculate model precision
print("Precision:",precision_score(target_test, predictions))

# Calculate model recall
print("Recall:",recall_score(target_test, predictions))

# Calculate model f1 score
print("F1-Score:",f1_score(target_test, predictions))

这将产生以下输出:

Accuracy: 0.7748917748917749
Precision: 0.7391304347826086
Recall: 0.6
F1-Score: 0.6623376623376623

scikit-learn 的metrics类提供了多种性能评估方法,例如准确率、精确率、召回率和 F1 分数。这些方法将使用实际目标标签(target_test)和预测标签(predictions)。我们将在评估分类模型性能部分详细了解这些指标。

朴素贝叶斯是一种简单、快速、准确且易于理解的预测方法。它具有较低的计算成本,可以处理大型数据集。朴素贝叶斯还可以用于多类分类问题。当数据具有类独立性假设时,朴素贝叶斯分类器比逻辑回归表现更好。

朴素贝叶斯存在 零频率问题。零频率意味着如果某个特征的类别缺失,则该类别的频率计数为零。这个问题可以通过拉普拉斯修正来解决。拉普拉斯修正(或拉普拉斯变换)是一种平滑技术,会为每个类别添加一条记录,使得缺失类别的频率计数变为 1,从而不会影响贝叶斯定理中的概率。朴素贝叶斯的另一个问题是其假设类条件独立性,因为在实际情况中,所有预测因子完全独立几乎是不可能的。在这一部分,我们已经学习了朴素贝叶斯分类法。现在是时候学习决策树分类算法了。

决策树分类

决策树是最著名的分类技术之一。它可以应用于两种类型的监督学习问题(分类问题和回归问题)。决策树是一种类似流程图的树形结构,模仿人类思维方式,这使得它更容易理解和解释。与支持向量机(SVM)和神经网络等“黑箱”算法不同,决策树能让你看到预测背后的逻辑。

决策树有三个基本组件:内部节点、分支和叶子节点。在这里,每个终端节点代表一个特征,链接代表决策规则或分割规则,叶子节点提供预测结果。树中的第一个起始节点或主节点是根节点。它根据特征或属性值来划分数据。在这里,我们分割数据,然后递归地再次划分剩余数据,直到所有项属于同一类别或没有剩余列。决策树可以应用于分类和回归问题。市面上有许多决策树算法,例如 CART、ID3、C4.5 和 CHAID。但在这里,我们主要关注 CART 和 ID3,因为在 scikit-learn 中,这两种算法是可用的。让我们在下图中看看决策树分类器的生成过程:

CART 代表 分类与回归树。CART 使用基尼指数来选择最佳列。基尼指数是每个类别的概率平方和与 1 的差值。具有最小基尼指数值的特征或列被选为分割或划分特征。基尼指数的值范围在 0 和 1 之间。如果基尼指数值为 0,表示所有项属于同一类;如果基尼指数值为 1,则表示所有元素是随机分布的。基尼指数值为 0.5 表示项在多个类别中均匀分布:

ID3 代表 Iterative Dichotomiser 3(迭代二分法 3)。它使用信息增益或熵作为属性选择度量。熵由香农提出,用于衡量数据集中的杂乱度或随机性。信息增益衡量在特定列的分割前后,熵的变化量。具有最大信息增益值的特征或属性将被选择为分裂特征或属性。如果熵为 0,表示只有一个类;如果熵为 1,则表示项目均匀分布:

决策树非常直观,易于理解、解释并向利益相关者讲解。无需对特征进行标准化,并且是无分布假设的算法。决策树也可以用来预测缺失值。它们具备捕捉非线性模式的能力。决策树可能会过拟合,并且对噪声数据敏感。决策树在数据不平衡时有偏差,这也是在应用决策树之前,我们需要平衡数据集的原因。决策树在时间和复杂度上更为昂贵。

让我们使用 scikit-learn 构建决策树并执行预测数据集。之后,我们将准备好构建模型:

  1. 首先,您需要导入 pandas 并使用我们在上一部分中看到的 read_csv() 方法加载 Pimas 数据集。

  2. 接下来,我们需要将数据集划分为训练集和测试集,类似于我们在前一部分中执行的操作。

  3. 现在,我们将构建决策树分类模型:

# Import Decision Tree model
from sklearn.tree import DecisionTreeClassifier

# Create a Decision Tree classifier object
clf = DecisionTreeClassifier()

# Train the model using training dataset
clf = clf.fit(feature_train,target_train)

# Predict the response for test dataset
predictions = clf.predict(feature_test)

这里,我们创建了一个决策树模型。首先,我们将导入 DecisionTreeClassifier 类并创建其对象或模型。该模型将在训练数据集(feature_traintarget_train)上进行拟合。训练完成后,模型已准备好使用 predict() 方法进行预测。

  1. 现在,我们将评估模型的性能:
# Import metrics module for performance evaluation
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

# Calculate model accuracy
print("Accuracy:",accuracy_score(target_test, predictions))

# Calculate model precision
print("Precision:",precision_score(target_test, predictions))

# Calculate model recall
print("Recall:",recall_score(target_test, predictions))

# Calculate model f1 score
print("F1-Score:",f1_score(target_test, predictions))

这将输出以下结果:

Accuracy: 0.7229437229437229
Precision: 0.6438356164383562
Recall: 0.5529411764705883
F1-Score: 0.5949367088607594

在上述示例中,模型性能通过准确度、精确度、召回率和 F1 分数进行评估。

在完全理解决策树之后,让我们继续进行 KNN 分类。

KNN 分类

KNN 是一种简单、易于理解和实现的分类算法。它也可以用于回归问题。KNN 可用于许多应用场景,如项目推荐和分类问题。具体来说,它可以在 Netflix 上推荐电影,在 Medium 上推荐文章,在 naukari.com 上推荐候选人,在 eBay 上推荐产品,在 YouTube 上推荐视频。在分类中,它可以用于分类实例,例如银行机构可以对风险较大的贷款候选人进行分类,或者政治学家可以对潜在选民进行分类。

KNN 有三个基本属性,分别是非参数性、懒惰学习者和基于实例的学习。非参数性意味着算法不依赖于分布,因此不需要像均值和标准差这样的参数。懒惰学习者意味着 KNN 不进行模型训练;也就是说,模型是在测试阶段进行训练的。这使得训练速度更快,但测试速度较慢,并且也更加耗时和占用内存。基于实例的学习意味着预测结果是基于与其最近邻的相似度。它不会为预测创建抽象的方程或规则,而是存储所有数据并查询每个记录。

KNN 分类算法从训练数据集中找到 k 个最相似的实例,且多数决定了给定输入特征的预测标签。KNN 分类器将执行以下步骤来进行预测:

  1. 计算输入观察与训练数据集中所有观察的距离。

  2. 通过按距离对所有实例进行升序排序,找到 K 个最接近的邻居。

  3. K 个最接近的邻居进行投票,并预测获得最多票数的标签。

这一过程可以通过以下图示来更好地展示:

让我们使用 scikit-learn 构建一个 KNN 分类器,并对数据集进行预测:

  1. 加载皮马印第安糖尿病数据集。

首先,您需要导入 pandas 并使用我们在 朴素贝叶斯分类 课程中已经看到的 read_csv() 方法加载数据集。

  1. 划分数据集。

之后,我们需要将数据集分成两部分——训练集和测试集——就像我们在 朴素贝叶斯分类 部分所做的那样。

  1. 构建 KNN 分类模型。

现在,我们准备开始构建模型:

# Import KNN model
from sklearn.neighbors import KNeighborsClassifier 

# Create a KNN classifier object 
model = KNeighborsClassifier(n_neighbors=3) 

# Train the model using the training dataset 
model.fit(feature_train,target_train) 

# Predict the target variable for test dataset 
predictions = model.predict(feature_test)

在前面的代码块中,我们导入了 KNeighborsClassifier 类并创建了它的对象或模型。在这里,我们将 3 个邻居作为模型的输入参数。如果我们没有指定邻居的数量,模型将默认选择 5 个邻居。该模型将拟合训练数据集(feature_train, target_train)。训练完成后,模型已准备好使用 predict() 方法进行预测。

  1. 评估模型性能:
# Import metrics module for performance evaluation
from sklearn.metrics import accuracy_score 
from sklearn.metrics import precision_score 
from sklearn.metrics import recall_score 
from sklearn.metrics import f1_score 

# Calculate model accuracy 
print("Accuracy:",accuracy_score(target_test, predictions)) 

# Calculate model precision 
print("Precision:",precision_score(target_test, predictions)) 

# Calculate model recall 
print("Recall:",recall_score(target_test, predictions)) 

# Calculate model f1 score 
print("F1-Score:",f1_score(target_test, predictions))

这将产生以下输出:

Accuracy: 0.7532467532467533
Precision: 0.7058823529411765
Recall: 0.5647058823529412
F1-Score: 0.6274509803921569

在前面的示例中,模型性能通过准确率、精确度、召回率和 F1 分数进行评估。

在理解了 KNN 分类算法之后,接下来是学习 SVM 分类算法。

SVM 分类

由于其较少的计算资源需求和较高的准确性,SVM 是许多数据科学家最喜欢的机器学习算法。它们被用于回归和分类问题,并提供了核技巧来建模非线性关系。SVM 有多种应用场景,例如入侵检测、文本分类、人脸识别和手写识别。

SVM 是一个判别模型,它在 n 维空间中生成具有大间隔的最优超平面来分隔数据点。其基本思想是发现最大间隔超平面MMH),该超平面完美地将数据分成不同类别。最大间隔意味着两类数据点之间的最大距离。

术语

现在,我们将探讨一些与 SVM 分类相关的术语:

  • 超平面:超平面是用来区分两类的决策边界。超平面的维度由特征的数量决定。它也被称为决策平面。

  • 支持向量:支持向量是距离超平面最近的点,它们通过最大化间隔来帮助确定超平面的方向。

  • 间隔:间隔是距离最近点的最大距离。间隔越大,分类效果越好。间隔可以通过从支持向量线到超平面的垂直距离来计算。

SVM 的核心目标是选择具有最大可能边界的超平面,边界由支持向量之间的距离决定。SVM 通过以下两个阶段来找到 MMH:

  1. 创建超平面,以最佳方式分隔数据点。

  2. 选择具有最大间隔的超平面:

与朴素贝叶斯相比,SVM 算法是一种更快、更准确的分类器。它在较大的分隔间隔下表现更好。SVM 不适用于大规模数据集。其性能也依赖于所使用的核函数类型。对于重叠类,它的表现较差。

让我们使用scikit-learn进行支持向量分类器的工作,并执行一个预测数据集。完成后,我们将数据集划分为训练集和测试集,就像我们在朴素贝叶斯分类部分所做的那样。接下来,我们准备好进行模型构建:

  1. 加载皮马印第安人糖尿病数据集。

首先,你需要导入pandas并使用我们在朴素贝叶斯分类环节中已经看到的read_csv()方法加载数据集。

  1. 划分数据集。

完成后,我们需要将数据集拆分为两个集合——训练集和测试集——就像我们在朴素贝叶斯分类部分所做的那样。

  1. 构建 SVM 分类模型。

现在,我们已经准备好开始模型构建:

# Import SVM model
from sklearn import svm

# Create a SVM classifier object
clf = svm.SVC(kernel='linear')

# Train the model using the training sets
clf.fit(feature_train,target_train)

# Predict the target variable for test dataset
predictions = clf.predict(feature_test)

在上述代码块中,我们将导入 svm 模块并创建其 svm.SVC() 对象或模型。 这里我们传递了 linear 核。 您还可以传递另一个核,例如 polyrbfsigmoid。 如果我们不指定核心,则默认选择 rbf 作为核心。 线性核将创建一个线性超平面来区分糖尿病患者和非糖尿病患者。 该模型将适合于训练数据集(feature_traintarget_train)。 训练后,模型已准备使用 predict() 方法进行预测。

  1. 评估模型的性能:
# Import metrics module for performance evaluation
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

# Calculate model accuracy
print("Accuracy:",accuracy_score(target_test, predictions))

# Calculate model precision
print("Precision:",precision_score(target_test, predictions))

# Calculate model recall
print("Recall:",recall_score(target_test, predictions))

# Calculate model f1 score
print("F1-Score:",f1_score(target_test, predictions))

这将导致以下输出:

Accuracy: 0.7835497835497836
Precision: 0.7868852459016393
Recall: 0.5647058823529412
F1-Score: 0.6575342465753424

在上述示例中,将使用准确性、精确度、召回率和 F1 分数等指标评估模型的性能。 理解所有这些分类器后,现在是时候看看训练和测试集分割策略了。

分割训练和测试集

数据科学家需要评估模型的性能,克服过拟合并调整超参数。 所有这些任务都需要一些未在模型开发阶段使用的隐藏数据记录。 在模型开发之前,数据需要分成一些部分,例如训练、测试和验证集。 训练数据集用于构建模型。 测试数据集用于评估在训练集上训练的模型的性能。 验证集用于找到超参数。 让我们看看下面的训练-测试分割策略:

  • 保留样本法

  • K 折交叉验证

  • Bootstrap 方法

保留样本法

在此方法中,数据集被随机分成两部分:训练集和测试集。 通常,这个比例是 2:1,即 2/3 用于训练,1/3 用于测试。 我们还可以将其分割成不同的比例,如 6:4、7:3 和 8:2:

# partition data into training and testing set
from sklearn.model_selection import train_test_split

# split train and test set
feature_train, feature_test, target_train, target_test = train_test_split(features, target, test_size=0.3, random_state=1)

在上述示例中,test_size=0.3 表示测试集占 30%,训练集占 70%。 train_test_split() 将数据集分割为 7:3。

K 折交叉验证

在此方法中,数据分为大致相同大小的 k 个分区。 它将训练 k 个模型,并使用每个分区进行评估。 在每次迭代中,一个分区将保留用于测试,其余的 k 个分区将集体用于训练。 分类准确度将是所有准确度的平均值。 它还确保模型不会过拟合:

在分层交叉验证中,k 个分区大致相同的类分布。 这意味着它保留每个分区中每个类的百分比。

Bootstrap 方法

自助法是一种重采样技术。它从数据集中反复进行有放回的抽样。有放回的抽样会进行随机选择。它需要样本的大小和迭代次数。在每次迭代中,它会均匀选择记录。每条记录被选择的机会相同。未被选择的样本称为“袋外”样本。我们可以通过以下图表来理解自助法:

在上面的图表中,我们可以看到每个元素在每次自助采样中都有相同的选择机会。接下来,我们将跳到分类的另一个重要话题——分类模型评估。下一个话题帮助我们评估分类模型的表现。

评估分类模型的表现

到目前为止,我们已经学习了如何创建分类模型。创建机器学习分类模型还不够;作为业务或数据分析师,你还需要评估它的表现,以便可以将其部署到实际项目中。

scikit-learn 提供了各种度量标准,如混淆矩阵、准确率、精确度、召回率和 F1 分数,用于评估模型的表现。

混淆矩阵

混淆矩阵是一种简要说明二分类和多分类问题预测结果的方法。假设我们要找出一个人是否患有糖尿病。混淆矩阵的概念是找出正确预测和错误预测的数量,然后将它们进一步总结并分开到每个类别中。它阐明了与我们分类模型表现相关的所有混淆信息。这个 2x2 矩阵不仅显示了分类器所犯的错误,还展示了犯的是什么类型的错误。混淆矩阵用于更快速地完成统计数据分析,并通过清晰的数据可视化使结果更具可读性和易理解性。它包含两行两列,如下所示。让我们理解混淆矩阵的基本术语:

  • 真阳性 (TP):这代表预测为,且实际情况也是的案例;例如,我们预测它们为欺诈案例,实际上它们确实是欺诈案例。

  • 真阴性 (TN):这代表预测为不是,且实际情况也是不是的案例;例如,我们预测它们为非欺诈案例,实际上它们确实是非欺诈案例。

  • 假阳性 (FP):这代表预测为,但实际情况是不是的案例;例如,我们预测它们为欺诈案例,但实际上它们不是欺诈案例。这种类型的事件类别表示类型 I 错误。

  • 假阴性FN):这表示那些预测为,但实际上是的案例;例如,我们预测它们为非欺诈案件,实际上它们是欺诈案件。这种类型的事件类别表示的是第二类错误。

让我们以一个欺诈检测问题为例:

在前面的例子中,我们考虑了两类欺诈行为:是和否。是表示欺诈行为,否表示非欺诈行为。预测记录的总数为 825,这意味着测试了 825 笔交易。在这 825 个案例中,模型或分类器预测了 550 次是,275 次否。实际上,实际的欺诈案件为 525 个,非欺诈案件为 300 个。

让我们使用 scikit-learn 在 Python 中创建一个混淆矩阵:

# Import libraries
import pandas as pd

# read the dataset
diabetes = pd.read_csv("diabetes.csv")

# split dataset in two parts: feature set and target label
feature_set = ['pregnant', 'insulin', 'bmi', 'age','glucose','bp','pedigree']
features = diabetes[feature_set]

target = diabetes.label

# partition data into training and testing set
from sklearn.model_selection import train_test_split
feature_train, feature_test, target_train, target_test = train_test_split(features, target, test_size=0.3, random_state=1)

# import logistic regression scikit-learn model
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score # for performance evaluation

# instantiate the model
logreg = LogisticRegression(solver='lbfgs')

# fit the model with data
logreg.fit(feature_train,target_train)

# Forecast the target variable for given test dataset
predictions = logreg.predict(feature_test)

# Get prediction probability 
predictions_prob = logreg.predict_proba(feature_test)[::,1]

# Import the confusion matrix
from sklearn.metrics import plot_confusion_matrix

# Plot Confusion matrix
plot_confusion_matrix(logreg , feature_test, target_test, values_format='d')

这将产生以下输出:

在前面的例子中,我们加载了数据并将其分为两个部分:训练集和测试集。之后,我们使用逻辑回归进行了模型训练,正如在前一章中所做的那样。在这里,为了绘制混淆矩阵,我们使用了plot_confusion_matrix()方法,传入了模型对象、测试特征集、测试标签集和values_format参数。

准确率

现在,我们将计算从混淆矩阵得出的模型准确率。它告诉我们预测模型的准确性:

精确度

当模型预测为时,它的正确率有多高?这是数据集中总预测案例中正类案例的百分比。简而言之,我们可以将精确度理解为“当模型说它正确时,它到底有多正确”:

召回率

当实际为时,模型预测的频率是多少?这也被称为灵敏度。它是数据集中所有实际正类案例中,预测为正类的比例:

F-measure(F 值)

F-measure 被认为是评估模型的较好方式之一。在数据科学的许多领域,竞争模型的性能都是通过 F-measure 来评估的。它是精确度和召回率的调和均值。F1 分数的值越高,模型越好。F1 分数为精确度和召回率赋予相等的权重,这意味着它表示两者之间的平衡:

F-measure 的一个缺点是它对精确度和召回率赋予相同的权重,但在某些情况下,需要其中一个高于另一个,这也是为什么 F1 分数可能不是一个准确的度量标准。

在前面的章节中,我们看到了诸如朴素贝叶斯、决策树、KNN 和 SVM 等分类算法。我们通过使用 scikit-learn 的 accuracy_score() 来评估模型准确率,precision_score() 来评估模型精度,recall_score() 来评估模型召回率,以及 f1_score() 来评估模型的 F1 分数。

我们还可以打印分类报告,深入了解分类模型的细节。让我们创建混淆报告:

# import classification report
from sklearn.metrics import classification_report

# Create classification report
print(classification_report(target_test, predictions, target_names=['Yes(1)','No(0)']))

这将产生以下输出:

在前面的代码中,我们使用 confusion_report() 方法打印了混淆矩阵报告,传入了测试集标签、预测集或预测标签以及目标值列表参数。

ROC 曲线和 AUC

AUC-ROC 曲线是衡量和评估分类模型性能的工具。ROC接收者操作特性)是模型性能的图示化表示。它绘制了 FP 率(或 1-特异性)与 TP 率(或灵敏度)之间的二维概率图。我们还可以使用 AUC 用一个数字表示模型所覆盖的区域:

让我们使用 scikit-learn 模块创建 ROC 曲线:

# import plot_roc_curve
from sklearn.metrics import plot_roc_curve

plot_roc_curve(logreg , feature_test, target_test)

这将产生以下输出:

在前面的示例中,我们使用模型对象、测试特征集和测试标签集参数绘制了 plot_roc_curve() 方法的 ROC 图。

在 ROC 曲线中,AUC 是一种可分性度量。它告诉我们模型的类区分能力。AUC 值越高,模型在区分“欺诈”和“非欺诈”方面就越好。对于理想的分类器,AUC 等于 1:

让我们计算 AUC 分数,如下所示:

# import ROC AUC score
from sklearn.metrics import roc_auc_score

# Compute the area under ROC curve
auc = roc_auc_score(target_test, predictions_prob)

# Print auc value
print("Area Under Curve:",auc)

这将产生以下输出:

Area Under Curve: 0.8628525382755843

scikit-learn 的 metrics 类提供了 AUC 性能评估度量。roc_auc_score() 方法将接受实际标签(y_test)和预测概率(y_pred_prob)。

总结

在本章中,我们学习了分类及其技术、训练-测试划分策略和性能评估指标。这将帮助你掌握预测数据分析的重要技能。你已经学会了如何使用 scikit-learn 开发线性和非线性分类器进行预测分析。在本章的前面部分,你了解了分类基础和机器学习算法,例如朴素贝叶斯分类、决策树分类、KNN 和 SVM。后续章节中,你看到了数据划分方法和模型性能评估指标,例如准确度分数、精度分数、召回率、F1 分数、ROC 曲线和 AUC 分数。

下一章,第十一章,无监督学习——主成分分析与聚类,将重点讲解无监督机器学习技术和降维技术在 Python 中的应用。章节开始介绍降维和主成分分析。在接下来的部分中,将聚焦于聚类方法,如 k-means、层次聚类、DBSCAN 和谱聚类。