两大步骤,29行代码学会数据清洗

开发 前端
缺失数据是数据文件中最常见的问题之一。在Pandas中的缺失值表示为NA,其中数值类型的缺失值标记为NaN(Not a Number),datetime类型的缺失值标记为NaT(Not a Time)。缺失值的存在可能会引起后续的数据分析错误。

 

[[413843]]

本文转载自微信公众号「数仓宝贝库」,作者王恺 等。转载本文请联系数仓宝贝库公众号。

 01处理缺失数据

缺失数据是数据文件中最常见的问题之一。在Pandas中的缺失值表示为NA,其中数值类型的缺失值标记为NaN(Not a Number),datetime类型的缺失值标记为NaT(Not a Time)。缺失值的存在可能会引起后续的数据分析错误。

在清洗数据之前,首先要确定数据中是否存在缺失值以及缺失值的确切位置。Pandas提供了isna()和notna()方法,用于快速确定Series和DataFrame对象中缺失值的位置,其语法格式如下:

  • pd.isna(data) 或者 data.isna()
  • pd.notna(data) 或者 data.notna()

data可以是一个Series对象,返回值为布尔Series对象;也可以是一个DataFrame对象,返回值为布尔DataFrame对象;还可以是一个标量值,此时返回一个布尔值。对于isna方法,data中如果包含NA值,则返回值对应的位置为True,其余正常元素对应的位置为False。notna方法与isna方法相反,data中如果包含NA值,则返回值对应的位置为False,其余正常元素对应的位置为True。

Pandas提供了几种处理缺失值的方法,即为缺失值重新赋值、删除缺失值所在的行、删除数据缺失率较高的列等。删除缺失值的方法一般用于缺失值较少、对整体数据影响不大的情况。

1)Pandas提供了fillna方法用于将缺失值重新赋值为新的元素值,常用的语法格式如下:

  1. result=data.fillna(value,method=None,…) 

其中data既可以是Series对象,也可以是DataFrame对象。value可以是一个固定的元素,比如0;value也可以是一个字典对象、Series对象或DataFrame对象,用于将data中匹配标签(Series对象)或匹配列标签(DataFrame对象)所对应的缺失值替换为不同的值,未与value匹配的data中的缺失值则不会被替换。method表示填充NA值的方法,缺省时默认为None。method='ffill'或者'method=pad'时使用上一个有效值填充NA值,而method='bfill'或者'method=backfill'时使用下一个有效值来填充NA值。fillna的返回值为新赋值的Series或DataFrame对象。

2)Pandas提供了dropna方法,实现按行或列删除NA值的功能,其语法格式如下:

  1. result =data.dropna(axis=0,how='any',…) 

如果data是Series对象,则axis只能等于0,直接删除所有的NA值。如果data是DataFrame对象,参数axis为0或'index',实现删除缺失值所在的行;如果设置axis为1或'columns',则删除缺失值所在的列;axis缺省时默认为0。how = 'any'表示只要有NA值存在,就会删除所在的行或列;how='all'表示只有当全部元素都是NA值时才会执行删除操作;how缺省时默认为'any'。dropna的返回值为删掉缺失值的Series或DataFrame对象。

3)Pandas还为Series和DataFrame提供了interpolate()方法,通过插值法补充缺失的数据点,其语法格式如下:

  1. result=data.interpolate(method='linear',axis=0,…) 

method表示使用的插值方法,缺省时默认为线性插值'linear'。常用的还有

'time',即根据时间间隔进行插值。除此之外,method还提供了更高级的插值方法,比如Scipy库中的'nearest'、'zero'、'slinear'、'quadratic'、'cubic'、

'spline'、'barycentric'、'polynomial'等。axis参数的用法与dropna方法相同。

下面通过代码清单演示Pandas提供的处理缺失数据方法的用法。

  1. 代码清单 Pandas处理缺失数据方法的用法示例 
  2.  
  3. 1 import pandas as pd 
  4.  
  5. 2 import numpy as np 
  6.  
  7. 3 df = pd.DataFrame({'A': [1, 2.1, np.nan, 4.7, 5.6], 'B': [.25, np.nan,  
  8.  
  9.  np.nan, 4, 12.2]}) 
  10.  
  11. 4 print('df:\n',df) 
  12.  
  13. 5 print('df中的元素是否为缺失值:\n',pd.isna(df)) 
  14.  
  15. 6 df1 = df.fillna(0)#用固定值来填充 
  16.  
  17. 7 print('用0填充缺失值后的数据:\n',df1) 
  18.  
  19. 8 df2 = df.fillna(value={'A': 1, 'B': 2}) #将A、B列中的NaN分别替换为1、2 
  20.  
  21. 9 print('用字典填充缺失值后的数据:\n',df2) 
  22.  
  23. 10 df3 = df.fillna(df.mean()) #用每列的平均值来填充 
  24.  
  25. 11 print('用每列的平均值填充缺失值后的数据:\n',df3) 
  26.  
  27. 12 df4 = df.dropna() 
  28.  
  29. 13 print('删除缺失值后的数据:\n',df4) 
  30.  
  31. 14 df5=df.interpolate() 
  32.  
  33. 15 print('线性插值法填充缺失值后的数据:\n',df5) 
  34.  
  35. 16 df6= df.interpolate(method='polynomial',order=2) 
  36.  
  37. 17 print('多项式插值法填充缺失值后的数据:\n',df6) 

程序执行结束后,输出结果如下:

  1. df: 
  2.  
  3.     A        B 
  4.  
  5. 0  1.0     0.25 
  6.  
  7. 1  2.1      NaN 
  8.  
  9. 2  NaN      NaN 
  10.  
  11. 3  4.7     4.00 
  12.  
  13. 4  5.6    12.20 
  14.  
  15. df中的元素是否为缺失值: 
  16.  
  17.     A       B 
  18.  
  19. 0  False  False 
  20.  
  21. 1  False   True 
  22.  
  23. 2   True   True 
  24.  
  25. 3  False  False 
  26.  
  27. 4  False  False 
  28.  
  29. 用0填充缺失值后的数据: 
  30.  
  31.    A       B 
  32.  
  33. 0  1.0   0.25 
  34.  
  35. 1  2.1   0.00 
  36.  
  37. 2  0.0   0.00 
  38.  
  39. 3  4.7   4.00 
  40.  
  41. 4  5.6  12.20 
  42.  
  43. 用字典填充缺失值后的数据: 
  44.  
  45.    A      B 
  46.  
  47. 0  1.0   0.25 
  48.  
  49. 1  2.1   2.00 
  50.  
  51. 2  1.0   2.00 
  52.  
  53. 3  4.7   4.00 
  54.  
  55. 4  5.6  12.20 
  56.  
  57. 用每列的平均值填充缺失值后的数据: 
  58.  
  59.     A          B 
  60.  
  61. 0  1.00   0.250000 
  62.  
  63. 1  2.10   5.483333 
  64.  
  65. 2  3.35   5.483333 
  66.  
  67. 3  4.70   4.000000 
  68.  
  69. 4  5.60  12.200000 
  70.  
  71. 删除缺失值后的数据: 
  72.  
  73.    A      B 
  74.  
  75. 0  1.0   0.25 
  76.  
  77. 3  4.7   4.00 
  78.  
  79. 4  5.6  12.20 
  80.  
  81. 线性插值法填充缺失值后的数据: 
  82.  
  83.    A      B 
  84.  
  85. 0  1.0   0.25 
  86.  
  87. 1  2.1   1.50 
  88.  
  89. 2  3.4   2.75 
  90.  
  91. 3  4.7   4.00 
  92.  
  93. 4  5.6  12.20 
  94.  
  95. 多项式插值法填充缺失值后的数据: 
  96.  
  97.        A        B 
  98.  
  99. 0  1.000000   0.250 
  100.  
  101. 1  2.100000  -1.975 
  102.  
  103. 2  3.433333  -0.725 
  104.  
  105. 3  4.700000   4.000 
  106.  
  107. 4  5.600000  12.200 

下面对代码清单中的代码做简要说明。

  • 第3行代码通过字典创建了一个5行2列的DataFrame对象df,其中使用Numpy库中的np.nan设置了几个缺失值,如第4行print函数的输出结果所示。
  • 第5行代码通过isna方法来确认df中的哪些元素是缺失值,返回的结果中,True表示df中对应位置为缺失值,False则表示对应位置为正常值。
  • 第6行代码通过fillna方法使用固定值0对df中的缺失值进行填充,并将返回结果赋值给新的DataFrame对象df1,如第7行print函数的输出结果所示。
  • 第8行代码通过fillna方法使用字典{'A': 1, 'B': 2}对df中的缺失值进行填充,A列中的NaN填充为1,B列中的NaN填充为2,并将返回结果赋值给新的DataFrame对象df2,如第9行print函数的输出结果所示。
  • 第10行代码通过fillna方法,使用df.mean()对df中的缺失值进行填充。df.mean()的返回值是Series对象类型,表示df每列的平均值,fillna方法再用该平均值对df每列的缺失值依次进行填充,并将返回结果赋值给新的DataFrame对象df3,如第11行print函数的输出结果所示。
  • 第12行代码通过dropna方法对df中的缺失值进行删除,采用默认的参数设置,即删除所有至少包含一个缺失值的行,并将返回结果赋值给新的DataFrame对象df4,如第13行print函数的输出结果所示。
  • 第14行代码通过interpolate方法对df中的缺失值进行插值处理,采用默认的参数设置,即以列为单位进行线性插值,并将返回结果赋值给新的DataFrame对象df5,如第15行print函数的输出结果所示。
  • 第16行代码通过interpolate方法对df中的缺失值进行了插值处理,参数method='polynomial'表示采用多项式插值法,order=2指定多项式的阶数为2,并将返回结果赋值给新的DataFrame对象df6,如第17行print函数的输出结果所示。

Tips

上文介绍的fillna、dropna、interpolate等处理缺失值的方法都是在数据的拷贝上进行处理,不会改变原数据。

02删除重复数据

除数据缺失之外,数据文件中还可能存在重复的数据,这会对分析结果产生影响,因此,在数据清洗阶段还需要删除重复数据。

要识别数据中是否存在重复行,可以使用Pandas提供的duplicated方法。常用的语法格式如下:

  1. data.duplicated(subset=None,keep='first',…) 

data可以是一个Series对象,也可以是一个DataFrame对象,返回值为一个表示重复行的布尔类型Series对象。当data是Series对象时,duplicated方法中没有subset参数。subset是列标签参数,表示考虑某些特定列来标识重复数据,缺省时默认为考虑全部列。keep决定标记哪个重复数据,缺省时默认为'first',即对于data中的每一组重复数据,第一次出现的位置标记为False,其他重复出现的位置则标记为True。keep='last'时则表示重复数据最后一次出现的位置才标记为False,其余位置为True。

可以使用drop_duplicates方法删除重复的行,常用的语法格式如下:

  1. result=data.drop_duplicates(subset=None,keep='first',…) 

drop_duplicates方法的参数含义与duplicated方法相同。keep参数决定保留哪一行重复数据。返回值为删掉重复数据的Series或DataFrame对象。

Pandas还可以利用drop_duplicates方法处理数据标签中存在重复项的情况,具体方法是:先使用Index.duplicated方法确定数据标签中是否存在重复值,然后再利用得到的布尔数组对数据执行行切片。

下面通过如下代码清单演示Pandas提供的处理重复数据方法的用法。

  1. 代码清单 Pandas处理重复数据方法的用法示例 
  2.  
  3. 1 import pandas as pd 
  4.  
  5. 2 df = pd.DataFrame({'brand': ['YumYum''YumYum''Indomie''Indomie',  
  6.  
  7.  'Indomie'], 'style': ['cup''cup''cup''pack''pack'], 'rating': [4,  
  8.  
  9.  4, 3.5, 15, 5]},index=['a''a''b''c''d']) 
  10.  
  11. 3 print('df:\n',df) 
  12.  
  13. 4 print('对于全列,df的行中是否存在重复项:\n',df.duplicated()) 
  14.  
  15. 5 df1=df.drop_duplicates() 
  16.  
  17. 6 print('删除上述重复项后的df:\n',df1) 
  18.  
  19. 7 print('对于brand和style列,df的行中是否存在重复项:\n',df.duplicated(subset= ['brand''style'])) 
  20.  
  21. 8 df2=df.drop_duplicates(subset= ['brand''style']) 
  22.  
  23. 9 print('删除上述重复项后的df:\n',df2) 
  24.  
  25. 10 print('df的index是否存在重复项:\n',df.index.duplicated(keep='last')) 
  26.  
  27. 11 df3=df[~df.index.duplicated(keep='last')] 
  28.  
  29. 12 print('删除index重复项后的df:\n',df3) 

程序执行结束后,输出结果如下:

  1. df: 
  2.  
  3.       brand  style   rating 
  4.  
  5. a    YumYum    cup      4.0 
  6.  
  7. a    YumYum    cup      4.0 
  8.  
  9. b   Indomie    cup      3.5 
  10.  
  11. c   Indomie   pack     15.0 
  12.  
  13. d   Indomie   pack      5.0 
  14.  
  15. 对于全列,df的行中是否存在重复项: 
  16.  
  17. a    False 
  18.  
  19. a     True 
  20.  
  21. b    False 
  22.  
  23. c    False 
  24.  
  25. d    False 
  26.  
  27. dtype: bool 
  28.  
  29. 删除上述重复项后的df: 
  30.  
  31.       brand   style    rating 
  32.  
  33. a    YumYum     cup       4.0 
  34.  
  35. b   Indomie     cup       3.5 
  36.  
  37. c   Indomie    pack      15.0 
  38.  
  39. d   Indomie    pack       5.0 
  40.  
  41. 对于brand和style列,df的行中是否存在重复项: 
  42.  
  43. a    False 
  44.  
  45. a     True 
  46.  
  47. b    False 
  48.  
  49. c    False 
  50.  
  51. d     True 
  52.  
  53. dtype: bool 
  54.  
  55. 删除上述重复项后的df: 
  56.  
  57.       brand   style   rating 
  58.  
  59. a    YumYum     cup      4.0 
  60.  
  61. b   Indomie     cup      3.5 
  62.  
  63. c   Indomie    pack     15.0 
  64.  
  65. df的index是否存在重复项: 
  66.  
  67. True False False False False
  68.  
  69. 删除index重复项后的df: 
  70.  
  71.       brand   style   rating 
  72.  
  73. a    YumYum     cup      4.0 
  74.  
  75. b   Indomie     cup      3.5 
  76.  
  77. c   Indomie    pack     15.0 
  78.  
  79. d   Indomie    pack      5.0 

下面对代码清单中的代码做简要说明。

  • 第2行代码通过字典创建了一个5行3列的DataFrame对象df,并设置index参数为['a', 'a', 'b', 'c', 'd'],如第3行print函数的输出结果所示。
  • 第4行代码通过duplicated方法来确认df中是否存在重复数据,采用了默认的参数设置,即根据df的所有列来标识重复数据。对于df中的每一组重复数据,第一次出现的位置标记为False,其他重复出现的位置则标记为True,返回值为Series对象。从print函数的输出结果分析得到,df中的第2行为重复数据。
  • 第5行代码通过drop_duplicates方法删除了第4行代码中确定的重复数据所在的行,并将返回结果赋值给新的DataFrame对象df1,如第6行print函数的输出结果所示。
  • 第7行代码通过duplicated方法来确认df中是否存在重复数据,subset= ['brand', 'style']表示根据df的brand和style两列来标识重复数据。对于df中的每一组重复数据,第一次出现的位置标记为False,其他重复出现的位置则标记为True,返回值为Series对象。从print函数的输出结果分析得到,df中的第2行和第5行为重复数据。
  • 第8行代码通过drop_duplicates方法删除了第6行代码中确定的重复数据所在的行,并将返回结果赋值给新的DataFrame对象df2,如第9行print函数的输出结果所示。
  • 第10行代码通过duplicated方法来确认df.index(即df的行标签)中是否存在重复项,keep='last'表示对于df.index中的每一组重复数据,最后一次出现的位置标记为Fasle,其他重复出现的位置则标记为True,返回值为一维布尔数组。从print函数的输出结果分析得到,df中第1行的行标签为重复项。
  • 第11行代码通过布尔数组切片的方法删除了df中行标签重复的行。首先对第10行代码得到的布尔数组进行取反操作,即将第1行重复项标记为Fasle,其他项标记为True;然后再利用得到的新布尔数组对df进行切片,截取True对应的行,并将返回结果赋值给新的DataFrame对象df3,如第12行print函数的输出结果所示。

Tips

1)上文介绍的drop_duplicates方法也是在数据的拷贝上进行删除,不会改变原数据。
2)Pandas还提供了del和drop等方法,通过位置索引或标签索引删除数据中的指定行或列。

本文摘编于《Python数据分析与应用》,经出版方授权发布。

 

责任编辑:武晓燕 来源: 数仓宝贝库
相关推荐

2010-04-12 10:16:55

Oracle存储过程

2010-06-10 17:29:52

MySQL插入数据

2011-05-12 10:03:29

MySQL数据库远程登录账号

2011-03-30 09:45:16

MySQL数据库远程登录

2012-11-20 16:36:15

云数据库

2010-02-24 09:47:25

Oracle手动创建数

2022-07-05 15:11:42

Python数据可视化机器学习

2023-09-26 01:03:36

Pandas数据数据集

2010-05-04 14:30:45

Oracle数据

2021-04-20 12:26:35

SpaceX月球

2021-09-01 20:37:59

云数据库云计算迁移

2010-03-12 08:59:40

Python代码

2015-06-16 14:46:59

数据中心数据中心优化

2010-05-25 14:31:05

远程链接MySQL

2010-07-30 16:37:02

Flex配置

2023-05-10 14:26:24

云迁移云计算

2015-01-26 14:15:06

数据中心迁移

2014-08-14 10:02:34

大数据行业

2012-03-14 09:44:06

数据中心云计算

2020-12-29 07:56:23

JavaScript数据类型 primitive
点赞
收藏

51CTO技术栈公众号