本文系转发自:https://blog.csdn.net/cyan_soul

前些天报名参加了 Kaggle 的 Data Cleaning 5天挑战,5天的任务如下:

  • Day 1: Handling missing values
  • Day 2: Data scaling and normalization
  • Day 3: Cleaning and parsing dates
  • Day 4: Fixing encoding errors (no more messed up text fields!)
  • Day 5: Fixing inconsistent data entry & spelling errors

今天是第一天,任务是处理数据集中的缺失值。活动的主持人 Rachael Tatman 给出的操作步骤如下:

  1. Take a first look at the data
  2. See how many missing data points we have
  3. Figure out why the data is missing
  4. Drop missing values
  5. Filling in missing values

我们一步一步来进行操作~


1、观察数据

首先我们在 notebook 中加载需要清理的数据集,数据集的位置可以在本地也可以在服务器上。今天官方例子中的数据集是关于美国橄榄球比赛的,然后我们动手去做的是关于旧金山建筑许可证的数据集。

引入 pandas 和 numpy 包,从给出的路径读数据集,

# modules we'll use
import pandas as pd
import numpy as np

# read in all our data
sf_permits = pd.read_csv("../input/building-permit-applications-data/Building_Permits.csv")

# set seed for reproducibility
np.random.seed(0) 

然后用 sample(10) 方法随机抽取数据集中的 10 条数据,结果中有很多数据格被标记了 "NaN" ,这些就是我们需要处理的缺失值。

sf_permits.sample(10)

2、观察缺失值的数量

现在我们知道了数据集中存在缺失值,再来看看每一个 column 下缺失值的具体数量(由于 column 过多我们只选了前 15 列)。

# get the number of missing data points per column
missing_values_count = sf_permits.isnull().sum()

# look at the # of missing points in the first ten columns
missing_values_count[0:15]

然后可以进一步看看数据集中缺失值的数目占总数的百分比,结果约为 26.26%,四分之一的数据都缺失了!

# how many total missing values do we have?
total_cells = np.product(sf_permits.shape)
total_missing = missing_values_count.sum()

# percent of data that is missing
(total_missing/total_cells) * 100

3、分析出现缺失值的原因

这一部分的重点之一是我们对数据的直觉,Rachael 所用的说法是 "data intuition",也就是说我们需要搞清楚我们面对的数据集为什么如此,以及对我们后续的数据分析会有什么样的影响。由于缺乏经验,入门者这部分可能比较困扰。我们需要考虑的问题之一是:

某个数据的缺失是因为它没有被记录还是根本不存在?

如果一个数据值缺失是因为它根本不存在,那么我们就没有必要去猜它可能的值,我们需要做的就是让它继续为 NaN;如果一个数据值缺失是因为没有被记录,我们就应该基于与它同行同列的其他值,来猜想它的可能值。

拿当前的数据集做例子,我们来看一下 Street Number Suffix 和 Zipcode 的缺失值:

missing_values_count = sf_permits.isnull().sum()
missing_values_count[['Street Number Suffix', 'Zipcode']]

我们看到 Street Number Suffix 下有大量缺失值,由于它对地址来说并不是一个普遍存在的数据,所以我猜想它的缺失值根本不存在;有少量的 Zipcode 数据缺失,由于每个地址的邮编一定存在,所以它应该是没有被记录。


4、剔除缺失值

如果你实在急于做分析,可以采取的方案之一就是剔除掉任何包含缺失值的行或列。但这种方法是并不推荐,要想得到更好的分析结果,还是要先合理地处理缺失值。

如果确定想要剔除掉含有缺失值的数据行,可以直接使用 pandas 的 dropna() 方法:

# remove all the rows that contain a missing value
sf_permits.dropna()

但是我们得到的结果是 0 rows × 43 columns,因为每一行都存在缺失值!

再剔除含有缺失值的数据列:

# remove all columns with at least one missing value
columns_with_na_dropped = sf_permits.dropna(axis=1)
columns_with_na_dropped.head()

看一下剔除空值前后的 column 数目对比:

# just how much data did we lose?
print("Columns in original dataset: %d \n" % sf_permits.shape[1])
print("Columns with na's dropped: %d" % columns_with_na_dropped.shape[1])

5、自动补全缺失值

除了直接 drop 掉含有缺失值的行或列,另一个方案是去补全缺失的值。这部分我们先截取一部分 column 的数据进行处理,便于观察。

# get a small subset of the sf_permits dataset
subset_sf_permits = sf_permits.loc[:,"Street Number Suffix":"Issued Date"].head()
subset_sf_permits

如果数据的类型都是数字,我们可以考虑把所有的缺失值都填为 0:

# replace all NA's with 0
subset_sf_permits.fillna(0)

但该数据集中,有 string 型的数据,还有另一种选择就是将空值置为与它相邻的下一行对应的数据,没有下一行数据就置为 0:

# comes directly after it and then 
subset_sf_permits.fillna(method = "bfill", axis=0).fillna("0")

处理不同类型的数据集,需要采取不同的方法,还可以用相应 column 的平均值来补全该列的缺失值等。

这就是 5 Day Challenge 第一天的内容,总地来说是非常基础的清洗数据方法,完毕~