在数据科学、数据分析和机器学习领域,Python因其易学性成为初学者的首选编程语言。Python拥有庞大的在线学习社区和众多以数据为中心的库。随着数据量的激增,确保用于机器学习和预测建模等数据科学应用的数据是干净的变得尤为重要。那么,什么是干净的数据?又是什么让数据变得“脏”呢?
“脏”数据通常指的是存在错误的数据。记录重复、数据不完整或过时、解析不当都可能使数据变“脏”。这类数据需要被清洗。数据清洗(或数据净化)是指识别数据中的错误并纠正它们的过程。
数据清洗是机器学习项目中的重要步骤,本文将介绍一些基本的数据清洗技术(使用Python)。将通过一个样本数据集来学习如何在Python中进行数据清洗。将使用Kaggle上的俄罗斯住房数据集作为示例。
将通过一个样本数据集来深入了解Python中的数据清洗。首先,需要导入所需的库。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
下载数据后,使用read_csv()函数将其读入Pandas DataFrame,并指定文件路径。然后使用shape属性检查数据集中的行数和列数。以下是相应的代码:
df = pd.read_csv('housing_data.csv')
df.shape
数据集包含30,471行和292列。现在将数值列与分类列分开。
# 选择数值列
df_numeric = df.select_dtypes(include=[np.number])
numeric_cols = df_numeric.columns.values
# 选择非数值列
df_non_numeric = df.select_dtypes(exclude=[np.number])
non_numeric_cols = df_non_numeric.columns.values
已经完成了初步步骤。现在可以开始数据清洗。首先,将识别包含缺失值的列并尝试修复它们。
首先计算每个列中缺失值的百分比,然后将这些信息存储在DataFrame中。以下是相应的代码:
values_list = list()
cols_list = list()
for col in df.columns:
pct_missing = np.mean(df[col].isnull())*100
cols_list.append(col)
values_list.append(pct_missing)
pct_missing_df = pd.DataFrame()
pct_missing_df['col'] = cols_list
pct_missing_df['pct_missing'] = values_list
DataFrame pct_missing_df现在包含了每个列中缺失值的百分比以及列名。还可以利用以下代码将这些信息可视化,以便更好地理解:
pct_missing_df.loc[pct_missing_df.pct_missing > 0].plot(kind='bar', figsize=(12,8))
plt.show()
执行上述代码后,输出结果应该如下所示:一些列只有很少的值缺失,而其他列有相当一部分值缺失。现在将修复这些缺失值。修复这些缺失值有多种方法,包括:
一种方法是删除包含任何空值的观测值。当每个列中缺失值的百分比非常低时,这种方法是可行的。将删除那些在列中包含空值的观测值,这些列的空值少于0.5%。这些列将是metro_min_walk, metro_km_walk, railroad_station_walk_km, railroad_station_walk_min, 和ID_railroad_station_walk。
less_missing_values_cols_list = list(pct_missing_df.loc[(pct_missing_df.pct_missing < 0.5) & (pct_missing_df.pct_missing > 0), 'col'].values)
df.dropna(subset=less_missing_values_cols_list, inplace=True)
这将使数据集记录数减少到30,446条。
另一种处理数据集中缺失值的方法是删除那些有显著百分比值缺失的列或特征。这些列不包含很多信息,可以完全从数据集中删除。在例子中,让删除所有缺失值超过40%的列。这些列将是build_year, state, hospital_beds_raion, cafe_sum_500_min_price_avg, cafe_sum_500_max_price_avg, 和cafe_avg_price_500。
# 删除超过40%空值的列
_40_pct_missing_cols_list = list(pct_missing_df.loc[pct_missing_df.pct_missing > 40, 'col'].values)
df.drop(columns=_40_pct_missing_cols_list, inplace=True)
数据集现在有286个特征。
数据集中仍然有缺失数据。现在将填充每个数值列中的缺失值,使用该列的中位数值。
df_numeric = df.select_dtypes(include=[np.number])
numeric_cols = df_numeric.columns.values
for col in numeric_cols:
missing = df[col].isnull()
num_missing = np.sum(missing)
if num_missing > 0: # 仅对有缺失值的列填充值
med = df[col].median() # 使用中位数填充
df[col] = df[col].fillna(med)
数值列中的缺失值现在已经修复。对于分类列,将用该列的众数值替换缺失值。
df_non_numeric = df.select_dtypes(exclude=[np.number])
non_numeric_cols = df_non_numeric.columns.values
for col in non_numeric_cols:
missing = df[col].isnull()
num_missing = np.sum(missing)
if num_missing > 0: # 仅对有缺失值的列填充值
mod = df[col].describe()['top'] # 使用最频繁出现的值填充
df[col] = df[col].fillna(mod)
数据集中的所有缺失值现在都已处理。可以通过运行以下代码来验证这一点:
df.isnull().sum().sum()
如果输出为零,则意味着数据集中现在没有缺失值了。还可以将缺失值替换为特定值(如-9999或‘missing’),这将表明此处的数据原本是缺失的。这可以作为缺失值填充的替代方法。
异常值是远离大多数数据的不寻常观测值。异常值可能会显著影响机器学习模型的性能。因此,识别并处理异常值变得很重要。
以‘life_sq’列为例。首先使用describe()方法查看描述性统计数据,看看是否能从中获取任何信息。
df.life_sq.describe()
输出结果如下:
count 30446.000000
mean 33.482658
std 46.538609
min 0.000000
25% 22.000000
50% 30.000000
75% 38.000000
max 7478.000000
Name: life_sq, dtype: float64
从输出中可以清楚地看到,最大值与平均值和中位数相比异常地大。可以通过制作这个数据的箱线图来获得更好的理解。
df.life_sq.plot(kind='box', figsize=(12, 8))
plt.show()
从箱线图中可以清楚地看到,最大值(7478)的观测值是这个数据中的异常值。描述性统计、箱线图和散点图有助于识别数据中的异常值。
可以像处理缺失值一样处理异常值。可以删除认为是异常值的观测值,或者用合适的值替换异常值,或者对数据进行某种转换(如对数或指数)。在例子中,让删除‘life_sq’值为7478的记录。
# 移除life_sq列中的异常值
df = df.loc[df.life_sq < 7478]
数据有时可能包含重复值。在进行任何机器学习项目之前,从数据集中删除重复记录是很重要的。在数据中,由于ID列是唯一标识符,将通过考虑除ID列之外的所有列来删除重复记录。
# 通过考虑除ID列之外的所有列来删除重复记录
cols_other_than_id = list(df.columns)[1:]
df.drop_duplicates(subset=cols_other_than_id, inplace=True)
这将帮助删除重复记录。使用shape方法,可以检查重复记录是否确实已被删除。观测值数量现在是30,434。
通常在数据集中,值的存储类型不正确。这可能会在后续阶段造成问题,可能无法获得所需的输出,或者在执行时出现错误。一个常见的数据类型错误是日期。日期通常在Python中被解析为对象。Pandas中有一个专门的日期类型,称为DateTime。
首先检查数据中的时间戳列的数据类型。
df.timestamp.dtype
# 将时间戳转换为datetime格式
df['timestamp'] = pd.to_datetime(df.timestamp, format='%Y-%m-%d')