20. Pandas的数据清洗-删除NaN

数据清洗(Tidy Data),是对数据进行重新审查和校验的过程,目的在于删除重复信息、纠正存在的错误,并提供数据一致性。 Pandas提供了很多的工具和函数可以对缺失、重复的数据进行相应的数据的处理。

20.1 构造缺失数据

在Pandas的各类数据Series和DataFrame里字段值为NaN的为缺失数据,不代表0而是说没有赋值数据。数据的缺失有很多原因,缺失不是错误、无效,需要对缺失的数据进行必要的技术处理,以便后续的计算、统计。

  • 构造缺失数据的DataFrame
import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
print df
df["e"] = np.nan
df.at["make", "e"] = 100
df.at["wake", "e"] = 300
df.loc["jake"] = np.nan
df.at["jake", "c"] = 200
df["f"] = np.nan
print df

执行结果:

       a   b   c   d
cake  10  11  12  13
make  14  15  16  17
fake  18  19  20  21
sake  22  23  24  25
wake  26  27  28  29
lake  30  31  32  33
take  34  35  36  37
       a   b    c   d    e   f
cake  10  11   12  13  NaN NaN
make  14  15   16  17  100 NaN
fake  18  19   20  21  NaN NaN
sake  22  23   24  25  NaN NaN
wake  26  27   28  29  300 NaN
lake  30  31   32  33  NaN NaN
take  34  35   36  37  NaN NaN
jake NaN NaN  200 NaN  NaN NaN

20.2 查看缺失数据

查看缺失数据的情况可以用pandas的isnull函数看看有那些字段上的数据缺失,可以用sum进行统计。也可使用notnull和count函数统计非NaN数据量。

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
print df
df["e"] = np.nan
df.at["make", "e"] = 100
df.at["wake", "e"] = 300
df.loc["jake"] = np.nan
df.at["jake", "c"] = 200
df["f"] = np.nan
print df
print "which has Nan?\n", df.isnull(),"\n"
print "each column has NaN\n", df.isnull().sum(),"\n"
print "total has NaN\n", df.isnull().sum().sum(),"\n"
print "each column values\n", df.count(),"\n"
print "which column values\n", df.notnull(),"\n"

执行结果如下:

       a   b   c   d
cake  10  11  12  13
...
take  34  35  36  37
       a   b    c   d    e   f
cake  10  11   12  13  NaN NaN
make  14  15   16  17  100 NaN
fake  18  19   20  21  NaN NaN
sake  22  23   24  25  NaN NaN
wake  26  27   28  29  300 NaN
lake  30  31   32  33  NaN NaN
take  34  35   36  37  NaN NaN
jake NaN NaN  200 NaN  NaN NaN
which has Nan?
          a      b      c      d      e     f
cake  False  False  False  False   True  True
make  False  False  False  False  False  True
fake  False  False  False  False   True  True
sake  False  False  False  False   True  True
wake  False  False  False  False  False  True
lake  False  False  False  False   True  True
take  False  False  False  False   True  True
jake   True   True  False   True   True  True 

each column has NaN
a    1
b    1
c    0
d    1
e    6
f    8
dtype: int64 

total has NaN
17 

each column values
a    7
b    7
c    8
d    7
e    2
f    0
dtype: int64 

which column values
          a      b     c      d      e      f
cake   True   True  True   True  False  False
make   True   True  True   True   True  False
fake   True   True  True   True  False  False
sake   True   True  True   True  False  False
wake   True   True  True   True   True  False
lake   True   True  True   True  False  False
take   True   True  True   True  False  False
jake  False  False  True  False  False  False 

20.3 布尔选择删除

删除NaN(主要针对列Series),在pandas里可以使用布尔选择或者dropna函数删除DataFrame的某Series列里的数据,但不会影响DataFrame本身。

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
df["e"] = np.nan
df.at["make", "e"] = 100
df.at["wake", "e"] = 300
df.loc["jake"] = np.nan
df.at["jake", "c"] = 200
df["f"] = np.nan
print df
print df.e[df.e.notnull()]
print df.e.dropna()
print df

执行结果:

       a   b    c   d    e   f
cake  10  11   12  13  NaN NaN
make  14  15   16  17  100 NaN
fake  18  19   20  21  NaN NaN
sake  22  23   24  25  NaN NaN
wake  26  27   28  29  300 NaN
lake  30  31   32  33  NaN NaN
take  34  35   36  37  NaN NaN
jake NaN NaN  200 NaN  NaN NaN # print df
make    100
wake    300
Name: e, dtype: float64 # print df.e[df.e.notnull()]
make    100
wake    300
Name: e, dtype: float64 # print df.e.dropna()
       a   b    c   d    e   f
cake  10  11   12  13  NaN NaN
make  14  15   16  17  100 NaN
fake  18  19   20  21  NaN NaN
sake  22  23   24  25  NaN NaN
wake  26  27   28  29  300 NaN
lake  30  31   32  33  NaN NaN
take  34  35   36  37  NaN NaN
jake NaN NaN  200 NaN  NaN NaN # print df

20.4 使用dropna函数删除

如果对DataFrame使用了dropna那么行上有NaN的会被删除这行得到结果不直接会影响DataFrame本身。

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
print df
df["e"] = np.nan
df.at["make", "e"] = 100
print df
print df.dropna()
print df

执行结果:

       a   b   c   d
cake  10  11  12  13
make  14  15  16  17
fake  18  19  20  21
sake  22  23  24  25
wake  26  27  28  29
lake  30  31  32  33
take  34  35  36  37# print df
       a   b   c   d    e
cake  10  11  12  13  NaN
make  14  15  16  17  100
fake  18  19  20  21  NaN
sake  22  23  24  25  NaN
wake  26  27  28  29  NaN
lake  30  31  32  33  NaN
take  34  35  36  37  NaN # print df
       a   b   c   d    e
make  14  15  16  17  100 # print df.dropna()
       a   b   c   d    e
cake  10  11  12  13  NaN
make  14  15  16  17  100
fake  18  19  20  21  NaN
sake  22  23  24  25  NaN
wake  26  27  28  29  NaN
lake  30  31  32  33  NaN
take  34  35  36  37  NaN # print df

20.5 行删除NaN

如果仅想删除行里全都是NaN的行,可以在dropna函数里使用how= 'all'参数。

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
df["e"] = np.nan
df.at["make", "e"] = 100
df["f"] = np.nan
df.loc["gake"] = np.nan 
print df
print "del cols is all NaN\n", df.dropna(axis = 'columns', how='all')
print df
print "del rows is all NaN\n", df.dropna(axis = 'rows', how='all')
print df

执行结果:

       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
gake NaN NaN NaN NaN  NaN NaN

del cols is all NaN
       a   b   c   d    e
cake  10  11  12  13  NaN
make  14  15  16  17  100
fake  18  19  20  21  NaN
sake  22  23  24  25  NaN
wake  26  27  28  29  NaN
lake  30  31  32  33  NaN
take  34  35  36  37  NaN
gake NaN NaN NaN NaN  NaN
       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
gake NaN NaN NaN NaN  NaN NaN

del rows is all NaN
       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
gake NaN NaN NaN NaN  NaN NaN

20.6 设定阈值删除

如果想保留含有若干非空值的行或者列可以使用thresh参数。

import pandas as pd
import numpy as np
val = np.arange(10, 38).reshape(7, 4)
col = list("abcd")
idx = "cake make fake sake wake lake take".split()
df = pd.DataFrame(val, columns = col, index = idx)
df["e"] = np.nan
df.at["make", "e"] = 100
df["f"] = np.nan
df.loc["gake"] = np.nan 
print df
print df.dropna(axis = 1, thresh = 2)

程序里axis = 1, thresh = 2是说列上至少有两个非NaN的列留下。

       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
gake NaN NaN NaN NaN  NaN NaN
       a   b   c   d
cake  10  11  12  13
make  14  15  16  17
fake  18  19  20  21
sake  22  23  24  25
wake  26  27  28  29
lake  30  31  32  33
take  34  35  36  37
gake NaN NaN NaN NaN
       a   b   c   d    e   f
cake  10  11  12  13  NaN NaN
make  14  15  16  17  100 NaN
fake  18  19  20  21  NaN NaN
sake  22  23  24  25  NaN NaN
wake  26  27  28  29  NaN NaN
lake  30  31  32  33  NaN NaN
take  34  35  36  37  NaN NaN
gake NaN NaN NaN NaN  NaN NaN

20.7 影响DataFrame参数

如果想dropna函数想直接影响dataframe本身可以使用参数inplace=True