七、数据清理

    “数据清理”是查找并删除或修复“错误数据”的过程,其中“错误数据”通常指的是损坏和/或不准确的数据点。

    缺失值只是缺少的数据点。可以通过多种方式指示缺失值。

    值可以是字面上的空值,或编码为特殊值,例如 Python 或NaN,一个 numpy 对象(“非数字”的缩写)。

    有时缺失值由任意选择的值指示,例如由某些不可能的值指示,例如-999

    1. # Python 具有特殊值“None”,可以编码缺失值或 null 值
    2. dat_none = None
    3. # None 实际上是它自己的类型
    4. print(type(None))
    5. # <class 'NoneType'>
    6. # 请注意,“None”的作用类似于 null 类型(就好像变量不存在一样)
    7. assert dat_none
    8. '''
    9. ---------------------------------------------------------------------------
    10. AssertionError Traceback (most recent call last)
    11. <ipython-input-4-95ad9e3fb11e> in <module>()
    12. 1 # Note that 'None' acts like a null type (as if the variable doesn't exist)
    13. ----> 2 assert dat_none
    14. AssertionError:
    15. '''
    16. # 由于 None 是 null 类型,因此当数据中包含 None 时,基本操作将失败
    17. dat_lst = [1, 2, 3, None]
    18. sum(dat_lst) / len(dat_lst)
    19. '''
    20. TypeError Traceback (most recent call last)
    21. <ipython-input-5-bc3aab645ea1> in <module>()
    22. 1 # Since None is a null type, basic operations will fail when None is in the data
    23. 2 dat_lst = [1, 2, 3, None]
    24. ----> 3 sum(dat_lst) / len(dat_lst)
    25. TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    26. '''
    1. # Numpy也有“非数字”的特殊值 -- NaN
    2. dat_nan = np.nan
    3. # 它实际上是一个特殊的浮点值
    4. type(dat_nan)
    5. # float
    6. # 它不会求值为 null(与 None 不同)
    7. assert dat_nan
    8. # Numpy 实际上有多个版本的 NaN - 但它们实际上都是一样的。
    9. np.nan is np.NaN is np.NAN
    10. # True
    11. # NaN 值不会失败(与 None 不同)但它们将返回未定义(NaN)的答案
    12. dat_a = np.array([1, 2, 3, np.nan])
    13. print(np.mean(dat_a))
    14. # nan
    15. # 你可以告诉 numpy 进行计算,忽略 NaN 值,但你必须明确告诉它这样做
    16. np.nanmean(np.array([1, 2, 3, np.nan]))

    处理缺失数据是一个决策点:你需要做什么?

    • 你丢弃了观测吗?
      • 如果这需要放弃大量观测怎么办?
    • 你保留它,但在任何计算中忽略它?
      • 如果你在不同的计算中得到不同的 N,怎么办?
    • 你重新编码那个数据点吗?
      • 你把它重新编码为什么?

    数据清理包括检查和处理不可能的值。由于编码或数据输入错误,可能会出现不可能的值。

    请注意,数据集还可能将缺失的数据编码为特殊值 - 例如,使用-999表示缺少的年龄。

    这些都必须处理,否则会扭曲你的结果。

    示例问题:我们有两个单独的文件,它们共同拥有一组人的 id 号,年龄,体重和身高。

    让我们假设最终,我们对年龄与身高的关系感兴趣(老年人萎缩真的是真的吗??)

    • messy_dat.json,有 id 和身高信息
    • messy_dat.csv,有 id,年龄和体重信息
    1. # 让我们用 pandas 来丢弃 NaN 值
    2. # 注意 inplace 参数:这将操作我们调用的数据帧
    3. # 而不是返回并将数据帧重新保存到新变量
    4. df1.dropna(inplace=True)
    5. # 丢弃 NaN 后检查数据
    6. df1
    id height
    0 1 168.0
    1 2 155.0
    3 4 173.0
    1. # 读入 csv 数据文件
    2. df2 = pd.read_csv('files/messy_dat.csv')
    3. # 检查数据
    4. df2

    请注意,我们有另一个 NaN 值! 但是,它位于体重列中,我们实际上并不计划将其用于当前分析。 如果我们从这个数据框中删除 NaN,我们实际上拒绝了好的数据 - 因为我们将放弃记录 1,他实际上确实有我们需要的年龄和身高信息。

    我们需要的数据列中没有任何 NaN 值! 我们继续吧!

    1. # 现在让我们将数据合并在一起
    2. # 请注意,这里我们指定使用 'id' 列来合并数据
    3. # 这意味着数据点将基于具有相同 ID 的数据点来合并。
    4. df = pd.merge(df1, df2, on='id')
    5. # 检查合并后的数据帧
    6. df
    id height age
    0 1 168.0 20
    1 2 155.0 27
    2 4 173.0 -999
    1. # 查看基本的描述性统计量,看看事情是否合理
    2. df.describe()

    所以,看起来我们的平均年龄约是 300….

    这似乎不对。在数据收集的某些时刻,缺失的年龄值似乎已编码为。我们需要处理这些数据。

    id height age
    0 1 168.0 20
    1 2 155.0 27

    这实际上只是数据清理的开始 - 将数据转换为适合分析的形状,可以包括任何东西

    提示:

    • 阅读你拥有的数据集的任何文档
      • 像缺失值这样的东西可能是任意编码的,但应该(希望)记录在某处
    • 检查数据类型是否符合预期。如果你正在阅读混合类型数据,请确保最终得到正确的编码
    • 可视化你的数据!看看分布是否似乎合理
    • 检查基本统计量。df.describe()可以让你感觉到,某些东西是否真的偏斜了
    • 请记住你的数据收集方式。
      • 如果任何东西来自将信息输入表格的人类,这可能需要大量清洁
        • 修复数据输入错误(错别字)
    • 清理这类数据可能需要更多的手工工作(因为错误很可能是特殊的)

    Quartz 有一个有用的,Pandas 教程有很多相关资料,包括数据清理的章节 (#7)。