在数据分析领域,pandas可能是应用最为广泛的库。pandas基于强大的NumPy库构建,它提供了快速且灵活的数据结构,可以用来处理现实世界中的数据集。原始数据通常用表格形式呈现并通过.csv 格式文件进行分享。pandas为导入.csv文件提供了便捷的接口并用一种名为DataFrame的数据结构进行存储,这使得在Python中操作数据变得非常轻松。

pandas DataFrame是一个二维数据结构,你可以把它看作Excel的单元格。DataFrame使你能够通过简单的指令导入.csv文件:

import pandas as pd
df = pd.read_csv("raw_data.csv")

数据导入为DataFrame类型之后,我们便可以轻易地对其进行数据分析。我们将通过鸢尾属植物数据集(Iris flower Data Set)来讲解。鸢尾属植物数据集是一个很常用的数据集,它包含了几类鸢尾属植物的测量数据(萼片的长度和宽度,花瓣的长度和宽度)。首先,让我们导入加州大学欧文分校(UCI)免费提供的数据集。注意,pandas可以直接从URL导入数据集:

URL = \
'*****://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
df = pd.read_csv(URL, names = ['sepal_length', 'sepal_width',
'petal_length', 'petal_width', 'class'])

现在数据已经存入DataFrame,我们可以很方便地操作数据了。然后来获取数据集的汇总信息,因为了解即将要操作的数据集是很重要的。

print(df.info())

代码的执行结果如图1-9所示。

图1-9

数据集有150行,每一行有5列,其中有4列是数值形式的信息,包括sepal_ length、sepal_width、petal_length和petal_width。另外还有一列包含了非数值形式的信息,表示花的种类。

我们可以通过调用describe函数快速获取4个数值列的统计信息:

print(df.describe())

输出结果如图1-10所示。

图1-10

下一步让我们看看表中前10行的数据:

print(df.head(10))

输出结果如图1-11所示。

图1-11

很简单,对吧?pandas同样可以帮助我们轻松地进行数据清洗。例如,下面的操作可以过滤并筛选sepal_length大于5.0的行:

df2 = df.loc[df['sepal_length'] > 5.0, ]

输出结果如图1-12所示。

图1-12

通过loc命令我们可以获取一组行和列中的数据。

探索性数据分析(EDA)也许可以称得上是机器学习工作流里最重要的一个步骤了,pandas使我们可以非常轻松地利用Python进行数据可视化。pandas提供了基于matplotlib的高级应用程序接口(API),这使得利用DataFrame数据绘制图表变得非常容易。

举个例子,可以通过对鸢尾属植物数据集进行可视化来揭示一些重要的信息。首先绘制散点图观察sepal_width 和sepal_length的关系。我们可以通过DataFrame. plot.scatter()方法轻松创建散点图,这个方法是所有DataFrame的内建方法。

# 为不同的类别定义不同的散点图图标
import matplotlib.pyplot as plt
marker_shapes = ['.', '^', '*']
# 然后绘制散点图 
ax = plt.axes()
for i, species in enumerate(df['class'].unique()):
    species_data = df[df['class'] == species]
    species_data.plot.scatter(x='sepal_length', y='sepal_width',marker=
                                marker_shapes[i],s=100,title="Sepal Width  
                                    vs Length by Species",label=species,
figsize=(10,7), ax=ax)

输出的散点图如图1-13所示。

图1-13

从散点图中我们可以洞察出一些有趣的信息。首先,sepal_width和sepal_length的关系和种类相关。Setosa(点)的sepal_width和sepal_length差不多是线性关系。相对于Setosa而言,versicolor(三角)和virginica(星号)的sepal_length要大得多。如果我们要设计一个机器学习算法来预测花的种类,那么sepal_width和sepal_length是模型需要包含的一组重要特征。

然后,画出直方图看看分布情况。和散点图一样,pandas DataFrame提供了内建的方法用于绘制直方图,使用DataFrame.plot.hist函数:

df['petal_length'].plot.hist(title='Histogram of Petal Length')

输出结果如图1-14所示。

图1-14

可以看到花瓣长度是一种双峰分布。相对于其他类型的花,某种类型的花的花瓣长度更短。同样也可以画出数据的箱线图(boxplot)。箱线图是一种重要的数据可视化工具,数据科学家使用箱线图,并基于第一四分位数、中位数、第三四分位数来理解数据的分布情况:

df.plot.box(title='Boxplot of Sepal Length & Width, and Petal Length &
Width')

输出结果如图1-15所示。

图1-15

从箱线图我们可以看出sepal_width的方差远小于其他变量,而petal_length则有着最大的方差。

使用pandas直接进行数据可视化是如此得简单方便。请记住,探索性数据分析在机器学习工作流中是至关重要的一步,在本书的其他项目中,我们都会对其进行探索性数据分析。

最后,让我们看看如何使用pandas进行数据预处理,尤其是如何对类别变量进行编码以及填补缺失值。

1.编码类别变量

在机器学习项目中,数据集含有类别变量是很常见的情况。以下是一些类别变量的例子。

性别:男性、女性。

日期:星期一、星期二、星期三、星期四、星期五、星期六、星期日。

国家:美国、英国、中国、日本。

机器学习算法(例如神经网络)是无法处理类别变量的,因为它只接收数值变量。为此我们需要在将类别变量输入机器学习算法前对其进行预处理。

将类别变量转化为数值变量的一个常用方法是独热编码(One-hot encoding),可在pandas中通过get_dummies函数实现。独热编码将n个类别变量转换为n个二元特征。案例如图1-16所示。

图1-16

从本质上看,转换后的特征是二元特征,如果表示原本的特征则置为1,否则置为0。可以想象,如果为此手动编写代码会很麻烦。幸运的是,pandas提供一个便捷的函数帮你处理这件事。首先,让我们使用图1-16中的数据在pandas中创建一个DataFrame:

df2 = pd.DataFrame({'Day': ['Monday','Tuesday','Wednesday',
                            'Thursday','Friday','Saturday',
'Sunday']})

输出如图1-17所示。

图1-17

在pandas中对原始数据的分类特征进行独热编码,只需要调用下面的函数:

print(pd.get_dummies(df2))

输入如图1-18所示。

图1-18

2.填充缺失数据

正如前面所探讨的,填充缺失数据是机器学习工作流中的必要步骤。真实世界的数据集非常杂乱而且通常包含缺失的数据。大多数的机器学习模型,例如神经网络遇到缺失数据是不能工作的,因此我们必须在将数据传入模型之前对其进行预处理。pandas使得处理缺失数据变得非常容易。

我们会使用前面提到的鸢尾属植物数据集来讲解如何填充缺失数据。鸢尾属植物数据集中原本并没有缺失数据,为了这个练习,我们故意删掉其中一些数据。下面的代码会在数据集中随机选择10行数据并删除其中的sepal_length值:

import numpy as np
import pandas as pd
# 导入iris数据集
URL = \
'*****://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
df = pd.read_csv(URL, names = ['sepal_length', 'sepal_width',
                               'petal_length', 'petal_width', 'class'])
# 随机选择10行
random_index = np.random.choice(df.index, replace= False, size=10)
# 将这些列中的sepal_length设置为None
df.loc[random_index,'sepal_length'] = None

让我们使用修改后的数据集,看看应该如何处理缺失的数据。首先,查看有哪些缺失的数据:

print(df.isnull().any())

print函数的输出结果如图1-19所示。

果不其然,pandas告诉我们sepal_length中有缺失的数据。这个命令对找到数据集中的缺失数据很有用。

处理缺失数据的一个办法是把它们所在的行直接移除。pandas提供了一个非常方便的函数dropna来完成这个操作:

print("Number of rows before deleting: %d" % (df.shape[0]))
df2 = df.dropna()
print("Number of rows after deleting: %d" % (df2.shape[0]))

输出结果如图1-20所示。

图1-19

图1-20

另外一个方法是将缺失的sepal_length用其他sepal_length的均值代替:

df.sepal_length = df.sepal_length.fillna(df.sepal_length.mean())

在pandas中使用df.means()计算平均值时,pandas会自动排除缺失的值。

现在,让我们确认数据集中不再包含缺失值(如图1-21所示)。

图1-21

缺失值的问题解决后,我们可以将DataFrame传递到机器学习模型中了。

我们已经了解了如何使用pandas导入.csv格式的表格数据,并使用pandas内置函数进行预处理和数据可视化。在本书的余下内容中,如果数据是表格形式的,我们还会使用pandas。pandas在数据预处理和探索性数据分析中将起到至关重要的作用,在后续的章节我们会见证这一点。