首页 > 编程语言 >Python NumPy 数据清洗:高效处理数据异常与缺失

Python NumPy 数据清洗:高效处理数据异常与缺失

时间:2024-09-29 18:23:05浏览次数:10  
标签:False Python NumPy data np True dtype print 数据

Python NumPy 数据清洗:高效处理数据异常与缺失

文章目录

本文展示了如何利用 Python 的 NumPy 库高效地进行数据清洗,特别是对复杂数据的异常处理与缺失值填补。文章详细介绍了数据清洗中的常见问题,包括数据值缺失、异常值、格式错误及非独立数据,并提供了对应的解决方案。通过具体的学期学生成绩数据示例,演示了如何识别重复学号、处理缺失年龄值、剔除异常分数、填补缺失成绩等。借助 np.uniquenp.isnannp.clip 等 NumPy 方法,实现了对数据的精细化处理。最终,经过数据清洗,所有数据均符合预期格式和规则,为后续的数据分析和建模奠定了坚实基础。

一 数据预处理的常见问题

数据值缺失数据值异常大或小格式错误非独立数据错误。以下是数据预处理中常见问题及其描述、原因和解决方法的表格:

问题类型描述产生原因解决方法
数据值缺失数据集中有些值为空或不存在,通常用 NaNnull 或空字符串表示。数据收集过程中的遗漏、传感器故障、数据传输问题。删除缺失值、填充缺失值(平均值、中位数等)、标记缺失值。
数据值异常大或小数据集中某些值与其他数据显著不同,通常为极端值或不合理的值。测量或录入错误、正态分布中的极端情况、数据采集设备问题。剔除异常值、替换异常值(中位数、分位数等)、使用算法检测异常值。
格式错误数据格式不符合预期,如字符串中混有数字、日期格式不一致、分类标签混乱等。数据来源不一致、录入错误、缺乏格式规范。统一格式、清理数据(删除或更正错误格式)、转换数据类型。
非独立数据错误数据点之间存在依赖关系,如重复数据、同一对象的多次测量导致数据非独立性。同一对象多次采样、数据重复、对象间存在依赖关系。删除重复数据、聚合处理(取平均、最大值等)、标记数据依赖性。

:在项目中,应结合业务背景和实际情况综合判断哪些数据属于异常。

二 待处理的数据

假设手上有一学期的小学生上课成绩数据。

raw_data = [
    ["Name", "StudentID", "Age", "AttendClass", "Score"],
    ["小明", 20131, 10, 1, 67],
    ["小花", 20132, 11, 1, 88],
    ["小菜", 20133, None, 1, "98"],
    ["小七", 20134, 8, 1, 110],
    ["花菜", 20134, 98, 0, None],
    ["西兰花", 20136, 12, 0, 12]
]
print(raw_data)

对比数据类型。

data = np.array(raw_data)
# object
print("data.dtype", data.dtype)
test1 = np.array([1, 2, 3])
test2 = np.array([1.1, 2.3, 3.4])
test3 = np.array([1, 2, 3], dtype=np.float64)
print("test1.dtype", test1.dtype)
print("test2.dtype", test2.dtype)
print("test3.dtype", test3.dtype)
print("test2 > 2 ", test2 > 2)
# TypeError: '>' not supported between instances of 'str' and 'int'
# print("data > 2", data > 2)  # 这里会报错

运行结结果

data.dtype object
test1.dtype int64
test2.dtype float64
test3.dtype float64
test2 > 2  [False  True  True]

NumPy 数组主要是用于存储同种数据类型的元素 ,运行 data > 2 后报错 TypeError: '>' not supported between instances of 'str' and 'int'。下面对上述 data 数据进行清洗。

三 数据预处理

不要首行字符串并去掉首列名字。

data_process = []
for i in range(len(raw_data)):
    if i == 0:
        continue  # 不要首行字符串
    # 去掉首列名字
    data_process.append(raw_data[i][1:])
data = np.array(data_process, dtype=np.float64)
print("data.dtype", data.dtype)
print(data)

四 清洗数据

1 查看第一列学号

进过 np.unique 函数运行之后,发现学号有重复,查看数据发现相邻的数据 20135,则修改第五行第一列。

# 查看第一列学号
sid = data[:, 0]
unique, counts = np.unique(sid, return_counts=True)
print(counts)
# 数据中少 20135
print(unique[counts > 1])
# 修改第五行第一列
data[4, 0] = 20135
print(data)
2 查看第二列年龄
# 查看第二列年龄
is_nan = np.isnan(data[:, 1])
print("is_nan:", is_nan)
nan_idx = np.argwhere(is_nan)
print(nan_idx)
# 用 ~ 符号可以 True/False 对调
print(~np.isnan(data[:, 1]))
# 计算有数据的平均年龄,用 ~ 符号可以 True/False 对调
print(data[~np.isnan(data[:, 1]), 1])
mean_age = data[~np.isnan(data[:, 1]), 1].mean()
print("有数据的平均年龄:", mean_age)

运行结果

is_nan: [False False  True False False False]
[[2]]
[ True  True False  True  True  True]
[10. 11.  8. 98. 12.]
有数据的平均年龄: 27.8
结果解析

发现平均均值偏高,查看数据发现有个年龄为 98 的,判断这个是异常数据,继续处理数据。

# ~ 表示 True/False 对调,& 就是逐个做 Python and 的运算
normal_age_mask = ~np.isnan(data[:, 1]) & (data[:, 1] < 20)
print("normal_age_mask:", normal_age_mask)

normal_age_mean = data[normal_age_mask, 1].mean()
print("normal_age_mean:", normal_age_mean)

data[~normal_age_mask, 1] = normal_age_mean
print("ages:", data[:, 1])

运行结果

normal_age_mask: [ True  True False  True False  True]
normal_age_mean: 10.25
ages: [10.   11.   10.25  8.   10.25 12.  ]
函数解释
1)~np.isnan(data[:, 1])
  • ~ 是按位取反运算符,它将布尔数组中 TrueFalse 的值互换,即将 True 变为 FalseFalse 变为 True
  • ~np.isnan(data[:, 1])np.isnan(data[:, 1]) 中所有的 True 变为 FalseFalse 变为 True,即标记出 data[:, 1] 中那些不是 NaN 的元素。
2)data[~np.isnan(data[:, 1]), 1]
  • 这一部分使用布尔索引选择 data 中第二列(索引为 1)的非 NaN 元素。
  • data[~np.isnan(data[:, 1]), 1] 中的 ~np.isnan(data[:, 1]) 作为行的条件,表示只选择第二列中非 NaN 对应的行。
  • 1 表示列索引,指第二列。
  • 结果是一个一维数组,包含 data 中第二列所有非 NaN 的元素。
3 观察后三行数据
# 观察后三行数据
print(data[-3:, 2:])

运行结果

[[  1. 110.]
 [  0.  nan]
 [  0.  12.]]
结果解析

因为没上课,就没成绩,但是倒数第一行,没上课,但是有成绩?倒数第三行,成绩居然超出了满分 100 分,继续处理数据。

# 没上课的转成分数转成 0
data[data[:, 2] == 0, 3] = 0
# 超过 100 分和低于 0 分的都处理一下
data[:, 3] = np.clip(data[:, 3], 0, 100)
print(data[:, 2:])
函数解释

np.clip(array, min, max):这是 NumPy 的一个函数,用于将数组中的元素限制在给定的最小值和最大值之间。对于每个元素:

  • 如果元素小于 min,则将该元素设置为 min
  • 如果元素大于 max,则将该元素设置为 max
  • 如果元素在 minmax 之间,则保持不变。

五 完整代码示例

# This is a sample Python script.

# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
import numpy as np


def print_hi(name):
    # Use a breakpoint in the code line below to debug your script.
    print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.
    raw_data = [
        ["Name", "StudentID", "Age", "AttendClass", "Score"],
        ["小明", 20131, 10, 1, 67],
        ["小花", 20132, 11, 1, 88],
        ["小菜", 20133, None, 1, "98"],
        ["小七", 20134, 8, 1, 110],
        ["花菜", 20134, 98, 0, None],
        ["西兰花", 20136, 12, 0, 12]
    ]
    # print(raw_data)

    data = np.array(raw_data)
    print("data.dtype", data.dtype)
    test1 = np.array([1, 2, 3])
    test2 = np.array([1.1, 2.3, 3.4])
    test3 = np.array([1, 2, 3], dtype=np.float64)
    print("test1.dtype", test1.dtype)
    print("test2.dtype", test2.dtype)
    print("test3.dtype", test3.dtype)
    print("test2 > 2 ", test2 > 2)
    # TypeError: '>' not supported between instances of 'str' and 'int'
    # print("data > 2", data > 2)  # 这里会报错
    # 数据预处理
    data_process = []
    for i in range(len(raw_data)):
        if i == 0:
            continue  # 不要首行字符串
        # 去掉首列名字
        data_process.append(raw_data[i][1:])
    data = np.array(data_process, dtype=np.float64)
    print("data.dtype", data.dtype)
    # print(data)
    # 清洗数据
    # 查看第一列学号
    sid = data[:, 0]
    unique, counts = np.unique(sid, return_counts=True)
    print(counts)
    # 数据中少 20135
    print(unique[counts > 1])
    # 修改第五行第一列
    data[4, 0] = 20135
    # print(data)
    # 查看第二列年龄
    is_nan = np.isnan(data[:, 1])
    print("is_nan:", is_nan)
    nan_idx = np.argwhere(is_nan)
    print(nan_idx)
    # 用 ~ 符号可以 True/False 对调
    print(~np.isnan(data[:, 1]))
    # 计算有数据的平均年龄,用 ~ 符号可以 True/False 对调
    print(data[~np.isnan(data[:, 1]), 1])
    mean_age = data[~np.isnan(data[:, 1]), 1].mean()
    print("有数据的平均年龄:", mean_age)
    # 发现平均均值偏高,查看数据发现有个年龄为 98 的,判断这个是异常数据
    # ~ 表示 True/False 对调,& 就是逐个做 Python and 的运算
    normal_age_mask = ~np.isnan(data[:, 1]) & (data[:, 1] < 20)
    print("normal_age_mask:", normal_age_mask)

    normal_age_mean = data[normal_age_mask, 1].mean()
    print("normal_age_mean:", normal_age_mean)

    data[~normal_age_mask, 1] = normal_age_mean
    print("ages:", data[:, 1])

    # 观察后面两数据
    print(data[-3:, 2:])
    # 因为没上课,就没成绩,但是倒数第一行,没上课,怎么还有成绩?还有倒数第三行,成绩居然超出了满分 100 分
    # 没上课的转成分数转成 0
    data[data[:, 2] == 0, 3] = 0

    # 超过 100 分和低于 0 分的都处理一下
    data[:, 3] = np.clip(data[:, 3], 0, 100)

    print(data[:, 2:])


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    print_hi('数据清洗')

# See PyCharm help at https://www.jetbrains.com/help/pycharm/

复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。

Hi, 数据清洗
data.dtype object
test1.dtype int64
test2.dtype float64
test3.dtype float64
test2 > 2  [False  True  True]
data.dtype float64
[1 1 1 2 1]
[20134.]
is_nan: [False False  True False False False]
[[2]]
[ True  True False  True  True  True]
[10. 11.  8. 98. 12.]
有数据的平均年龄: 27.8
normal_age_mask: [ True  True False  True False  True]
normal_age_mean: 10.25
ages: [10.   11.   10.25  8.   10.25 12.  ]
[[  1. 110.]
 [  0.  nan]
 [  0.  12.]]
[[  1.  67.]
 [  1.  88.]
 [  1.  98.]
 [  1. 100.]
 [  0.   0.]
 [  0.   0.]]

六 源码地址

代码地址:

国内看 Giteenumpy/数据清洗.py

国外看 GitHubnumpy/数据清洗.py

引用 莫烦 Python

标签:False,Python,NumPy,data,np,True,dtype,print,数据
From: https://blog.csdn.net/u014394049/article/details/142618293

相关文章

  • pg结果子查询转换数据不正确
    1、问题同样的sql,执行思路,在测试环境,可以正常获取结果,生产环境数据就是不对,怀疑是PG版本不同。sql如下:xx的意思:查询completion_date,6天后的日期(跳过节假日),结果数据都没有转换 SELECTdistinct   A.input_user,   A.acqtn_mode,   A.assemble_idAS......
  • jsp爱宠宠物医院管理系统设计与实现0685i--(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、课题名称爱宠宠物医院管理系统设计与实现二、研究背景与意义随着宠物市场的不断扩大,宠物医院作为宠物健康保障的重要环节,其管理效率和服务质......
  • jsp爱独居老人网站的设计与实现rig5u--(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景随着社会老龄化的加剧,独居老人群体日益庞大,他们面临着生活孤独、健康监测不足、紧急求助困难等问题。为了改善独居老人的生活质量,提升......
  • jsp爱电影网站的设计与实现6nk0x(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、研究背景与意义随着互联网技术的飞速发展,网络娱乐已成为人们日常生活中不可或缺的一部分,其中在线观影因其便捷性、丰富性和互动性而备受青睐。......
  • 基于C++11的数据库连接池环境配置
    欢迎访问我的另一个博客:https://xingzhu.top/ubuntu安装python2由于接下来要使用python,所以先安装python#安装python2.7.18即可#python3不行,版本过高,会报错sudoaptinstallpython2python2--version安装完成后我们可以使用如下命令来检查目前可用的Pyt......
  • 数据库连接池实现
    欢迎访问的另一个博客:https://xingzhu.top/源码链接:https://github.com/xingzhuz/MysqlLinkPool前置知识:相关的环境配置:https://xingzhu.top/archives/shu-ju-ku-lian-jie-chi-huan-jing-pei-zhiMySQLAPI:https://subingwen.cn/mysql/mysql-api/JsoncppAPI:htt......
  • The Zen of Python/Python之禅(import this)
    经验丰富的程序员倡导尽可能避繁就简。Python社区的理念都包含在TimPeters撰写的“Python之禅”中,要了解这些有关编写优秀Python代码的指导原则,只需在解释器中执行命令importthis。>>>importthisTheZenofPython,byTimPetersBeautifulisbetterthanugly.Explic......
  • 数据结构————顺序表
    1.线性表什么是线性表呢大家往下面看:其实线性表(linearlist)是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中⼴泛使⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串(线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是......
  • 足球分析:AI数据分析预测足球联赛解读
    一、前言在当今数字化时代,人工智能(AI)正逐渐在各个领域展现出强大的实力,足球领域也不例外。在你还在苦于该如何分析各类足球联赛的情况时,AI或许便已经给出了解读答案,AI优异的数据分析能力使得它能够胜任预测足球各大联赛的任务,本文将介绍该如何利用AI来预测足球比赛结果。二......
  • 使用python语言进行文件复制
    importos.path#来源文件sc_file=r"D:\py\test1"#目标文件des_file=r"D:\py\test2"#定义函数defcopy(sc,des):#判断来源文件是否为文件夹ifos.path.isdir(sc):#列出当前文件夹下的所有文件files=os.listdir(sc)#......