数据预处理Data Preprocessing

960 阅读6分钟

该文章介绍:

处理缺失值、处理噪声数据、数据归一化、汇总、抽样、离散化和主成分分析等概念。

数据质量问题(Data Quality Issues)

糟糕的数据质量会对数据挖掘产生不利影响。常见的数据质量问题包括噪声、离群值、缺失值和重复数据。本节介绍Python代码的例子,以缓解其中一些数据质量问题。我们从一个来自UCI机器学习资源库的示例数据集开始,其中包含乳腺癌患者的信息。我们将首先使用Pandas read_csv()函数下载该数据集,并显示其前5个数据点。

import pandas as pd

data = pd.read_csv('archive.ics.uci.edu/ml/machine-…', header=None) 

data.columns = ['Sample code', 'Clump Thickness', 'Uniformity of Cell Size', 'Uniformity of Cell Shape', 'Marginal Adhesion', 'Single Epithelial Cell Size', 'Bare Nuclei', 'Bland Chromatin', 'Normal Nucleoli', 'Mitoses','Class'] 

data = data.drop(['Sample code'],axis=1) 

print('Number of instances = %d' % (data.shape[0])) 

print('Number of attributes = %d' % (data.shape[1])) data.head()

1.1 缺失的数据(missing data)

一个对象缺少一个或多个属性值是很正常的。在某些情况下,信息没有被收集;而在其他情况下,一些属性对数据实例不适用。本节介绍了处理缺失值的不同方法的例子。 根据数据的描述(archive.ics.uci.edu/ml/datasets…

import numpy as np data = data.replace('?',np.NaN) 

print('Number of instances = %d' % (data.shape[0])) 

print('Number of attributes = %d' % (data.shape[1])) 

print('Number of missing values:') 

for col in data.columns: 

    print('\t%s: %d' % (col,data[col].isna().sum()))

请注意,只有 "Bare Nuclei "列包含缺失值。在下面的例子中,"Bare Nuclei "列中的缺失值被该列的中值所取代。替换前和替换后的值显示的是数据点的子集。

data2 = data['Bare Nuclei'] 

print('Before replacing missing values:')

print(data2[20:25])

data2 = data2.fillna(data2.median())

print('\nAfter replacing missing values:')

print(data2[20:25])

另一种常见的方法是丢弃包含缺失值的数据点,而不是替换缺失值。这可以通过对数据框架应用dropna()函数轻松实现。

1.2 Outliers

离群值是指具有与数据集的其他部分有很大差异的特征的数据实例。在下面的示例代码中,我们将绘制一个boxplot来识别表中包含异常值的列。请注意,所有列中的值(除了'Bare Nuclei')最初都存储为'int64',而'Bare Nuclei'列中的值则存储为字符串对象(因为该列最初包含'?'等字符串,用于表示缺失值)。因此,在创建boxplot之前,我们必须先将该列转换成数值。否则,在绘制boxplot时将不会显示该列。

data2 = data.drop(['Class'],axis=1) 

data2['Bare Nuclei'] = pd.to_numeric(data2['Bare Nuclei']) 

data2.boxplot(figsize=(20,3))

波形图表明,只有5个列(边缘粘附、单个上皮细胞大小、平淡的染色质、正常的核仁和Mitoses)包含异常的高值。为了摒弃异常值,我们可以计算每个属性的Z-score,并删除那些包含异常高或低Z-score的属性的实例(例如,如果Z > 3或Z <= -3)。

下面的代码显示了对数据列进行标准化的结果。请注意,缺失值(NaN)不受标准化过程的影响。

Z = (data2-data2.mean())/data2.std() 

Z[20:25]

下面的代码显示了丢弃Z>3或Z<=-3的列的结果。

print('Number of rows before discarding outliers = %d' % (Z.shape[0])) 

Z2 = Z.loc[((Z > -3).sum(axis=1)==9) & ((Z <= 3).sum(axis=1)==9),:]

print('Number of rows after discarding missing values = %d' % (Z2.shape[0]))

1.3 重复数据(Duplicate Data)

一些数据集,特别是通过合并多个数据源获得的数据集,可能包含重复或接近重复的实例。术语重复数据删除通常用来指处理重复数据问题的过程。在下面的例子中,我们首先检查乳腺癌数据集中的重复实例。

dups = data.duplicated()

print('Number of duplicate rows = %d' % (dups.sum()))

data.loc[[11,28]]

duplicated()函数将返回一个布尔数组,该数组表示每一行是否与表中的前一行重复。结果表明,在乳腺癌数据集中有236条重复的行。例如,行索引为11的实例与行索引为28的实例具有相同的属性值。虽然这样的重复行可能对应不同个体的样本,但在这个假设的例子中,我们假设重复行是取自同一个体的样本,并在下面说明如何删除重复行。

聚合(Aggregation)

数据聚合是一项预处理任务,在这项任务中,两个或多个对象的值被合并成一个对象。聚合的动机包括:(1)减少需要处理的数据规模;(2)改变分析的粒度(从细尺度到粗尺度);(3)提高数据的稳定性。 在下面的例子中,我们将使用位于底特律地铁机场的气象站的每日降水时间序列数据。原始数据是从气候数据在线网站(www.ncdc.noaa.gov/cdo-web/)获得… 下面的代码将加载降水时间序列数据,并绘制其每日时间序列的线图。

daily = pd.read_csv('DTW_prec.csv', header='infer')

daily.index = pd.to_datetime(daily['DATE'])

daily = daily['PRCP']

ax = daily.plot(kind='line',figsize=(15,3))

ax.set_title('Daily Precipitation (variance = %.4f)' % (daily.var()))

观察到每日的时间序列似乎相当混乱,并且在不同的时间步长之间变化很大。时间序列可以按月进行分组和汇总,以获得总的月降水量值。与每日时间序列相比,所得到的时间序列似乎变化更为平稳。

monthly = daily.groupby(pd.Grouper(freq='M')).sum()

ax = monthly.plot(kind='line',figsize=(15,3))

ax.set_title('Monthly Precipitation (variance = %.4f)' % (monthly.var()))

在下面的例子中,将每日降水时间序列按年份进行分组和汇总,得到年降水量值。

annual = daily.groupby(pd.Grouper(freq='Y')).sum() 

ax = annual.plot(kind='line',figsize=(15,3))

ax.set_title('Annual Precipitation (variance = %.4f)' % (annual.var()))

采样(Sampling)

抽样是一种常用的方法,以方便:(1)进行探索性数据分析的数据缩减和将算法扩展到大数据应用中;(2)量化因数据分布不同而产生的不确定性。数据抽样有多种方法,如不替换的抽样,即从数据集中删除每个被选实例;替换的抽样,即不删除每个被选实例,从而允许其在样本中被选择一次以上。 在下面的例子中,我们将对从UCI机器学习库中获得的乳腺癌数据集应用有替换和无替换的抽样。我们最初显示表的前五条记录。

在下面的代码中,从原始数据中随机选取一个大小为3的样本(不替换)。

sample = data.sample(n=3)

sample

在下一个例子中,我们随机选择1%的数据(不替换)并显示所选样本。函数的 random_state 参数指定了随机数发生器的种子值。

sample = data.sample(frac=0.01, random_state=1)

sample

最后,我们用替换法进行抽样,创建一个样本,其大小等于整个数据的1%。你应该可以通过增加样本大小来观察样本中的重复实例。

sample = data.sample(frac=0.01, replace=True, random_state=1)

sample

离散化(Discretization)

分散是一个数据预处理步骤,通常用于将一个连续值属性转换为一个分类属性。下面的例子说明了两种简单但广泛使用的无监督离散方法(等宽和等深),应用于乳腺癌数据集的 "Clump Thickness "属性。 首先,我们绘制一个直方图,显示属性值的分布。也可以应用value_counts()函数来统计每个属性值的频率。

data['Clump Thickness'].hist(bins=10)

data['Clump Thickness'].value_counts(sort=False)

对于等宽法,我们可以应用cut()函数将属性分解成4个区间宽度相近的bin。value_counts()函数可以用来确定每个bin中的实例数。

bins = pd.cut(data['Clump Thickness'],4)

bins.value_counts(sort=False)

对于等频法,可以使用qcut()函数将数值分成4个bin,使每个bin的实例数几乎相同。

bins = pd.qcut(data['Clump Thickness'],4)

bins.value_counts(sort=False)

主成分分析PCA(Principal Component Analysis)

主成分分析(PCA)是一种经典的减少数据中属性数量的方法,将数据从原来的高维空间投射到一个低维空间。PCA所创建的新属性(也称为成分)具有以下特性。(1)它们是原始属性的线性组合,(2)它们是相互正交(垂直)的,(3)它们能捕捉到数据中最大的变化量。 下面的例子说明了PCA在一个图像数据集上的应用。有16个RGB文件,每个文件的大小为111 x 111像素。下面的示例代码将读取每个图像文件,并将RGB图像转换为111 x 111 x 3 = 36963个特征值。这将创建一个大小为16×36963的数据矩阵。

使用PCA,数据矩阵被投影到它的前两个主成分。原始图像数据的投影值存储在一个名为projection的pandas DataFrame对象中。

最后,我们画一个散点图来显示投影值。观察到汉堡、饮料和面食的图像都投射到同一个区域。但是,炸鸡的图像(图中显示为黑色方块)比较难分辨。