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

ops/2024/10/20 18:56:46/

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

文章目录

  • Python NumPy 数据清洗:高效处理数据异常与缺失
      • 一 数据预处理的常见问题
      • 二 待处理的数据
      • 三 数据预处理
      • 四 清洗数据
        • 1 查看第一列学号
        • 2 查看第二列年龄
          • 结果解析
          • 函数解释
            • 1)`~np.isnan(data[:, 1])`
            • 2)`data[~np.isnan(data[:, 1]), 1]`
        • 3 观察后三行数据
          • 结果解析
          • 函数解释
      • 五 完整代码示例
      • 六 源码地址

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

一 数据预处理的常见问题

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

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

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

二 待处理的数据

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

python">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)

对比数据类型。

python">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 数据进行清洗。

三 数据预处理

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

python">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,则修改第五行第一列。

python"># 查看第一列学号
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 查看第二列年龄
python"># 查看第二列年龄
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 的,判断这个是异常数据,继续处理数据。

python"># ~ 表示 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 观察后三行数据
python"># 观察后三行数据
print(data[-3:, 2:])

运行结果

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

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

python"># 没上课的转成分数转成 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 之间,则保持不变。

五 完整代码示例

python"># 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 npdef 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)# 数据中少 20135print(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_meanprint("ages:", data[:, 1])# 观察后面两数据print(data[-3:, 2:])# 因为没上课,就没成绩,但是倒数第一行,没上课,怎么还有成绩?还有倒数第三行,成绩居然超出了满分 100 分# 没上课的转成分数转成 0data[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.]]

六 源码地址

代码地址:

国内看 Gitee 之 numpy/数据清洗.py

国外看 GitHub 之 numpy/数据清洗.py

引用 莫烦 Python


http://www.ppmy.cn/ops/118387.html

相关文章

美团中间件C++一面-面经总结

1、TCP和UDP 的区别&#xff1f; 速记标识符&#xff1a;连靠刘墉宿营 解释&#xff1a; 面向连接vs无连接 可靠传输vs不保证可靠 字节流vs报文传输 拥塞控制流量控制vs无 速度慢vs速度快 应用场景自己描述 2、服务端处于close wait是什么情况&#xff0c;是由什么造成的&…

FortiOS SSL VPN 用户访问权限配置

简介 使用不同用户组或用户登录 SSL VPN 隧道模式后&#xff0c;可配置不同的访问权限。 本文介绍为不同用户组分配不同访问权限的配置方法。 相关组件 FortiGate&#xff1a;FortiOS v6.4.14 build2093 (GA) 客户端&#xff1a;Windows11&#xff0c;安装 FortiClient VPN 7.…

安全运维类面试题

1、你熟悉哪些品牌的安全设备 答&#xff1a;天融信的ngfw防火墙&#xff0c;老牌防火墙厂商&#xff0c;功能比较齐全&#xff0c;像流量检测&#xff0c;web应用防护和僵木蠕等模块都有&#xff0c;界面是红白配色&#xff0c;设计稍微有点老 2、IPS用的是哪个牌子的 答&…

YOLOv8最新改进2023 CVPR 结合BiFormer

1,原理部分 作为视觉转换器的核心构建块,衰减是捕获长距离依赖性的强大工具。然而,这种能力是有代价的:它会产生巨大的计算负担和沉重的内存占用,因为所有空间位置的成对标记交互都是计算的。一系列作品试图通过将手工制作和与内容无关的稀疏性引入 attention 来缓解这个问…

uniapp监听滚动实现顶部透明度变化

效果如图&#xff1a; 实现思路&#xff1a; 1、使用onPageScroll监听页面滚动&#xff0c;改变导航条的透明度&#xff1b; 2、关于顶部图片的高度&#xff1a; 如果是小程序&#xff1a;使用getMenuButtonBoundingClientRect获取胶囊顶部距离和胶囊高度&#xff1b; 如果…

C++版本更新历史

前言 C语言发展至今已经迭代了很多版本&#xff0c;而在不同环境中编写代码时经常看到C标准的设定&#xff0c;比如 Leetcode 中可以看到版本信息&#xff1a; 这说明Leetcode已经支持最新C23标准了&#xff0c;但某些环境并不一定支持这些语法&#xff0c;如果不清楚使用的语法…

Python pyusb 使用指南【windows+linux】

前言&#xff1a;USB(通用串行总线)作为一种高度通用性的硬件接口&#xff0c;在诸多领域均有应用。在C中可以直接使用libusb库即可完成USB设备信息查询、USB设备监听、与USB设备控制端点、数据&#xff08;同步、批量、中断&#xff09;端点进行指令、数据交互等功能。python中…

【智能大数据分析 | 实验二】Spark实验:部署Spark集群

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…