Python 数据分析(PYDA)第三版(六)(1)

简介: Python 数据分析(PYDA)第三版(六)

十二、Python 建模库介绍

原文:wesmckinney.com/book/modeling

译者:飞龙

协议:CC BY-NC-SA 4.0

此开放访问网络版本的《Python 数据分析第三版》现已作为印刷版和数字版的伴侣提供。如果您发现任何勘误,请在此处报告。请注意,由 Quarto 生成的本站点的某些方面与 O’Reilly 的印刷版和电子书版本的格式不同。

如果您发现本书的在线版本有用,请考虑订购纸质版无 DRM 的电子书以支持作者。本网站的内容不得复制或再生产。代码示例采用 MIT 许可,可在 GitHub 或 Gitee 上找到。

在本书中,我专注于为在 Python 中进行数据分析提供编程基础。由于数据分析师和科学家经常报告花费大量时间进行数据整理和准备,因此本书的结构反映了掌握这些技术的重要性。

您用于开发模型的库将取决于应用程序。许多统计问题可以通过简单的技术解决,如普通最小二乘回归,而其他问题可能需要更高级的机器学习方法。幸运的是,Python 已经成为实现分析方法的首选语言之一,因此在完成本书后,您可以探索许多工具。

在本章中,我将回顾一些 pandas 的特性,这些特性在您在 pandas 中进行数据整理和模型拟合和评分之间来回切换时可能会有所帮助。然后,我将简要介绍两个流行的建模工具包,statsmodelsscikit-learn。由于这两个项目都足够庞大,值得有自己的专门书籍,因此我没有尝试全面介绍,而是建议您查阅这两个项目的在线文档,以及一些其他基于 Python 的数据科学、统计学和机器学习书籍。

12.1 pandas 与模型代码之间的接口

模型开发的常见工作流程是使用 pandas 进行数据加载和清理,然后切换到建模库来构建模型本身。模型开发过程中的一个重要部分被称为特征工程,在机器学习中。这可以描述从原始数据集中提取信息的任何数据转换或分析,这些信息在建模环境中可能有用。我们在本书中探讨的数据聚合和 GroupBy 工具经常在特征工程环境中使用。

虽然“好”的特征工程的细节超出了本书的范围,但我将展示一些方法,使在 pandas 中进行数据操作和建模之间的切换尽可能轻松。

pandas 与其他分析库之间的接触点通常是 NumPy 数组。要将 DataFrame 转换为 NumPy 数组,请使用to_numpy方法:

In [12]: data = pd.DataFrame({
 ....:     'x0': [1, 2, 3, 4, 5],
 ....:     'x1': [0.01, -0.01, 0.25, -4.1, 0.],
 ....:     'y': [-1.5, 0., 3.6, 1.3, -2.]})
In [13]: data
Out[13]: 
 x0    x1    y
0   1  0.01 -1.5
1   2 -0.01  0.0
2   3  0.25  3.6
3   4 -4.10  1.3
4   5  0.00 -2.0
In [14]: data.columns
Out[14]: Index(['x0', 'x1', 'y'], dtype='object')
In [15]: data.to_numpy()
Out[15]: 
array([[ 1.  ,  0.01, -1.5 ],
 [ 2.  , -0.01,  0.  ],
 [ 3.  ,  0.25,  3.6 ],
 [ 4.  , -4.1 ,  1.3 ],
 [ 5.  ,  0.  , -2.  ]])

回到 DataFrame,正如您可能从前几章中记得的那样,您可以传递一个二维的 ndarray,其中包含可选的列名:

In [16]: df2 = pd.DataFrame(data.to_numpy(), columns=['one', 'two', 'three'])
In [17]: df2
Out[17]: 
 one   two  three
0  1.0  0.01   -1.5
1  2.0 -0.01    0.0
2  3.0  0.25    3.6
3  4.0 -4.10    1.3
4  5.0  0.00   -2.0

to_numpy方法旨在在数据是同质的情况下使用,例如所有的数值类型。如果您有异构数据,结果将是一个 Python 对象的 ndarray:

In [18]: df3 = data.copy()
In [19]: df3['strings'] = ['a', 'b', 'c', 'd', 'e']
In [20]: df3
Out[20]: 
 x0    x1    y strings
0   1  0.01 -1.5       a
1   2 -0.01  0.0       b
2   3  0.25  3.6       c
3   4 -4.10  1.3       d
4   5  0.00 -2.0       e
In [21]: df3.to_numpy()
Out[21]: 
array([[1, 0.01, -1.5, 'a'],
 [2, -0.01, 0.0, 'b'],
 [3, 0.25, 3.6, 'c'],
 [4, -4.1, 1.3, 'd'],
 [5, 0.0, -2.0, 'e']], dtype=object)

对于某些模型,您可能希望仅使用部分列。我建议使用loc索引和to_numpy

In [22]: model_cols = ['x0', 'x1']
In [23]: data.loc[:, model_cols].to_numpy()
Out[23]: 
array([[ 1.  ,  0.01],
 [ 2.  , -0.01],
 [ 3.  ,  0.25],
 [ 4.  , -4.1 ],
 [ 5.  ,  0.  ]])

一些库原生支持 pandas,并自动完成一些工作:从 DataFrame 转换为 NumPy,并将模型参数名称附加到输出表或 Series 的列上。在其他情况下,您将不得不手动执行这种“元数据管理”。

在 Ch 7.5:分类数据中,我们看过 pandas 的Categorical类型和pandas.get_dummies函数。假设我们的示例数据集中有一个非数字列:

In [24]: data['category'] = pd.Categorical(['a', 'b', 'a', 'a', 'b'],
 ....:                                   categories=['a', 'b'])
In [25]: data
Out[25]: 
 x0    x1    y category
0   1  0.01 -1.5        a
1   2 -0.01  0.0        b
2   3  0.25  3.6        a
3   4 -4.10  1.3        a
4   5  0.00 -2.0        b

如果我们想用虚拟变量替换'category'列,我们创建虚拟变量,删除'category'列,然后将结果连接:

In [26]: dummies = pd.get_dummies(data.category, prefix='category',
 ....:                          dtype=float)
In [27]: data_with_dummies = data.drop('category', axis=1).join(dummies)
In [28]: data_with_dummies
Out[28]: 
 x0    x1    y  category_a  category_b
0   1  0.01 -1.5         1.0         0.0
1   2 -0.01  0.0         0.0         1.0
2   3  0.25  3.6         1.0         0.0
3   4 -4.10  1.3         1.0         0.0
4   5  0.00 -2.0         0.0         1.0

使用虚拟变量拟合某些统计模型时存在一些微妙之处。当您拥有不仅仅是简单数字列时,使用 Patsy(下一节的主题)可能更简单且更不容易出错。

12.2 使用 Patsy 创建模型描述

Patsy是一个用于描述统计模型(尤其是线性模型)的 Python 库,它使用基于字符串的“公式语法”,受到 R 和 S 统计编程语言使用的公式语法的启发(但并非完全相同)。在安装 statsmodels 时会自动安装它:

conda install statsmodels

Patsy 在为 statsmodels 指定线性模型方面得到很好的支持,因此我将重点介绍一些主要功能,以帮助您快速上手。Patsy 的公式是一种特殊的字符串语法,看起来像:

y ~ x0 + x1

语法a + b并不意味着将a加到b,而是这些是为模型创建的设计矩阵中的patsy.dmatrices函数接受一个公式字符串以及一个数据集(可以是 DataFrame 或数组字典),并为线性模型生成设计矩阵:

In [29]: data = pd.DataFrame({
 ....:     'x0': [1, 2, 3, 4, 5],
 ....:     'x1': [0.01, -0.01, 0.25, -4.1, 0.],
 ....:     'y': [-1.5, 0., 3.6, 1.3, -2.]})
In [30]: data
Out[30]: 
 x0    x1    y
0   1  0.01 -1.5
1   2 -0.01  0.0
2   3  0.25  3.6
3   4 -4.10  1.3
4   5  0.00 -2.0
In [31]: import patsy
In [32]: y, X = patsy.dmatrices('y ~ x0 + x1', data)

现在我们有:

In [33]: y
Out[33]: 
DesignMatrix with shape (5, 1)
 y
 -1.5
 0.0
 3.6
 1.3
 -2.0
 Terms:
 'y' (column 0)
In [34]: X
Out[34]: 
DesignMatrix with shape (5, 3)
 Intercept  x0     x1
 1   1   0.01
 1   2  -0.01
 1   3   0.25
 1   4  -4.10
 1   5   0.00
 Terms:
 'Intercept' (column 0)
 'x0' (column 1)
 'x1' (column 2)

这些 Patsy DesignMatrix实例是带有附加元数据的 NumPy ndarrays:

In [35]: np.asarray(y)
Out[35]: 
array([[-1.5],
 [ 0. ],
 [ 3.6],
 [ 1.3],
 [-2. ]])
In [36]: np.asarray(X)
Out[36]: 
array([[ 1.  ,  1.  ,  0.01],
 [ 1.  ,  2.  , -0.01],
 [ 1.  ,  3.  ,  0.25],
 [ 1.  ,  4.  , -4.1 ],
 [ 1.  ,  5.  ,  0.  ]])

您可能会想知道Intercept项是从哪里来的。这是线性模型(如普通最小二乘回归)的一个约定。您可以通过在模型中添加+ 0项来抑制截距:

In [37]: patsy.dmatrices('y ~ x0 + x1 + 0', data)[1]
Out[37]: 
DesignMatrix with shape (5, 2)
 x0     x1
 1   0.01
 2  -0.01
 3   0.25
 4  -4.10
 5   0.00
 Terms:
 'x0' (column 0)
 'x1' (column 1)

Patsy 对象可以直接传递到像numpy.linalg.lstsq这样的算法中,该算法执行普通最小二乘回归:

In [38]: coef, resid, _, _ = np.linalg.lstsq(X, y, rcond=None)
• 1

模型元数据保留在design_info属性中,因此您可以重新附加模型列名称到拟合系数以获得一个 Series,例如:

In [39]: coef
Out[39]: 
array([[ 0.3129],
 [-0.0791],
 [-0.2655]])
In [40]: coef = pd.Series(coef.squeeze(), index=X.design_info.column_names)
In [41]: coef
Out[41]: 
Intercept    0.312910
x0          -0.079106
x1          -0.265464
dtype: float64

Patsy 公式中的数据转换

您可以将 Python 代码混合到您的 Patsy 公式中;在评估公式时,库将尝试在封闭范围中找到您使用的函数:

In [42]: y, X = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1) + 1)', data)
In [43]: X
Out[43]: 
DesignMatrix with shape (5, 3)
 Intercept  x0  np.log(np.abs(x1) + 1)
 1   1                 0.00995
 1   2                 0.00995
 1   3                 0.22314
 1   4                 1.62924
 1   5                 0.00000
 Terms:
 'Intercept' (column 0)
 'x0' (column 1)
 'np.log(np.abs(x1) + 1)' (column 2)

一些常用的变量转换包括标准化(均值为 0,方差为 1)和中心化(减去均值)。Patsy 具有内置函数用于此目的:

In [44]: y, X = patsy.dmatrices('y ~ standardize(x0) + center(x1)', data)
In [45]: X
Out[45]: 
DesignMatrix with shape (5, 3)
 Intercept  standardize(x0)  center(x1)
 1         -1.41421        0.78
 1         -0.70711        0.76
 1          0.00000        1.02
 1          0.70711       -3.33
 1          1.41421        0.77
 Terms:
 'Intercept' (column 0)
 'standardize(x0)' (column 1)

作为建模过程的一部分,您可以在一个数据集上拟合模型,然后基于另一个数据集评估模型。这可能是一个保留部分或稍后观察到的新数据。当应用诸如中心化和标准化之类的转换时,您在使用模型基于新数据形成预测时应当小心。这些被称为有状态转换,因为在转换新数据时必须使用原始数据集的统计数据,如均值或标准差。

patsy.build_design_matrices函数可以使用原始样本内数据的保存信息对新的样本外数据应用转换:

In [46]: new_data = pd.DataFrame({
 ....:     'x0': [6, 7, 8, 9],
 ....:     'x1': [3.1, -0.5, 0, 2.3],
 ....:     'y': [1, 2, 3, 4]})
In [47]: new_X = patsy.build_design_matrices([X.design_info], new_data)
In [48]: new_X
Out[48]: 
[DesignMatrix with shape (4, 3)
 Intercept  standardize(x0)  center(x1)
 1          2.12132        3.87
 1          2.82843        0.27
 1          3.53553        0.77
 1          4.24264        3.07
 Terms:
 'Intercept' (column 0)
 'standardize(x0)' (column 1)
 'center(x1)' (column 2)]

因为 Patsy 公式中加号(+)并不表示加法,所以当您想按名称从数据集中添加列时,您必须将它们包装在特殊的I函数中:

In [49]: y, X = patsy.dmatrices('y ~ I(x0 + x1)', data)
In [50]: X
Out[50]: 
DesignMatrix with shape (5, 2)
 Intercept  I(x0 + x1)
 1        1.01
 1        1.99
 1        3.25
 1       -0.10
 1        5.00
 Terms:
 'Intercept' (column 0)
 'I(x0 + x1)' (column 1)

Patsy 在patsy.builtins模块中还有几个内置转换。请查看在线文档以获取更多信息。

分类数据有一类特殊的转换,接下来我会解释。

分类数据和 Patsy

非数字数据可以以多种不同的方式转换为模型设计矩阵。本书不涉及这个主题的完整处理,最好是在统计课程中学习。

当您在 Patsy 公式中使用非数字术语时,默认情况下它们会被转换为虚拟变量。如果有一个截距,将会有一个级别被排除以避免共线性:

In [51]: data = pd.DataFrame({
 ....:     'key1': ['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'],
 ....:     'key2': [0, 1, 0, 1, 0, 1, 0, 0],
 ....:     'v1': [1, 2, 3, 4, 5, 6, 7, 8],
 ....:     'v2': [-1, 0, 2.5, -0.5, 4.0, -1.2, 0.2, -1.7]
 ....: })
In [52]: y, X = patsy.dmatrices('v2 ~ key1', data)
In [53]: X
Out[53]: 
DesignMatrix with shape (8, 2)
 Intercept  key1[T.b]
 1          0
 1          0
 1          1
 1          1
 1          0
 1          1
 1          0
 1          1
 Terms:
 'Intercept' (column 0)
 'key1' (column 1)

如果从模型中省略截距,那么每个类别值的列将包含在模型设计矩阵中:

In [54]: y, X = patsy.dmatrices('v2 ~ key1 + 0', data)
In [55]: X
Out[55]: 
DesignMatrix with shape (8, 2)
 key1[a]  key1[b]
 1        0
 1        0
 0        1
 0        1
 1        0
 0        1
 1        0
 0        1
 Terms:
 'key1' (columns 0:2)

数值列可以使用C函数解释为分类列:

In [56]: y, X = patsy.dmatrices('v2 ~ C(key2)', data)
In [57]: X
Out[57]: 
DesignMatrix with shape (8, 2)
 Intercept  C(key2)[T.1]
 1             0
 1             1
 1             0
 1             1
 1             0
 1             1
 1             0
 1             0
 Terms:
 'Intercept' (column 0)
 'C(key2)' (column 1)

当您在模型中使用多个分类项时,情况可能会更加复杂,因为您可以包括形式为key1:key2的交互项,例如在方差分析(ANOVA)模型中使用:

In [58]: data['key2'] = data['key2'].map({0: 'zero', 1: 'one'})
In [59]: data
Out[59]: 
 key1  key2  v1   v2
0    a  zero   1 -1.0
1    a   one   2  0.0
2    b  zero   3  2.5
3    b   one   4 -0.5
4    a  zero   5  4.0
5    b   one   6 -1.2
6    a  zero   7  0.2
7    b  zero   8 -1.7
In [60]: y, X = patsy.dmatrices('v2 ~ key1 + key2', data)
In [61]: X
Out[61]: 
DesignMatrix with shape (8, 3)
 Intercept  key1[T.b]  key2[T.zero]
 1          0             1
 1          0             0
 1          1             1
 1          1             0
 1          0             1
 1          1             0
 1          0             1
 1          1             1
 Terms:
 'Intercept' (column 0)
 'key1' (column 1)
 'key2' (column 2)
In [62]: y, X = patsy.dmatrices('v2 ~ key1 + key2 + key1:key2', data)
In [63]: X
Out[63]: 
DesignMatrix with shape (8, 4)
 Intercept  key1[T.b]  key2[T.zero]  key1[T.b]:key2[T.zero]
 1          0             1                       0
 1          0             0                       0
 1          1             1                       1
 1          1             0                       0
 1          0             1                       0
 1          1             0                       0
 1          0             1                       0
 1          1             1                       1
 Terms:
 'Intercept' (column 0)
 'key1' (column 1)
 'key2' (column 2)
 'key1:key2' (column 3)

Patsy 提供了其他转换分类数据的方法,包括具有特定顺序的项的转换。有关更多信息,请参阅在线文档。


Python 数据分析(PYDA)第三版(六)(2)https://developer.aliyun.com/article/1482397

相关文章
|
2天前
|
机器学习/深度学习 数据挖掘 Python
Python数据分析 | 泰坦尼克逻辑回归(下)
Python数据分析 | 泰坦尼克逻辑回归
7 1
|
2天前
|
机器学习/深度学习 数据挖掘 BI
Python数据分析 | 泰坦尼克逻辑回归(上)
Python数据分析 | 泰坦尼克逻辑回归
15 0
|
2天前
|
数据采集 数据挖掘 Python
Python数据分析 | 线性回归
Python数据分析 | 线性回归
11 1
|
2天前
|
机器学习/深度学习 数据采集 自然语言处理
10个 Python 小技巧,覆盖了90%的数据分析需求!_countries_lat_lon
10个 Python 小技巧,覆盖了90%的数据分析需求!_countries_lat_lon
|
3天前
|
数据采集 人工智能 数据挖掘
「一行分析」利用12000条招聘数据分析Python学习方向和就业方向
「一行分析」利用12000条招聘数据分析Python学习方向和就业方向
|
5天前
|
数据采集 数据可视化 数据挖掘
利用Python和Pandas库优化数据分析流程
在当今数据驱动的时代,数据分析已成为企业和个人决策的重要依据。Python作为一种强大且易于上手的编程语言,配合Pandas这一功能丰富的数据处理库,极大地简化了数据分析的流程。本文将探讨如何利用Python和Pandas库进行高效的数据清洗、转换、聚合以及可视化,从而优化数据分析的流程,提高数据分析的效率和准确性。
|
5天前
|
SQL 数据采集 数据挖掘
构建高效的Python数据处理流水线:使用Pandas和NumPy优化数据分析任务
在数据科学和分析领域,Python一直是最受欢迎的编程语言之一。本文将介绍如何通过使用Pandas和NumPy库构建高效的数据处理流水线,从而加速数据分析任务的执行。我们将讨论如何优化数据加载、清洗、转换和分析的过程,以及如何利用这些库中的强大功能来提高代码的性能和可维护性。
|
6月前
|
数据可视化 数据挖掘 Python
【Python】数据分析:matplotlib折线图
【Python】数据分析:matplotlib折线图
63 0
|
8月前
|
机器学习/深度学习 数据采集 数据挖掘
Python 数据分析入门教程:Numpy、Pandas、Matplotlib和Scikit-Learn详解
Python 数据分析入门教程:Numpy、Pandas、Matplotlib和Scikit-Learn详解
146 0
|
5天前
|
数据可视化 数据挖掘 Python
Python中数据分析工具Matplotlib
【4月更文挑战第14天】Matplotlib是Python的数据可视化库,能生成多种图表,如折线图、柱状图等。以下是一个绘制简单折线图的代码示例: ```python import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5] y = [2, 4, 6, 8, 10] plt.figure() plt.plot(x, y) plt.title('简单折线图') plt.xlabel('X轴') plt.ylabel('Y轴') plt.show() ```
14 1