清洗数据
缺失数据
本节主要讲解对数据集中缺失数据的处理
-
缺失数据
-
填充缺失数据
使用统计值
使用模型 -
查找和删除缺失数据
缺失数据
当我们读入数据时发现某些值缺失!我们可以怎么处理呢?
首先,我们应该尽量搞明白为什么缺少数据点。他们是不是随机丢失了?当数据集足够大的时候,我们可以删除随机丢失的数据。如果数据由于某种原因而丢失,那么丢失数据意味着源数据为0?还是意味着某些故障?我们应该对这些非随机缺失值进行处理。例如,如果它们应该为0,则将它们设置为零。
其次,我们应该考虑所拥有的数据中有多少行是缺失的。如果有100万个数据点,而随机缺少10个点,则可以删除这些行。但是,如果有300个数据点,而缺少100个,那么我们可能会犹豫是否要删除1/3的数据。假设找不到丢失数据的根本原因,如何处理?
填充缺失数据
以下是一些填充缺失数据的方法
使用统计值
用统计值(例如平均值,中位数或众数)填充列的缺失值。这具有简单易行的优势,而且在填充的列中的方差比其他列小。列内的高方差通常对机器学习模型是有益的(假设它是真实的)。另外,这可能没有多大意义。例如,假有一组包含高度和重量的数据集缺少重量。然后,无论高度如何,都用平均值填充所有缺失的重量。我们知道身高和体重是相关的,但我们没有利用这些相关性。
让我们看一个简单的示例,它是我们第一个用统计值填充缺失值的想法。
import numpy as np
import pandas as pd
pd_series = pd.Series([5, 10, np.nan, 15, 20, np.nan, 25, 50, np.nan])
print("Average of non-missing values: {0}".format(pd_series.mean()))
pd_series = pd_series.fillna(pd_series.mean())
print(pd_series)
输出
Average of non-missing values: 20.833333333333332
0 5.000000
1 10.000000
2 20.833333
3 15.000000
4 20.000000
5 20.833333
6 25.000000
7 50.000000
8 20.833333
dtype: float64
上面,我们创建了一个Pandas Series,它只是Pandas dataframe数据的一列。在我们的Series中,我们使用np.nan添加了3个缺失值。
Pandas可以让我们轻松地使用fillna()功能填写缺失值。我们将要使用的值传递给此函数。在此示例中,我们传递了平均值。
使用模型
使用模型来学习对于缺失值似乎合理的值。基本上,利用不丢失的数据来了解丢失的变量可能是什么。在我们的身高和体重示例中,您可以使用身高来预测那些没有缺失的体重,然后将该模型应用于缺少体重的身高,以填写丢失的数据。一种流行的算法是K-Neares 相邻值。有关如何处理丢失的数据的更多想法,请看下文
查找和删除缺失数据
Pandas 因为可以用dropna()函数来剔除缺失值:
import numpy as np
import pandas as pd
# 创建一列数据集
pd_series = pd.Series([5, 10, np.nan, 15, 20, np.nan, 25, 50, np.nan])
# 剔除缺失含有数据的行
pd_series = pd_series.dropna()
print(pd_series)
输出
1.416s
0 5.0
1 10.0
3 15.0
4 20.0
6 25.0
7 50.0
dtype: float64
或者我们可以用isnull()函数来查找哪些值有缺失
import numpy as np
import pandas as pd
# 创建一列数据集
pd_series = pd.Series([5, 10, np.nan, 15, 20, np.nan, 25, 50, np.nan])
# 查找哪些行有缺失数据
print(pd_series.isnull())
输出
0 False
1 False
2 True
3 False
4 False
5 True
6 False
7 False
8 True
dtype: bool
结果返回一个新系列值,对于该系列,True值表示缺少值,而False值表示没有缺少值。
我们现在已经熟悉了丢失的数据,那么在下一小结中,我们将学习如何处理与其他数据比起来有些异常的数据。
异常值
本节主要说明什么是异常值,他们是如何产生的以及怎样处理。
- 什么是异常值
- 查找异常值
- 移除异常值
什么是异常值
清洗的另一个应用可以处理异常值。首先,如何定义异常值?这可能需要领域知识以及其他信息,但是最简单的开始方法是查看箱形图:
上图是使用以下命令计算的:
bbox = train_df['hoursperweek'].plot(kind="box")
查找异常值
在这里,“whiskers”之外的任何值都可以视为异常值。“whiskers”是从盒子中伸出的线条,是四分位间距的1.5倍。四分位间距是第25个百分位数和第75个百分位数之间的距离。
以下代码计算dataframe的所有数值变量中需要移除的数据。
q_df = train_df.quantile([.25, .75])
q_df.loc['iqr'] = q_df.loc[0.75] - q_df.loc[0.25]
q_df.loc['whisker_length'] = 1.5 * q_df.loc['iqr']
q_df.loc['max_whisker'] = q_df.loc['whisker_length'] + q_df.loc[0.75]
q_df.loc['min_whisker'] = q_df.loc[0.25] - q_df.loc['whisker_length']
q_df
此代码假定数据在一个名为train_df的dataframe中。第一行计算第25和第75个百分位数的值。然后,利用两者之间的差值获得四分位间距(iqr)。我们通过将iqr乘以1.5来获得胡须的长度,然后通过从第25个百分位数和第75个百分位数中分别减去和加上胡须长度来计算最小胡须者和最大胡须者。这段代码的输出如下所示:
在此示例中,我们可以更仔细地查看“年龄”的数值。如果我们认为使用最小或最大胡须值之外的任何值都是异常值,那么任何年龄大于78或小于-2的年龄都将被视为异常值。
尝试识别异常值的另一种简单方法是取值的标准偏差的倍数,通常为2或3倍。例如,如果年龄的标准偏差为13,平均值为30,并且认为标准偏差的3倍可能是异常值,则年龄大于69(13x3 + 30)或小于-9(30- 13x3)的值是异常值。
对于年龄,我们还可以使凭常识可以知道小于0或者大于130的任何值显然都是异常值。
综上所述,有许多方法可以检测异常值。这些方法本身就看待特征,有时您的离群值是多变量的,就重量本身可能不是异常值,但是在给定身高的情况,他就有可能是。这是一篇有关处理这些问题的更高级方法的文章:
https://www.kdnuggets.com/2017/01/3-methods-deal-outliers.html
移除异常值
一旦我们发现了异常值,该怎么办?
就像丢失数据一样,我们需要弄清楚,为什么这些异常值会出现?如果它们实际上是您数据的一部分,那么我们可能希望保留它们。如果删除它们,将使训练偏离事实。如果它们是错误的,例如年龄超过500,如果有足够的数据或输入更好的值,则可以放心删除这些行。最好的办法是,尝试发现这些异常值的产生原因并加以解决。可能是您的数据管道中断了,但是原始数据仍然很好。
最后,考虑数据从来里来的。是否来自样本?如果是这样,则可能不是非常具有代表性,因此样本中看起来像异常值的实际上不在总体中。
有许多因素需要考虑,而这些只是其中一些。重要是要考察异常值,而不是不加思索地忽略或丢弃它们。
缩放比例
本小节讨论比例缩放是如何应用于数据清洗的
- 缩放介绍
- 缩放类型
标准缩放
最小/最大缩放
缩放介绍
特征缩放对于许多机器学习算法都很重要。假如收入列的值介于100到100,000之间,年龄列的值介于0到100之间,这会引起发问题,因为这两个数据列的规模差异很大。为了解决这个问题,标准是重新缩放数据。有很多方法可以做到这一点,但是最常见的两种是:
- 标准缩放
- 最小/最大缩放
缩放类型
标准缩放
标准缩放减去平均值,然后除以标准偏差。这会将特征值集中于零,且具有单位方差。
from sklearn.preprocessing import MinMaxScaler, StandardScaler
import numpy as np
# 创建数据矩阵
data = [[-1, 2],
[-0.5, 6],
[0, 10],
[1, 18]]
print("Before Standard scaling")
print(np.mean(data, 0))
print(np.std(data, 0))
# 初始化StandardScaler
standard = StandardScaler()
# 用StandardScaler处理数据
standard_data = standard.fit_transform(data)
print("After Standard scaling")
print(np.mean(standard_data, 0))
print(np.std(standard_data, 0))
输出
Before Standard scaling
[-0.125 9. ]
[0.73950997 5.91607978]
After Standard scaling
[0. 0.]
[1. 1.]
在上面的示例中,我们创建了一个形状为(4,2)的NumPy数组。然后,我们使用StandardScaler()自动减去均值并除以每列的标准差。这是通过fit_transform()调用完成的。
我们通过打印平均值和标准偏差来检查它是否有效。我们可以看到现在两列的平均值为0,标准差为1。
最小/最大缩放
让我们看一下相同的示例,这次使用的是MinMaxScaler()。
from sklearn.preprocessing import MinMaxScaler
import numpy as np
# 创建数据矩阵
data = [[-1, 2],
[-0.5, 6],
[0, 10],
[1, 18]]
# 初始化MinMaxScaler
min_max = MinMaxScaler()
# 处理数据
min_max_data = min_max.fit_transform(data)
print(np.min(min_max_data, 0))
print(np.max(min_max_data, 0))
print(np.mean(min_max_data, 0))
print(np.std(min_max_data, 0))
输出
[0. 0.]
[1. 1.]
[0.4375 0.4375]
[0.36975499 0.36975499]
默认情况下,MinMaxScaler()将每列缩放为最小值为0且最大值为1。
我们的代码通过打印出最小值和最大值来验证这一点。我们还打印了列的均值和标准差,以查看它们分别不再是0和1。我们可以通过传递以下参数将最小,最大范围更改为所需的范围:
feature_range=(min, max)
这就是缩放数据。在下一节中,学习如果数据是分类的,则如何处理数据。
分类数据
本节讨论什么是分类数据以及Pandas如何对其进行处理。
- 分类数据简介
- 处理分类数据
标签编码
One-hot编码
分类数据简介
有时,我们会得到分类数据,这些数据是具有有限且通常为固定数量的值的变量。例如,男性和女性。机器学习算法需要数字才能起作用,那么如何处理这些数字呢?我们将讨论两种方式:
- 标签编码
- One-hot编码
处理分类数据
标签编码
标签编码通过将值转换为数字表示来工作。例如,如果我们有两个类别male和female,我们可以将它们分类为数字:
- male为0
- female为1
Pandas提供了一种category类型的简便方法来进行操作。
import pandas as pd
# Create series with male and female values
non_categorical_series = pd.Series(['male', 'female', 'male', 'female'])
# Convert the text series to a categorical series
categorical_series = non_categorical_series.astype('category')
# Print the numeric codes for each value
print(categorical_series.cat.codes)
# Print the category names
print(categorical_series.cat.categories)
输出
0 1
1 0
2 1
3 0
dtype: int8
Index(['female', 'male'], dtype='object')
在上面的代码中,我们创建了一个Pandas Series,其文本值是male或female。
然后,我们使用astype()函数强制转换列,并传递类型category。这将在我们的列中找到所有不同的值,并为每个值分配一个唯一的整数值,同时仍保留字符串值。
您可以通过添加.cat.codes到categorical_series的末尾来查看整数值。
您可以通过添加.cat.categories到categorical_series末尾来查看字符串值。
One-hot编码
One-hot编码类似,但是会为每一个类别创建一个新的列,并为每个具有该值的行填充1,否则填充零。
import pandas as pd
# Create series with male and female values
non_categorical_series = pd.Series(['male', 'female', 'male', 'female'])
# Create dummy or one-hot encoded variables
print(pd.get_dummies(non_categorical_series))
输出
female male
0 0 1
1 1 0
2 0 1
3 1 0
我们只需调用get_dummies(),它将自动为系列中的每个唯一值创建新列,并在适当时用1或0填充它们。