当前位置: 首页 > news >正文

Pandas5(数据清洗1)——缺失值处理、数据去重/转换/替换、离散化/分箱、检测和过滤异常值

数据清洗1

处理缺失数据

  • dropna() : 根据各标签的值中是否存在缺失数据,对轴标签进行过滤,可通过阈值调节对缺失值的容忍度
    ignore_index = True会忽略原先的索引,生成新的索引;不加 ignore_index 将缺失值进行过滤但是行标签保留下来
    how="all"将只丢弃全为NA的那些行; 默认how="any" 只有包含NA的行都丢弃
    thresh=N 至少有N个非缺失值的列/行 才保留数据
    inplace=False 是否修改原先的dataframe
  • fillna()/bfill()/ffill(): 用指定值或插值方法(如ffill或bfill)填充缺失数据
  • isnull()/isna(): 对于非NA值返回False, 对于NA值返回True
  • notnull()/notna(): isna的否定式,对于非NA值返回True, 对于NA值返回False
# 随堂练习 · 智能手环一周健康数据清洗
# 熟悉dropna / fillna / ffill / bfill / isna / notna#  模拟一周数据
# steps:  步数(千步)
# kcal:   消耗卡路里(百卡)
# sleep:  睡眠时长(小时)data = {"day"  : ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],"steps": [8.2,  9.1,  np.nan, 7.5, 8.8,  np.nan, 10.0],"kcal" : [2.3,  np.nan,2.6,   2.1, np.nan,3.0,   3.2],"sleep": [7.0,  6.5,   6.0,   np.nan,7.8,  8.0,   np.nan]
}
df = pd.DataFrame(data).set_index("day")
print("原始数据:\n", df, "\n")# 任务 1  缺失值检测
"""
1.a  用 isna 统计每列缺失值数量
1.b  找出“没有缺失值得行”的日期  (拿到没有缺失值行的索引对象)提示:用 notna 构造布尔 DataFrame,再用 .all(axis=1)
"""
### TODO 1.a
df.isna().sum()  # true表示1,false表示0,用sum方法计算true的值
### TODO 1.b
df[df.notna().all(axis = "columns")]# 任务 2  删除缺失 & 阈值容忍
"""
2.a  删除“任何含有NaN的列”
2.b  保留 ≥ 2 个非缺失值的行, 提示:删除缺失值方法的thresh参数
"""
### TODO 2.a
df.dropna(axis="columns", how="any")
### TODO 2.b
df.dropna(axis="index",thresh=3 )# 任务 3  缺失值填补
"""
3.a  对 steps 列用向前填充 ffill
3.b  对 kcal 列用列均值填充
3.c  对 sleep 列用向后填充 bfill,再对剩余 NaN 使用 0 替代
最终将结果合并到 new_df 并打印
"""
## TODO 3
new_df = df.copy()
print(new_df)
new_df["steps"] = new_df["steps"].ffill()
new_df["kcal"]  = new_df["kcal"].fillna(df["kcal"].mean())
new_df["sleep"].bfill(inplace=True)
new_df.fillna(0,inplace = True)
print(new_df)# 任务 4  一步完成多列不同策略填充
"""
使用 DataFrame.fillna(dict):- steps: 前向填充- kcal : 均值- sleep: 0
验证结果与任务 3 相同
提示:fillna可以传字典,字典的键是列名,字典的值是 series/数字(表示这一列缺失值要填充成什么)
{"steps": df["steps"].ffill(),"kcal" : df["kcal"].mean(),"sleep": 0
}
"""
### TODO 4
data = {"steps": df["steps"].ffill(),"kcal" : df["kcal"].mean(),"sleep": 0
}
df.fillna(data)

数据转换:去重,转换,替换

  • duplicated():标记每个元素是否重复出现 (即之前已经出现过,出现第一次标记为False,出现第二次及以上的标记为True)
    • keep=‘first’ (默认): 除了第一个,后面重复的都标记为True
    • keep=‘last’: 除了最后一个,前面重复的都标记为True
    • keep=False: 所有重复值都标记为True
  • drop_duplicates(): 只保留了duplicated()返回结果为False 的dataframe数据。(相当于data.loc[~data.duplicated()],先去重在否定在筛选 )
    • subset 指定某列进行筛选,去重
    • keep=“last”,则保留最后一个 ; keep=False, 丢掉全部重复过的
  • map(): 除了可以接收一个函数,也可以接收一个含有映射关系的字典型对象 字典的键->值 来实现键值转换
  • replace():map的简单版
# 模拟一份学生花名册
df = pd.DataFrame({"stu_id": [1001,1002,1003,1002,1004,1005,1005],"name"  : ["张三","李四","王五","李四","赵六","钱七","钱七"],"major" : ["CS","EE","ME","EE","CS","cs","ME"],"grade" : ["A","B","C","B","A","A","B"]
})
print("原始数据:\n", df)# TODO 1  使用 duplicated 标记出完全重复的行
dup_flags = df.duplicated()# TODO 2  删除完全重复的行,只保留第一次出现
# 提示:为了避免后面的警告,对删除重复行的dataframe来一次复制 (copy方法),因为系统不理解链式索引是视图还是复制的
df_unique = df.drop_duplicates().copy()# TODO 3  用 map 将 grade 列映射为 GPA 分数 (A=4,B=3,C=2), 并添加到一列 GP到df_unique, 来存分数
GPA = {'A' :'4','B' :'3','C' :'2',
}
df["GPA"] = df["grade"].map(GPA)# TODO 4  把 major 列大小写混杂的 "cs" 统一改写为 "CS"(用 replace)
df["major"] = df["major"].replace("cs", "CS")
print("\n清洗后:\n", df)

重命名轴索引

  • 索引对象的map方法:通过函数或字典映射进行转换,从而得到一个新的索引对象
  • rename(): 对列索引或行索引重命名,data frame内的方法。
    使用rename,则无须手动复制DataFrame 并给index和columns属性赋新值
data = pd.DataFrame(np.arange(12).reshape((3,4)),index=["Ohio", "Colorado", "New York"],columns=["one", "two", "three", "four"])
data# 定义一个转换函数
def transform(x):return x[:4].upper()
# 将数据的行索引的字母转换成大写
data.index = data.index.map(transform)# 如果要创建数据集转换后的版本,并且不修改原始数据,比较使用的方法是rename
data = pd.DataFrame(np.arange(12).reshape((3,4)),
index=["Ohio", "Colorado", "New York"],
columns=["one", "two", "three", "four"])
data.rename(index={"OHIO": "INDIANA"}, columns={"three":"三"})

离散化和分箱

  • 为了便于分析,连续数据常常被离散化或拆分为"箱子", 各个数据处于某个箱子中。

  • pd.cut() : 用于将数据分成指定区间的箱(bin),每个箱的宽度(区间范围)可以自定义。生成了 pandas 的特殊分类对象(Categorical),该对象包含codes代码类别 \categories区间索引 \value_counts()属性和方法

    • 参数:x:要分箱的一维数组或 Series。
    • bins:定义分箱的边界(可以是一个整数或列表)。
    • 如果是整数:表示将数据分成多少个等宽的区间。
    • 如果是列表:表示自定义的区间边界(如 [0, 10, 20, 30])。
    • labels:为每个箱指定标签(可选)。
    • right:是否包含右边界(默认为 True,即区间为左开右闭 (a, b])。i
    • include_lowest:是否包含最小值(默认为 False)
  • pd.qcut() : 用于将数据分成指定数量的箱,但每个箱中的样本量大致相同(基于分位数)。

    • 参数:x:要分箱的一维数组或 Series。
    • q:分箱的数量(如 4 表示 4 分位数)或自定义分位数列表(如 [0, 0.3, 0.7, 1])。
    • labels:为每个箱指定标签(可选)。
    • precision:该参数设置为 2 ,表示限定小数点后只有两位有效数字
    ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
    bins = [18, 25, 35, 60, np.inf] # 18-25,25-35,35-60,60-无穷大
    age_categories = pd.cut(ages, bins,right = False)
    age_categories.codes  # 类别代码:0,1,2 ...
    age_categories.categories  # 区间索引
    age_categories.categories[0] # 区间值,close = right表示右边是闭区间, 这个是pandas专门的区间对象
    age_categories.value_counts()  # 最后得到一个series,其标签是具体的区间group_names = ["少年", "青年", "中年", "老年"]
    pd.cut(ages, bins, labels=group_names)data = np.random.standard_normal(1000)
    quartiles = pd.qcut(data, 4, precision=2)  # 根据分位数 均分了数据  0-25%, 25%-50%, 50%-75%, 75%--100%    保留两位有效数字
    pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.])  #     0-10%, 10%-50%, 50%-90%, 90%-100%

检测和过滤异常值

1、 通过 data.describe() 或者可视化分析图 快速查看数据的分布情况,识别可能的异常值
2、过滤异常值:直接删除,替换为边界值,替换为中位数/均值


# 过滤或转换异常值很大程度上就是运用数组运算。
# 首先查看统计数据
data = pd.DataFrame(np.random.standard_normal((1000,4)))
data.describe()# 假设想要找出某列中绝对值大小超过3的值,  (给出一个想要的异常值,偏离平均值3倍标准差的值)
# 假设异常值
col = data[2]
col.loc[col.abs() > 3]# 选出全部含有 超过3或-3的值 的行,可以在布尔型DataFrame中使用any方法
# 将异常值筛选出
data[(data.abs() > 3).any(axis="columns")]  # 在看每一行是否有异常值,并将数据进行筛选出来# 替换为边界值
# 下面的代码可以将绝对值超过3的值 赋值为-3或3,将所有制限制在-3--3之间
# np.sign() 返回数据的符号,正数为1,负数为-1
data[data.abs()>=3] = np.sign(data) * 3
data.describe()
http://www.lqws.cn/news/580177.html

相关文章:

  • 【Kafka】docker 中配置带 Kerberos 认证的 Kafka 环境(全过程)
  • NIO 工作原理
  • C++ cstring 库解析:C 风格字符串函数
  • 【甲方安全建设】SDL基线建设及审计评估
  • API接口安全-2:签名、时间戳与Token如何联手抵御攻击
  • 【第二章:机器学习与神经网络概述】04.回归算法理论与实践 -(1)线性回归模型
  • Web攻防-SSRF服务端伪造功能逻辑SRC实践复盘参数盲测自动化检测流量插件
  • 【ArcGISPro】解决Pro不能导入AppData下的site-packages
  • MySQL数据库--SQL DDL语句
  • 大学专业科普 | 云计算、大数据
  • 淘宝API接口在数据分析中的应用
  • [springboot系列] 探秘 JUnit 5:现代 Java 单元测试利器
  • 2025年数据治理平台排名及功能对比分析
  • Nacos 3.0 架构全景解读,AI 时代服务注册中心的演进
  • 通过案列理解js中的深拷贝和浅拷贝
  • Server-Sent Events (SSE) 技术详解
  • 【原创】【5】【视频二创工具发布】基于视觉模型+FFmpeg+MoviePy实现短视频自动化二次编辑+多赛道
  • Windows 开发环境部署指南:WSL、Docker Desktop、Podman Desktop 部署顺序与存储路径迁移指南
  • PreparedStatement详解
  • Vue3静态文档资源展示的实现和使用总结
  • 【CS创世SD NAND征文】SD NAND赋能新一代儿童智能玩具
  • js代码04
  • 生信分析之流式数据分析:Flowjo 软件核心功能全解析
  • 《微信生态裂变增长利器:推客小程序架构设计与商业落地》
  • 颠覆传统加密:微算法科技创新LSQb算法,提升量子图像处理速度
  • python | numpy小记(四):理解 NumPy 中的 `np.round`:银行家舍入策略
  • BUUCTF在线评测-练习场-WebCTF习题[MRCTF2020]你传你[特殊字符]呢1-flag获取、解析
  • 攻防世界-MISC-red_green
  • 障碍感知 | 基于3D激光雷达的三维膨胀栅格地图构建(附ROS C++仿真)
  • macos 使用 vllm 启动模型