Python数据清洗综合案例

文章目录

  • 一. 导⼊数据
  • 二. 了解数据
  • 三. 清洗数据的基本方法
  • 四. 案例:检查异常
  • 五. 案例:时间索引
  • 干净整洁的数据是后续进行研究和分析的基础。数据科学家们会花费大量的时间来清理数据集,毫不夸张地说,数据清洗会占据80%的工作时间,而真正用来分析数据的时间只占到20%左右。 数据清洗到底是在清洗些什么?通常来说,所获取到的原始数据不能直接用来分析,因为它们会有各种各样的问题,如包含无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等…

    本例设计一个log.txt⽂件,该文件记录了某个项⽬中某个 api 的调⽤情况,采样时间为每分钟⼀次,包括调⽤次数、响应时间等信息,⼤约18万条数据。下⾯进⾏探索性数据分析。

    一. 导⼊数据

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    plt.rc('font', **{'family':'SimHei'})
    # 从log.txt导⼊数据
    data = pd.read_table('log.txt', header=None,names=['id', 'api', 'count', 'res_time_sum', 'res_time_min','res_time_max', 'res_time_avg', 'interval', 'created_at'])
    # 或者分开来
    data = pd.read_table('log.txt', header=None)
    data.columns = ['id', 'api', 'count', 'res_time_sum', 'res_time_min','res_time_max', 'res_time_avg', 'interval', 'created_at']
    # 看⼀下前⾯⼏个
    print( data.head() )
    '''
           id                     api  count  res_time_sum  res_time_min  res_time_max  res_time_avg  interval           created_at
    0  162542  /front-api/bill/create      8       1057.31         88.75        177.72         132.0        60  2017-11-01 00:00:07
    1  162644  /front-api/bill/create      5        749.12        103.79        240.38         149.0        60  2017-11-01 00:01:07
    2  162742  /front-api/bill/create      5        845.84        136.31        225.73         169.0        60  2017-11-01 00:02:07
    3  162808  /front-api/bill/create      9       1305.52         90.12        196.61         145.0        60  2017-11-01 00:03:07
    4  162943  /front-api/bill/create      3        568.89        138.45        232.02         189.0        60  2017-11-01 00:04:07
    '''
    # 随机抽取5个查看
    print( data.sample(5) )
    '''
                  id                     api  count  res_time_sum  res_time_min  res_time_max  res_time_avg  interval           created_at
    46438    3928038  /front-api/bill/create      3        469.92        129.04        206.80         156.0        60  2017-12-25 00:49:45
    88401    6731328  /front-api/bill/create      3        467.23        115.77        182.61         155.0        60  2018-02-12 13:13:08
    63324    5060491  /front-api/bill/create      8       1044.43         93.58        276.91         130.0        60  2018-01-13 20:00:19
    132049   9789375  /front-api/bill/create      3        433.51         95.90        173.21         144.0        60  2018-04-07 00:15:22
    169689  12678652  /front-api/bill/create      9       2070.40         76.71        768.48         230.0        60  2018-05-19 22:16:10
    '''
    

    二. 了解数据

    拿到一个全新的数据集,应该从哪里入手?没错,我们需要先了解数据,看看它长什么样子。常用的方法和属性如下:

  • .head():查看前n行数据,默认值是5。
  • .tail():查看后n行数据,默认值是5。
  • .shape:查看数据维数。
  • .columns:查看所有列名。
  • .info():查看索引、数据类型和内存信息。
  • .describe():查看每列数据的基本统计值,包括计数值、均值、标准差、最小最大值、1/4、1/2、3/4分位数。
  • .value_counts():查看Series对象的唯一值和计数值。
  • 如果上面这些操作还不够直观的话,就作图看看,需要先导入Python可视化库matplotlib。

  • 直方图
  • 箱型图
  • 散点图
  • 三. 清洗数据的基本方法

    了解数据集之后,我们就可以开始对数据集进行清洗了,通常要处理的问题包括无效信息,列名不规范、格式不一致,存在重复值,缺失值,异常值等,下面我们一个一个来看。

    第1步,去除不需要的行、列。

    在分析一个数据集的时候,很多信息其实是用不到的,因此,需要去除不必要的行或列。在导入的时候就可以通过设置pd.read_xxx()里面的参数来实现列的选择目的。

    如果在数据导入之后,还想删除某些行和列,可以用 .drop() 方法。先创建一个列表list,把不需要的列名放进去,再调用.drop() 方法,参数axis为1时代表列,为0时代表行,参数inplace=True表示不创建新的对象,直接对原始对象进行修改。

    第2步,重新命名列。

    当原始数据的列名不好理解,或者不够简洁时,可以用.rename()方法进行修改。这把英文的列名改成中文,先创建一个字典,把要修改的列名定义好,然后调用rename()方法。

    第3步,重新设置索引。

    数据默认的索引是从0开始的有序整数,但如果想把某一列设置为新的索引,可以用.set_index()方法实现。

    第4步,用字符串操作规范列。

    字符串str操作是非常实用的,因为列中总是会包含不必要的字符,常用的方法如下:

  • lower():把大写转换成小写。
  • upper():把小写转换成大写。
  • capitalize():设置首字母大写。
  • replace():替换特定字符。
  • strip():去除字符串中的头尾空格、以及\n \t。
  • split():使用字符串中的’x’字符作为分隔符,将字符串分隔成列表。
  • get():选取列表中某个位置的值。
  • contains():判断是否存在某个字符,返回的是布尔值。
  • find():检测字符串中是否包含子字符串str,如果是,则返回该子字符串开始位置的索引值。
  • 第5步,用函数规范列。

    在某些情况下,数据不规范的情况并不局限于某一列,而是更广泛地分布在整个表格中。因此,自定义函数并应用于整个表格中的每个元素会更加高效。用applymap()方法可以实现这个功能,它类似于内置的map()函数,只不过它是将函数应用于整个表格中的所有元素。

    第6步,删除重复数据。

    重复数据会消耗不必要的内存,在处理数据时执行不必要的计算,还会使分析结果出现偏差。因此,我们有必要学习如何删除重复数据。

    第7步,填充缺失值。

    数据集中经常会存在缺失值,学会正确处理它们很重要,因为在计算的时候,有些无法处理缺失值,有些则在默认情况下跳过缺失值。而且,了解缺失的数据,并思考用什么值来填充它们,对做出无偏的数据分析至关重要。

    四. 案例:检查异常

    针对上面导入的log.txt数据,下面编写程序来检查导入异常。完整示例代码

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    plt.rc('font', **{'family':'SimHei'})
    # 从log.txt导⼊数据
    data = pd.read_table('log.txt', header=None,names=['id', 'api', 'count', 'res_time_sum', 'res_time_min','res_time_max', 'res_time_avg', 'interval', 'created_at'])
    
    
    # 检查是否有重复值
    print( data.duplicated().sum()  )   # 0
    
    # 检查是否有空值
    print( data.isnull().sum()  )
    '''
    id              0
    api             0
    count           0
    res_time_sum    0
    res_time_min    0
    res_time_max    0
    res_time_avg    0
    interval        0
    created_at      0
    dtype: int64
    '''
    # 分析 api 和 interval 这两列的数据是否对分析有⽤
    print( len(data)  ) # 得到 179496
    print( len(data[data['interval'] == 60])  ) # 得到 179496
    print( len(data[data['api'] == '/front-api/bill/create'])  ) # 得到 179496
    
    # 查看api字段信息,可以发现unique=1,也就是说只有⼀个值,所以是没有意义的
    print( data['api'].describe() )
    '''
    count                     179496
    unique                         1
    top       /front-api/bill/create
    freq                      179496
    Name: api, dtype: object
    '''
    # 删除api⼀列
    data = data.drop('api', axis=1)
    # 还发现 interval 的值全是60
    print( data.interval.unique() )   # [60]
    
    # 把 id 字段都删掉
    data = data.drop(['id'], axis=1)
    # 发现数据中每⼀⾏的  interval 字段的值都⼀样,所以丢弃这列
    data2 = data.drop(columns=['interval'])
    print( data2.head() )
    '''
       count  res_time_sum  res_time_min  res_time_max  res_time_avg           created_at
    0      8       1057.31         88.75        177.72         132.0  2017-11-01 00:00:07
    1      5        749.12        103.79        240.38         149.0  2017-11-01 00:01:07
    2      5        845.84        136.31        225.73         169.0  2017-11-01 00:02:07
    3      9       1305.52         90.12        196.61         145.0  2017-11-01 00:03:07
    4      3        568.89        138.45        232.02         189.0  2017-11-01 00:04:07
    '''
    # 查看维度信息
    print( data2.shape )   # (179496, 6)
    # 查看字段类型
    print( data2.dtypes )
    '''
    count             int64
    res_time_sum    float64
    res_time_min    float64
    res_time_max    float64
    res_time_avg    float64
    created_at       object
    dtype: object
    '''
    print( data2.info() )
    '''
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 179496 entries, 0 to 179495
    Data columns (total 6 columns):
    count           179496 non-null int64
    res_time_sum    179496 non-null float64
    res_time_min    179496 non-null float64
    res_time_max    179496 non-null float64
    res_time_avg    179496 non-null float64
    created_at      179496 non-null object
    dtypes: float64(4), int64(1), object(1)
    memory usage: 7.5+ MB
    None
    '''
    print( data2.describe() )
    '''
                   count   res_time_sum   res_time_min   res_time_max   res_time_avg
    count  179496.000000  179496.000000  179496.000000  179496.000000  179496.000000
    mean        7.175909    1393.177370     108.419620     359.880351     187.812208
    std         4.325160    1499.485881      79.640559     638.919769     224.464813
    min         1.000000      36.550000       3.210000      36.550000      36.000000
    25%         4.000000     607.707500      83.410000     198.280000     144.000000
    50%         7.000000    1154.905000      97.120000     256.090000     167.000000
    75%        10.000000    1834.117500     116.990000     374.410000     202.000000
    max        31.000000  142650.550000   18896.640000  142468.270000   71325.000000
    '''
    

    通过上面操作,可以发现,这份数据其实已经很规整了!

    五. 案例:时间索引

    为⽅便分析,使⽤ created_at 这⼀列的数据作为时间索引。

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    plt.rc('font', **{'family':'SimHei'})
    # 从log.txt导⼊数据
    data = pd.read_table('log.txt', header=None,names=['id', 'api', 'count', 'res_time_sum', 'res_time_min','res_time_max', 'res_time_avg', 'interval', 'created_at'])
    
    
    # 检查是否有重复值
    print( data.duplicated().sum()  )   # 0
    
    # 检查是否有空值
    print( data.isnull().sum()  )
    # 分析 api 和 interval 这两列的数据是否对分析有⽤
    print( len(data)  ) # 得到 179496
    print( len(data[data['interval'] == 60])  ) # 得到 179496
    print( len(data[data['api'] == '/front-api/bill/create'])  ) # 得到 179496
    
    # 查看api字段信息,可以发现unique=1,也就是说只有⼀个值,所以是没有意义的
    print( data['api'].describe() )
    # 删除api⼀列
    data = data.drop('api', axis=1)
    # 还发现 interval 的值全是60
    print( data.interval.unique() )   # [60]
    
    # 把 id 字段都删掉
    data = data.drop(['id'], axis=1)
    # 发现数据中每⼀⾏的  interval 字段的值都⼀样,所以丢弃这列
    data2 = data.drop(columns=['interval'])
    print( data2.head() )
    
    # 查看维度信息
    print( data2.shape )   # (179496, 6)
    # 查看字段类型
    print( data2.dtypes )
    print( data2.info() )
    print( data2.describe() )
    print( "------------------------------------------" )
    
    # 查看时间字段,会发现count=unique=179496,说明没有重复值
    
    data2['created_at'].describe()
    
    # 选取 2018-05-01 的数据,但是没有显⽰
    print( data2[data2.created_at == '2018-05-01'] )
    '''
    Empty DataFrame
    Columns: [count, res_time_sum, res_time_min, res_time_max, res_time_avg, created_at]
    Index: []
    '''
    
    # 这样就可以,但是这样选取毕竟挺⿇烦的
    print( data2[(data2.created_at >= '2018-05-01') & (data2.created_at < '2018-05-01')] )
    '''
    Empty DataFrame
    Columns: [count, res_time_sum, res_time_min, res_time_max, res_time_avg, created_at]
    Index: []
    '''
    print( "------------------------------------------" )
    
    # 所以,将时间序列作为索引
    data2.index = data2['created_at']
    # 为了能 data['2018-05-01'] 这样选取数据,我们还要将时间序列由字符串转为时间索引
    data2.index = pd.to_datetime(data2['created_at'])
    # 有了时间索引,后⾯的操作就⽅便多了
    print( data2['2018-05-01'] )
    '''
                         count  res_time_sum  res_time_min  res_time_max  res_time_avg           created_at
    created_at
    2018-05-01 00:00:48      6       2105.08        125.74        992.46         350.0  2018-05-01 00:00:48
    2018-05-01 00:01:48      7       2579.11         76.55        987.47         368.0  2018-05-01 00:01:48
    2018-05-01 00:02:48      7       1277.79        109.65        236.73         182.0  2018-05-01 00:02:48
    2018-05-01 00:03:48      7       2137.20        131.55        920.52         305.0  2018-05-01 00:03:48
    2018-05-01 00:04:48     13       2948.70         86.42        491.31         226.0  2018-05-01 00:04:48
    ...                    ...           ...           ...           ...           ...                  ...
    2018-05-01 23:55:49      6       1083.97         70.85        262.22         180.0  2018-05-01 23:55:49
    2018-05-01 23:56:49      4        840.00        117.31        382.63         210.0  2018-05-01 23:56:49
    2018-05-01 23:57:49      2        295.51        101.71        193.80         147.0  2018-05-01 23:57:49
    2018-05-01 23:58:49      2        431.99         84.43        347.56         215.0  2018-05-01 23:58:49
    2018-05-01 23:59:49      3        428.84        103.58        206.57         142.0  2018-05-01 23:59:49
    
    [884 rows x 6 columns]
    '''
    

    作者:Token_w

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python数据清洗综合案例

    发表回复