丢弃缺失值 & 通过自动化工作流补全
这是来自 Kaggle Learn 的 Data Cleaning 课程。
在这个课程中,你将会学习如何处理一些常见的数据清洗问题,自己动手完成五个练习,它们都是一些真实的、杂乱的数据集。
初窥数据集 首先我们导入将要使用到的库和数据集。作为范例,这里使用到了美国足球比赛发生事件的数据集。
1 2 3 4 5 6 7 8 9 import pandas as pdimport numpy as npnfl_data = pd.read_csv("" ) np.random.seed(0 )
当我们获得一个新的数据集的时候,我们需要做的第一件事情就是查看其中的一部分数据。这将有助于确定数据是否正确读入并且给我们一些进行下一步操作的启示。在这一案例中,缺失数据将会以NaN
或者None
的形式出现。
Date
GameID
Drive
qtr
down
time
TimeUnder
TimeSecs
PlayTimeDiff
SideofField
…
yacEPA
Home_WP_pre
Away_WP_pre
Home_WP_post
Away_WP_post
Win_Prob
WPA
airWPA
0
2009-09-10
2009091000
1
1
NaN
15:00
15
3600.0
0.0
TEN
…
NaN
0.485675
0.514325
0.546433
0.453567
0.485675
0.060758
NaN
1
2009-09-10
2009091000
1
1
1.0
14:53
15
3593.0
7.0
PIT
…
1.146076
0.546433
0.453567
0.551088
0.448912
0.546433
0.004655
-0.032244
2
2009-09-10
2009091000
1
1
2.0
14:16
15
3556.0
37.0
PIT
…
NaN
0.551088
0.448912
0.510793
0.489207
0.551088
-0.040295
NaN
3
2009-09-10
2009091000
1
1
3.0
13:35
14
3515.0
41.0
PIT
…
-5.031425
0.510793
0.489207
0.461217
0.538783
0.510793
-0.049576
0.106663
4
2009-09-10
2009091000
1
1
4.0
13:27
14
3507.0
8.0
PIT
…
NaN
0.461217
0.538783
0.558929
0.441071
0.461217
0.097712
NaN
啊啊啊我们已经可以看到缺失数据的存在了!
数据集中到底有多少缺失数据点呢? 下面我们看看每一列都有多少缺失值
1 2 3 4 5 missing_values_count = nfl_data.isnull().sum () missing_values_count[0 :10 ]
Column Name
Missing value numbers
Date
0
GameID
0
Drive
0
qtr
0
down
61154
time
0
TimeUnder
224
TimeSecs
224
PlayTimeDiff
444
SideofField
528
看起来数据集中的缺失值还不少。此时计算数据的缺失百分比有助于我们俩了解问题的严重性。
1 2 3 4 5 6 7 8 9 10 total_cells = np.product(nfl_data.shape) total_missing = missing_values_count.sum () percent_missing = (total_missing/total_cells)*100 print (percent_missing)Out[1 ]: 24.87214126835169
哦偶,几乎四分之一的数据产生了缺失。那么下一步,我们就是要更仔细地查看一下每一列地缺失情况并且搞清楚究竟发生了什么状况。
搞清楚为什么数据会缺失 数据直觉 (或者说是数据敏感度 ?)是我们在进入数据科学领域非常关键的一点,简单来说就是要真切的对手头的数据进行观察并且尝试搞清楚为什么它会这样子以及它会对我们的数据分析产生什么影响。这可能会是数据科学令人感到非常沮丧的一部分,特别是当你初入一个领域并且没有相关的经验的时候。当面对缺失值的时候,你需要利用你的直觉想清楚为什么这个值会缺失。其中有一个十分重要的问题,或许你可以常常反问自己。
Is this value missing because it wasn’t recorded or because it doesn’t exist?
这个值缺失究竟是因为它没有被记录还是因为它不存在?
如果一个数据缺失仅仅是因为它压根不存在,那么你根本不需要费劲去猜它原来究竟是什么,你可能只是想让它保持NaN
就行了。如果一个数据缺失是因为它没有被记录,那么你可以根据这一列的其他数据尝试去猜它的值究竟是什么。
1 2 missing_values_count[0 :10 ]
(undone)
丢弃缺失值 如果你很着急或者没有什么理由搞清楚这些缺失值产生的原因,那么你可以选择简单地把含有缺失值的行或者列直接删除。(贴士:我通常不建议在一些重要的项目上使用这种方法,往往花费时间去浏览你的数据并且将每一列中所含缺失值都看一遍以真正了解你的数据集)
Date
GameID
Drive
qtr
down
time
TimeUnder
TimeSecs
PlayTimeDiff
SideofField
…
yacEPA
Home_WP_pre
Away_WP_pre
Home_WP_post
Away_WP_post
Win_Prob
WPA
airWPA
好家伙,看起来我们直接将所有数据都删除了!这是因为我们的每一行数据中都至少含有一个缺失值。移除至少含一个缺失值的那些列或许更有可行性。
1 2 3 columns_with_na_dropped = nfl_data.dropna(axis=1 ) columns_with_na_dropped.head()
Date
GameID
Drive
qtr
TimeUnder
ydstogo
ydsnet
PlayAttempted
Yards.Gained
sp
…
Timeout_Indicator
Timeout_Team
posteam_timeouts_pre
HomeTimeouts_Remaining_Pre
AwayTimeouts_Remaining_Pre
HomeTimeouts_Remaining_Post
AwayTimeouts_Remaining_Post
ExPoint_Prob
0
2009-09-10
2009091000
1
1
15
0
0
1
39
0
…
0
None
3
3
3
3
3
0.0
1
2009-09-10
2009091000
1
1
15
10
5
1
5
0
…
0
None
3
3
3
3
3
0.0
2
2009-09-10
2009091000
1
1
15
5
2
1
-3
0
…
0
None
3
3
3
3
3
0.0
3
2009-09-10
2009091000
1
1
14
8
2
1
0
0
…
0
None
3
3
3
3
3
0.0
4
2009-09-10
2009091000
1
1
14
8
2
1
0
0
…
0
None
3
3
3
3
3
0.0
1 2 3 4 5 6 7 print ("Columns in orginal dataset: %d \n" % nfl_data.shape[1 ])print ("Columns with na's dropped: %d \n" % columns_with_na_dropped.shape[1 ])Out[2 ]: Columns in original dataset: 102 Columns with na's dropped: 41
这样子我们丢失了不少数据,但是至少我们成功从我们的数据中移除了所有NaN
数据。
自动填充缺失值 另一种选择时尝试填补这些缺失值,在下一部分,我们只取该数据集的一小部分以方便我们将数据输出。
1 2 3 subset_nfl_data = nfl_data.loc[:, 'EPA' :'Season' ].head() subset_nfl_data
EPA
airEPA
yacEPA
Home_WP_pre
Away_WP_pre
Home_WP_post
Away_WP_post
Win_Prob
WPA
airWPA
yacWPA
Season
0
2.014474
NaN
NaN
0.485675
0.514325
0.546433
0.453567
0.485675
0.060758
NaN
NaN
2009
1
0.077907
-1.068169
1.146076
0.546433
0.453567
0.551088
0.448912
0.546433
0.004655
-0.032244
0.036899
2009
2
-1.402760
NaN
NaN
0.551088
0.448912
0.510793
0.489207
0.551088
-0.040295
NaN
NaN
2009
3
-1.712583
3.318841
-5.031425
0.510793
0.489207
0.461217
0.538783
0.510793
-0.049576
0.106663
-0.156239
2009
4
2.097796
NaN
NaN
0.461217
0.538783
0.558929
0.441071
0.461217
0.097712
NaN
NaN
2009
我们可以使用pandas
的fillna()
函数对数据框中的元素进行填充。
1 2 subset_nfl_data.fillna(0 )
EPA
airEPA
yacEPA
Home_WP_pre
Away_WP_pre
Home_WP_post
Away_WP_post
Win_Prob
WPA
airWPA
yacWPA
Season
0
2.014474
0.000000
0.000000
0.485675
0.514325
0.546433
0.453567
0.485675
0.060758
0.000000
0.000000
2009
1
0.077907
-1.068169
1.146076
0.546433
0.453567
0.551088
0.448912
0.546433
0.004655
-0.032244
0.036899
2009
2
-1.402760
0.000000
0.000000
0.551088
0.448912
0.510793
0.489207
0.551088
-0.040295
0.000000
0.000000
2009
3
-1.712583
3.318841
-5.031425
0.510793
0.489207
0.461217
0.538783
0.510793
-0.049576
0.106663
-0.156239
2009
4
2.097796
0.000000
0.000000
0.461217
0.538783
0.558929
0.441071
0.461217
0.097712
0.000000
0.000000
2009
1 2 3 subset_nfl_data.fillna(method="bfill" , axis=0 ).fillna(0 )
EPA
airEPA
yacEPA
Home_WP_pre
Away_WP_pre
Home_WP_post
Away_WP_post
Win_Prob
WPA
airWPA
yacWPA
Season
0
2.014474
-1.068169
1.146076
0.485675
0.514325
0.546433
0.453567
0.485675
0.060758
-0.032244
0.036899
2009
1
0.077907
-1.068169
1.146076
0.546433
0.453567
0.551088
0.448912
0.546433
0.004655
-0.032244
0.036899
2009
2
-1.402760
3.318841
-5.031425
0.551088
0.448912
0.510793
0.489207
0.551088
-0.040295
0.106663
-0.156239
2009
3
-1.712583
3.318841
-5.031425
0.510793
0.489207
0.461217
0.538783
0.510793
-0.049576
0.106663
-0.156239
2009
4
2.097796
0.000000
0.000000
0.461217
0.538783
0.558929
0.441071
0.461217
0.097712
0.000000
0.000000
2009
练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from learntools.core import binder binder.bind(globals ()) from learntools.data_cleaning.ex1 import *print ("Setup Complete!" )import pandas as pdimport numpy as npsf_permits = pd.read_csv("../input/building-permit-applications-data/Building_Permits.csv" ) np.random.seed(0 ) sf_permits.head() missing_values_count = sf_permits.isnull().sum () total_cells = np.product(sf_permits.shape) total_missing = missing_values_count.sum () percent_missing = (total_missing/total_cells)*100 print (percent_missing)columns_with_na_dropped = sf_permits.dropna() print (columns_with_na_dropped.shape[1 ])