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

Pandas-数据清洗与缺失值处理

数据清洗与缺失值处理

目录

  • 检测缺失值
  • 处理缺失值
  • 删除缺失值
  • 填充缺失值
  • 处理重复值
  • 数据类型转换
  • 数据规范化
  • 处理异常值
  • 实际应用示例

检测缺失值

基本检测方法

import pandas as pd
import numpy as np# 创建包含缺失值的数据
data = {'姓名': ['张三', '李四', '王五', '赵六', '孙七'],'年龄': [25, 30, np.nan, 28, np.nan],'工资': [8000, np.nan, 10000, 11000, 9500],'城市': ['北京', '上海', '广州', np.nan, '杭州']
}
df = pd.DataFrame(data)# 检查缺失值(返回布尔 DataFrame)
print(df.isna())
# 输出:
#      姓名     年龄     城市     工资
# 0  False  False  False  False
# 1  False  False  False   True
# 2  False   True  False  False
# 3  False  False   True  False
# 4  False   True  False  False# 检查非缺失值
print(df.notna())# 统计每列的缺失值数量
print(df.isna().sum())
# 输出:
# 姓名    0
# 年龄    2
# 城市    1
# 工资    1
# dtype: int64# 统计缺失值百分比
print(df.isna().sum() / len(df) * 100)# 检查是否有缺失值
print(df.isna().any().any())  # True# 检查每行是否有缺失值
print(df.isna().any(axis=1))# 统计每行缺失值数量
print(df.isna().sum(axis=1))

缺失值类型

import pandas as pd
import numpy as np# Pandas 中的缺失值表示
# - NaN (Not a Number): 用于浮点数
# - None: 用于对象类型
# - NaT (Not a Time): 用于时间戳df = pd.DataFrame({'A': [1, 2, np.nan, 4],'B': ['a', 'b', None, 'd'],'C': pd.date_range('2024-01-01', periods=4),
})
df.loc[2, 'C'] = pd.NaTprint(df)
print(df.isna())

处理缺失值

基本统计

import pandas as pd
import numpy as npdata = {'年龄': [25, 30, np.nan, 28, np.nan],'工资': [8000, np.nan, 10000, 11000, 9500]
}
df = pd.DataFrame(data)# 跳过缺失值进行统计
print(f"平均年龄: {df['年龄'].mean()}")        # 自动跳过 NaN
print(f"年龄总和: {df['年龄'].sum()}")         # 自动跳过 NaN
print(f"年龄最大值: {df['年龄'].max()}")       # 自动跳过 NaN# 统计非缺失值数量
print(f"有效年龄数量: {df['年龄'].count()}")# 使用 skipna 参数
print(f"包含 NaN 的平均值: {df['年龄'].mean(skipna=False)}")  # 返回 NaN

删除缺失值

dropna 方法

import pandas as pd
import numpy as npdata = {'姓名': ['张三', '李四', '王五', '赵六', '孙七'],'年龄': [25, 30, np.nan, 28, np.nan],'工资': [8000, np.nan, 10000, 11000, 9500],'城市': ['北京', '上海', '广州', np.nan, '杭州']
}
df = pd.DataFrame(data)# 删除包含任何缺失值的行(默认)
df_dropped = df.dropna()
print(df_dropped)
# 输出:
#    姓名   年龄    工资  城市
# 0  张三  25.0  8000.0  北京# 删除所有值都为缺失值的行
df_dropped = df.dropna(how='all')
print(df_dropped)# 删除至少包含 n 个缺失值的行
df_dropped = df.dropna(thresh=3)  # 至少 3 个非缺失值
print(df_dropped)# 删除包含缺失值的列
df_dropped = df.dropna(axis=1)
print(df_dropped)# 删除特定列包含缺失值的行
df_dropped = df.dropna(subset=['年龄'])
print(df_dropped)# 修改原 DataFrame
df.dropna(inplace=True)
print(df)

填充缺失值

fillna 方法

import pandas as pd
import numpy as npdata = {'年龄': [25, 30, np.nan, 28, np.nan],'工资': [8000, np.nan, 10000, 11000, 9500],'城市': ['北京', '上海', np.nan, '深圳', '杭州']
}
df = pd.DataFrame(data)# 用固定值填充
df_filled = df.fillna(0)
print(df_filled)# 用不同值填充不同列
df_filled = df.fillna({'年龄': 0, '工资': df['工资'].mean(), '城市': '未知'})
print(df_filled)# 前向填充(用前一个值填充)
df_filled = df.fillna(method='ffill')  # 或 method='pad'
print(df_filled)# 后向填充(用后一个值填充)
df_filled = df.fillna(method='bfill')  # 或 method='backfill'
print(df_filled)# 限制填充的行数
df_filled = df.fillna(method='ffill', limit=1)
print(df_filled)

使用统计值填充

import pandas as pd
import numpy as npdata = {'年龄': [25, 30, np.nan, 28, np.nan, 32],'工资': [8000, np.nan, 10000, 11000, 9500, np.nan]
}
df = pd.DataFrame(data)# 用均值填充
df['年龄'].fillna(df['年龄'].mean(), inplace=True)
print(df)# 用中位数填充
df['工资'].fillna(df['工资'].median(), inplace=True)
print(df)# 用众数填充
df['年龄'].fillna(df['年龄'].mode()[0], inplace=True)
print(df)# 用分组均值填充
df_grouped = df.groupby('部门')['工资'].transform(lambda x: x.fillna(x.mean()))

插值填充

import pandas as pd
import numpy as np# 线性插值(适用于数值型数据)
data = {'日期': pd.date_range('2024-01-01', periods=10, freq='D'),'价格': [100, 102, np.nan, np.nan, 108, 110, np.nan, 115, 117, 120]
}
df = pd.DataFrame(data)# 线性插值
df['价格'] = df['价格'].interpolate(method='linear')
print(df)# 时间索引的插值
df_indexed = df.set_index('日期')
df_indexed['价格'] = df_indexed['价格'].interpolate(method='time')
print(df_indexed)# 其他插值方法
# method='polynomial': 多项式插值
# method='spline': 样条插值
# method='quadratic': 二次插值

处理重复值

检测重复值

import pandas as pddata = {'姓名': ['张三', '李四', '王五', '张三', '赵六'],'年龄': [25, 30, 35, 25, 28],'城市': ['北京', '上海', '广州', '北京', '深圳']
}
df = pd.DataFrame(data)# 检查是否有重复行
print(df.duplicated())
# 输出:
# 0    False
# 1    False
# 2    False
# 3     True
# 4    False
# dtype: bool# 检查特定列的重复值
print(df.duplicated(subset=['姓名']))# 检查所有列都重复的行(keep='first' 保留第一个,keep='last' 保留最后一个)
print(df.duplicated(keep='first'))
print(df.duplicated(keep='last'))
print(df.duplicated(keep=False))  # 标记所有重复# 统计重复值数量
print(df.duplicated().sum())

删除重复值

import pandas as pddata = {'姓名': ['张三', '李四', '王五', '张三', '赵六'],'年龄': [25, 30, 35, 25, 28],'城市': ['北京', '上海', '广州', '北京', '深圳']
}
df = pd.DataFrame(data)# 删除重复行(保留第一个)
df_dedup = df.drop_duplicates()
print(df_dedup)# 删除重复行(保留最后一个)
df_dedup = df.drop_duplicates(keep='last')
print(df_dedup)# 删除所有重复的行
df_dedup = df.drop_duplicates(keep=False)
print(df_dedup)# 基于特定列删除重复
df_dedup = df.drop_duplicates(subset=['姓名'])
print(df_dedup)# 基于多列删除重复
df_dedup = df.drop_duplicates(subset=['姓名', '年龄'])
print(df_dedup)# 修改原 DataFrame
df.drop_duplicates(inplace=True)

数据类型转换

import pandas as pddata = {'年龄': ['25', '30', '35', '28'],'工资': [8000.5, 12000.3, 10000.7, 11000.2],'日期': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04']
}
df = pd.DataFrame(data)print(df.dtypes)# 转换单列类型
df['年龄'] = df['年龄'].astype(int)
print(df.dtypes)# 转换多列类型
df = df.astype({'年龄': int, '工资': int})
print(df.dtypes)# 转换为字符串
df['年龄'] = df['年龄'].astype(str)# 转换为日期
df['日期'] = pd.to_datetime(df['日期'])
print(df.dtypes)# 转换为类别类型(节省内存)
df['类别'] = ['A', 'B', 'A', 'B']
df['类别'] = df['类别'].astype('category')
print(df.dtypes)# 处理转换错误
df['年龄'] = pd.to_numeric(df['年龄'], errors='coerce')  # 错误值转为 NaN
df['年龄'] = pd.to_numeric(df['年龄'], errors='ignore')   # 忽略错误

数据规范化

标准化

import pandas as pd
import numpy as npdata = {'身高': [170, 175, 165, 180, 172],'体重': [65, 70, 60, 80, 68]
}
df = pd.DataFrame(data)# Z-score 标准化
df['身高_zscore'] = (df['身高'] - df['身高'].mean()) / df['身高'].std()
df['体重_zscore'] = (df['体重'] - df['体重'].mean()) / df['体重'].std()print(df)# Min-Max 标准化(缩放到 0-1)
df['身高_minmax'] = (df['身高'] - df['身高'].min()) / (df['身高'].max() - df['身高'].min())
print(df)

归一化

import pandas as pd# 字符串归一化
data = {'姓名': ['  张三  ', '李四', ' 王五 ', '赵六']
}
df = pd.DataFrame(data)# 去除空格
df['姓名'] = df['姓名'].str.strip()
print(df)# 统一大小写
df['姓名'] = df['姓名'].str.lower()
print(df)# 统一格式
df['姓名'] = df['姓名'].str.title()
print(df)

处理异常值

检测异常值

import pandas as pd
import numpy as npnp.random.seed(42)
data = {'年龄': [25, 30, 35, 28, 32, 150, 27, 29],  # 150 是异常值'工资': [8000, 12000, 10000, 11000, 9500, 120000, 9000, 10500]  # 120000 是异常值
}
df = pd.DataFrame(data)# 使用 IQR 方法检测异常值
def detect_outliers_iqr(df, column):Q1 = df[column].quantile(0.25)Q3 = df[column].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRoutliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]return outliersoutliers_age = detect_outliers_iqr(df, '年龄')
print("年龄异常值:")
print(outliers_age)outliers_salary = detect_outliers_iqr(df, '工资')
print("\n工资异常值:")
print(outliers_salary)# 使用 Z-score 方法检测异常值(通常阈值为 3)
from scipy import stats
z_scores = np.abs(stats.zscore(df['年龄']))
outliers = df[z_scores > 3]
print("\nZ-score 异常值:")
print(outliers)

处理异常值

import pandas as pd
import numpy as npnp.random.seed(42)
data = {'年龄': [25, 30, 35, 28, 32, 150, 27, 29],'工资': [8000, 12000, 10000, 11000, 9500, 120000, 9000, 10500]
}
df = pd.DataFrame(data)# 方法1:删除异常值
def remove_outliers_iqr(df, column):Q1 = df[column].quantile(0.25)Q3 = df[column].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRreturn df[(df[column] >= lower_bound) & (df[column] <= upper_bound)]df_cleaned = remove_outliers_iqr(df.copy(), '年龄')
print("删除年龄异常值后:")
print(df_cleaned)# 方法2:用边界值替换异常值(Winsorization)
def winsorize(df, column):Q1 = df[column].quantile(0.25)Q3 = df[column].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRdf[column] = df[column].clip(lower=lower_bound, upper=upper_bound)return dfdf_winsorized = winsorize(df.copy(), '工资')
print("\n工资异常值截断后:")
print(df_winsorized)# 方法3:用中位数或均值替换
def replace_outliers_with_median(df, column):Q1 = df[column].quantile(0.25)Q3 = df[column].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRmedian = df[column].median()df.loc[(df[column] < lower_bound) | (df[column] > upper_bound), column] = medianreturn dfdf_replaced = replace_outliers_with_median(df.copy(), '年龄')
print("\n年龄异常值替换为 median 后:")
print(df_replaced)

实际应用示例

示例 1:完整的数据清洗流程

import pandas as pd
import numpy as np# 创建包含各种问题的数据
np.random.seed(42)
data = {'ID': [1, 2, 3, 4, 5, 6, 7, 8],'姓名': ['张三', '李四', '王五', '赵六', '  孙七  ', '周八', '张三', '吴九'],'年龄': [25, 30, np.nan, 28, 32, 150, 27, np.nan],  # 有缺失值和异常值'工资': [8000, np.nan, 10000, 11000, 9500, 120000, 9000, 10500],  # 有缺失值和异常值'部门': ['销售', '技术', '销售', '技术', '销售', '技术', '销售', '技术'],'入职日期': ['2020-01-01', '2019-06-15', '2020-01-01', 'invalid', '2021-09-10', '2020-01-01', '2020-01-01', '2022-03-01']
}
df = pd.DataFrame(data)print("原始数据:")
print(df)
print(f"\n缺失值统计:\n{df.isna().sum()}")# 步骤1:处理字符串列的空格
df['姓名'] = df['姓名'].str.strip()# 步骤2:删除重复值
df = df.drop_duplicates(subset=['姓名'], keep='first')# 步骤3:处理异常值(年龄)
Q1_age = df['年龄'].quantile(0.25)
Q3_age = df['年龄'].quantile(0.75)
IQR_age = Q3_age - Q1_age
df = df[(df['年龄'] >= Q1_age - 1.5*IQR_age) & (df['年龄'] <= Q3_age + 1.5*IQR_age) | df['年龄'].isna()]# 步骤4:处理工资异常值(用边界值替换)
Q1_salary = df['工资'].quantile(0.25)
Q3_salary = df['工资'].quantile(0.75)
IQR_salary = Q3_salary - Q1_salary
upper_bound = Q3_salary + 1.5 * IQR_salary
df['工资'] = df['工资'].clip(upper=upper_bound)# 步骤5:填充缺失值
df['年龄'].fillna(df['年龄'].median(), inplace=True)
df['工资'].fillna(df.groupby('部门')['工资'].transform('median'), inplace=True)# 步骤6:处理日期列
df['入职日期'] = pd.to_datetime(df['入职日期'], errors='coerce')
df['入职日期'].fillna(df['入职日期'].median(), inplace=True)# 步骤7:数据类型转换
df['年龄'] = df['年龄'].astype(int)print("\n清洗后的数据:")
print(df)
print(f"\n缺失值统计:\n{df.isna().sum()}")

示例 2:处理真实场景数据

import pandas as pd
import numpy as np# 模拟真实数据场景
np.random.seed(42)
n = 1000
df = pd.DataFrame({'用户ID': range(1, n+1),'年龄': np.random.randint(18, 80, n),'收入': np.random.normal(5000, 2000, n),'城市': np.random.choice(['北京', '上海', '广州', '深圳', '杭州'], n),'注册日期': pd.date_range('2020-01-01', periods=n, freq='D')
})# 随机添加缺失值
missing_indices = np.random.choice(df.index, size=int(n*0.1), replace=False)
df.loc[missing_indices, '年龄'] = np.nanmissing_indices = np.random.choice(df.index, size=int(n*0.05), replace=False)
df.loc[missing_indices, '收入'] = np.nan# 添加异常值
outlier_indices = np.random.choice(df.index, size=10, replace=False)
df.loc[outlier_indices, '年龄'] = np.random.randint(150, 200, 10)
df.loc[outlier_indices, '收入'] = np.random.randint(100000, 200000, 10)# 数据清洗
print("清洗前统计:")
print(df.describe())
print(f"缺失值:\n{df.isna().sum()}")# 删除年龄异常值
df = df[(df['年龄'] >= 18) & (df['年龄'] <= 100)]# 处理收入异常值
Q1 = df['收入'].quantile(0.25)
Q3 = df['收入'].quantile(0.75)
IQR = Q3 - Q1
df['收入'] = df['收入'].clip(lower=Q1-1.5*IQR, upper=Q3+1.5*IQR)# 填充缺失值
df['年龄'].fillna(df.groupby('城市')['年龄'].transform('median'), inplace=True)
df['收入'].fillna(df.groupby(['城市', df['年龄']//10*10])['收入'].transform('median'), inplace=True)print("\n清洗后统计:")
print(df.describe())
print(f"缺失值:\n{df.isna().sum()}")

总结

数据清洗是数据分析的重要步骤:

  1. 缺失值处理:检测、删除或填充
  2. 重复值处理:检测和删除
  3. 数据类型转换:确保数据类型正确
  4. 异常值处理:检测、删除或替换
  5. 数据规范化:标准化和归一化

http://www.dtcms.com/a/562294.html

相关文章:

  • 做网站的大型公司北京地铁建设的网站
  • 网站开发服务计入什么科目高密建网站
  • 网站域名备案转接入手续聊城做wap网站找谁
  • 网站实现微信登录公众号5000粉丝月收入
  • 自己有主机怎么做论坛网站cnu摄影官网
  • 岳阳网站建设 熊掌号推广链接打开
  • AI决策的底层逻辑:拆解智能决策的三大核心算法体系
  • 太原网站制作建设花体字转换器
  • 网站结构怎么分析小型在线购物系统
  • 商城网站建设公司排名专门做问卷的网站
  • 网站建设 起飞站群
  • 设计素材网站飘百度h5制作软件下载
  • 青山网站建设秀山网站建设
  • Mysql中MVCC的流程
  • AOI在铁路行业检测领域中的应用
  • 【C语言基础案例目录】经典C语言程序设计100例目录(附100例题目)
  • 15套儿童成长相册PPT模板合集,多风格记录成长瞬间(PPTX格式)
  • 心形温馨提示墙
  • dede网站模版网站品牌建设功能
  • 深入了解栈与队列:从基础到应用
  • 做百度还是阿里网站好免费建立手机网站吗
  • [DeepOCR] 图像预处理单元 | OCRProcessor | init 核心标记化方法
  • 幼教资源网网站开发策划书wordpress 安装轮播
  • Paxos协议流程
  • 【合新通信】浸没式液冷与冷板式液冷未来前景对比
  • 数据结构刷题 ——001
  • 网站收录查询方法阿里云搭建多个网站
  • 上海快速建站wordpress菜单栏菜单简介
  • ps做阿里网站分辨率设置龙岩网页定制
  • 傻瓜式网站建设软件网络整合营销4i原则