资讯动态

claude-skills 项目 pandas-pro 数据清洗实战指南:缺失值、重复值与类型转换的完整方案

发布时间:2026/9/16 16:12:04 来源:尧图企业网站定制
claude-skills 项目 pandas-pro 数据清洗实战指南缺失值、重复值与类型转换的完整方案【免费下载链接】claude-skills67 Specialized Skills for Full-Stack Developers. Transform Claude Code into your expert pair programmer.项目地址: https://gitcode.com/GitHub_Trending/claud/claude-skills本指南系统讲解 claude-skills 项目中pandas-pro技能所依赖的核心参考文档>import pandas as pd import numpy as np df pd.DataFrame({ name: [Alice, Bob, None, Diana], age: [25, np.nan, 35, 28], salary: [50000, 60000, np.nan, np.nan], department: [Eng, , Eng, Sales] }) # 检查是否存在缺失值 df.isna().any() # 按列判断 df.isna().any().any() # 整个 DataFrame 是否含缺失 # 统计缺失数量 df.isna().sum() # 按列统计 df.isna().sum().sum() # 总缺失数 # 缺失比例百分比保留两位小数 (df.isna().sum() / len(df) * 100).round(2) # 含任意缺失的行 df[df.isna().any(axis1)] # 所有值均完整的行 df[df.notna().all(axis1)] # 一键汇总缺失信息数量、占比、dtype missing_info pd.DataFrame({ missing: df.isna().sum(), percent: (df.isna().sum() / len(df) * 100).round(2), dtype: df.dtypes })注意上面的示例数据中department含有一个空字符串它不会被isna()识别为缺失详见 2.4 节。2.2 删除缺失dropna()的精细控制dropna()支持按行/按列、按子集、按有效值阈值三种删除策略# 删除含任意缺失值的行 df_clean df.dropna() # 仅当指定列存在缺失时才删除该行 df_clean df.dropna(subset[name, age]) # 仅删除整行全为缺失的行 df_clean df.dropna(howall) # 保留至少 3 个非空值的行thresh 为非空值数量下限 df_clean df.dropna(thresh3) # 删除含缺失值的列 df_clean df.dropna(axis1) # 删除缺失比例超过 50% 的列thresh 传行数阈值 threshold len(df) * 0.5 df_clean df.dropna(axis1, threshthreshold)thresh是至少保留的非空值个数当配合axis1时阈值需要用行数len(df)换算示例中的写法缺失超过 50% 的列即基于这一换算。2.3 填充缺失从常量到分组填充填充策略应结合字段语义选择切勿无脑填 0# 用常量填充 df[age] df[age].fillna(0) # 用列均值 / 中位数 / 众数填充 df[age] df[age].fillna(df[age].mean()) df[salary] df[salary].fillna(df[salary].median()) df[department] df[department].fillna(df[department].mode()[0]) # 前向填充沿用上一个有效值常用于时序数据 df[salary] df[salary].ffill() # 后向填充沿用下一个有效值 df[salary] df[salary].bfill() # 每列使用不同的填充值 fill_values {age: 0, salary: df[salary].median(), name: Unknown} df df.fillna(fill_values) # 线性插值仅适用于数值列 df[salary] df[salary].interpolate(methodlinear) # 分组填充按 department 分组用组内均值填充该组缺失 df[salary] df.groupby(department)[salary].transform( lambda x: x.fillna(x.mean()) )分组填充是工程中最常用的策略之一它用同类别样本的统计量填补缺失比全局均值更贴合业务上下文。这一模式与技能另一参考文档 aggregation-groupby.md 中的 GroupBy/transform 能力一脉相承。SKILL.md 中的Missing Value Handling模式SKILL.md也给出了同款思路对 object 列填众数、对数值列填中位数。2.4 空字符串与 NaN最容易踩的坑空字符串和纯空白不是 NaNisna()默认统计不到它们。读取外部数据CSV、Excel时这是最高发的隐形脏数据# 空字符串不会被 isna() 统计到 df[department].isna().sum() # 不会把 计入 # 将空字符串替换为 NaN df[department] df[department].replace(, np.nan) # 或用正则匹配纯空白含多个空格 df[department] df[department].replace(r^\s*$, np.nan, regexTrue) # 一次性替换多个常见假缺失占位符 df df.replace([, N/A, null, None, -], np.nan) # 更推荐读取文件时直接用 na_values 声明缺失标记 df pd.read_csv(file.csv, na_values[, N/A, null, None, -])na_values在读取阶段就统一了缺失语义避免后续反复replace这是处理真实 CSV 数据时的最佳实践。三、重复值处理识别、去重或聚合3.1 检测重复duplicated()返回布尔 Seriessubset控制按哪些列判定重复df pd.DataFrame({ id: [1, 2, 2, 3, 4, 4], name: [Alice, Bob, Bob, Charlie, Diana, Diana], email: [ax.com, bx.com, bx.com, cx.com, dx.com, d2x.com] }) # 统计完全重复的行数所有列一致 df.duplicated().sum() # 按指定列判定重复 df.duplicated(subset[id]).sum() df.duplicated(subset[name, email]).sum() # 查看全部重复行 df[df.duplicated(keepFalse)] # 重复组的所有行 df[df.duplicated(keepfirst)] # 除首次出现外的重复行 df[df.duplicated(keeplast)] # 除最后一次出现外的重复行 # 按 key 统计每个重复组的大小 df.groupby(id).size().loc[lambda x: x 1]注意上面的示例email列中dx.com与d2x.com是不同的字符串所以nameemail组合在 id4 这两行并不重复——这正是按业务键判定重复的意义。3.2 删除重复drop_duplicates()# 删除完全重复行保留首次出现 df_clean df.drop_duplicates() # 保留最后一次出现 df_clean df.drop_duplicates(keeplast) # 删除所有重复行重复组一行不留 df_clean df.drop_duplicates(keepFalse) # 按指定列去重 df_clean df.drop_duplicates(subset[id]) df_clean df.drop_duplicates(subset[name, email], keeplast) # 原地修改 df.drop_duplicates(inplaceTrue)3.3 不去重改为聚合重复未必等于错误——多条记录可能携带不同信息如历史订单。此时聚合比删除更合适# 按 id 分组聚合name 取首条email 合并去重 df_agg df.groupby(id).agg({ name: first, email: lambda x: , .join(x.unique()) }).reset_index() # 每组保留 score 最大的行 df_best df.loc[df.groupby(id)[score].idxmax()] # 为每组内重复行编号1、2、3... df[rank] df.groupby(id).cumcount() 1这与 aggregation-groupby.md 的核心理念一致聚合变换aggregation是把记录级数据变为汇总级数据的标准手段data-cleaning 文档末尾也明确指出聚合重复而非删除是相关参考之一。四、类型转换安全、显式、可空4.1 检查与基础转换# 检查当前类型 df.dtypes df.info() # 转基础类型 df[age] df[age].astype(int) df[salary] df[salary].astype(float) df[name] df[name].astype(str) # 安全转换errorscoerce 把非法值变为 NaN df[age] pd.to_numeric(df[age], errorscoerce) # 非法 - NaN # errorsignore 转换失败则保留原值 df[age] pd.to_numeric(df[age], errorsignore) # 一次转换多列 df df.astype({age: int64, salary: float64}) # 转 pandas 2.0 可空字符串类型 StringDtype df[name] df[name].astype(string) # 可空字符串errorscoerce是清洗流程的关键它能捕获混入数字列里的脏值并把它们统一转成 NaN从而进入缺失值处理管线。4.2 日期时间转换df pd.DataFrame({ date_str: [2024-01-15, 2024-02-20, invalid, 2024-03-10], timestamp: [1705276800, 1708387200, 1710028800, 1710028800] }) # 字符串转 datetime非法值变 NaT df[date] pd.to_datetime(df[date_str], errorscoerce) # 指定格式解析更快 df[date] pd.to_datetime(df[date_str], format%Y-%m-%d, errorscoerce) # Unix 时间戳转 datetimeunits 秒 / ms 毫秒 df[datetime] pd.to_datetime(df[timestamp], units) # 提取日期分量 df[year] df[date].dt.year df[month] df[date].dt.month df[day_of_week] df[date].dt.day_name() # 混合格式解析pandas 2.0 df[date] pd.to_datetime(df[date_str], formatmixed, dayfirstFalse)formatmixed是 pandas 2.0 起支持的混合格式解析方式适合同一列里出现多种日期格式的真实数据。4.3 分类类型Categorical低基数字符串的内存利器对取值有限低基数的字符串列转category既能省内存又能配合排序与 GroupBy# 低基数字符串转 category df[department] df[department].astype(category) # 有序分类可控制排序顺序 df[size] pd.Categorical( df[size], categories[Small, Medium, Large], orderedTrue ) # 验证内存节省 print(fObject: {df[department].nbytes}) df[department] df[department].astype(category) print(fCategory: {df[department].nbytes})这一技巧在 performance-optimization.md 中被进一步展开当某列的 unique 值与总行数之比小于 0.5低基数时通常建议转为category其内存收益在百万级行上非常显著。4.4 可空类型Nullable Typespandas 2.0传统int64不支持 NaN一旦列中出现缺失astype(int)就会抛错。可空类型注意大写的Int64正是为带缺失的整数设计的# 标准 int 不支持 NaN改用可空整数 df[age] df[age].astype(Int64) # 注意大写 I # 全套可空类型 df df.astype({ count: Int64, # 可空整数 price: Float64, # 可空浮点 flag: boolean, # 可空布尔 name: string, # 可空字符串 }) # 直接构造带 NA 的可空数组 df[age] pd.array([1, 2, None, 4], dtypeInt64)SKILL.md 的验证结果环节也强调变换后必须检查result.isna().sum().sum() 0、形状与列集合是否符合预期可空类型让缺失 整数不再互相排斥。五、字符串清洗去空白、规范化与正则提取5.1 常用字符串操作通过.str访问器执行向量化字符串操作不要用apply(lambda x: x.upper())逐行处理df pd.DataFrame({ name: [ Alice , BOB, charlie, None, Diana Smith], email: [ALICEEXAMPLE.COM, bobtest, invalid, None, dianaexample.com] }) # 去除首尾空白 df[name] df[name].str.strip() # 大小写规范化 df[name] df[name].str.lower() df[name] df[name].str.upper() df[name] df[name].str.title() # 标题式每个单词首字母大写 # 正则替换多个空格压成一个 df[name] df[name].str.replace(r\s, , regexTrue) # 只保留数字清洗电话号码 df[phone] df[phone].str.replace(r[^0-9], , regexTrue) # 正则提取 df[domain] df[email].str.extract(r(.)$) # 提取邮箱域名 df[first_name] df[name].str.extract(r^(\w)) # 提取第一个单词 # 拆分字符串为多列 df[[first, last]] df[name].str.split( , n1, expandTrue)5.2 字符串校验清洗后需要校验数据是否符合预期格式# 正则校验邮箱格式naFalse 保证 NaN 行返回 False 而非报错 df[valid_email] df[email].str.match(r^[\w.][\w.]\.\w$, naFalse) # 字符串长度检查 df[name_length] df[name].str.len() df[valid_length] df[name].str.len().between(2, 50) # 包含关系检查 df[has_domain] df[email].str.contains(, naFalse)naFalse参数在处理含缺失的字符串列时不可或缺否则 NaN 会传导为 NaN 布尔值破坏后续过滤逻辑。六、数据校验从断言到 pandera Schema6.1 内置校验函数把校验封装为纯函数便于复用与测试def validate_dataframe(df: pd.DataFrame) - dict: 对 DataFrame 做全面校验返回统计报告。 report { rows: len(df), columns: len(df.columns), duplicates: df.duplicated().sum(), missing_by_column: df.isna().sum().to_dict(), dtypes: df.dtypes.astype(str).to_dict(), } return report # 范围校验返回布尔掩码 def validate_range(series: pd.Series, min_val, max_val) - pd.Series: 判断 series 中的值是否落在 [min_val, max_val] 区间。 return series.between(min_val, max_val) df[valid_age] validate_range(df[age], 0, 120) # 自定义校验邮箱格式 def validate_email(series: pd.Series) - pd.Series: 校验邮箱格式返回布尔掩码。 pattern r^[\w.-][\w-]\.[\w.-]$ return series.str.match(pattern, naFalse) df[valid_email] validate_email(df[email])6.2 用 pandera 做生产级 Schema 校验当清洗流程需要进入生产环境时建议引入 [pandera] 这类 Schema 校验库把列类型 约束规则声明式地固化下来# 使用 pandera 进行 Schema 校验生产环境推荐 import pandera as pa from pandera import Column, Check schema pa.DataFrameSchema({ name: Column(str, Check.str_length(min_value1, max_value100)), age: Column(int, Check.in_range(0, 120)), email: Column(str, Check.str_matches(r^[\w.-][\w-]\.[\w.-]$)), salary: Column(float, Check.greater_than(0), nullableTrue), }) # 校验 DataFrame try: schema.validate(df) except pa.errors.SchemaError as e: print(fValidation failed: {e})pandera 的Check提供了str_length、in_range、str_matches、greater_than等内置检查器配合nullableTrue可以精确表达该列允许缺失的业务语义。七、构建可复用的数据清洗管道7.1 方法链Method Chaining模式技能文档 SKILL.md 强调使用方法链实现可读、可维护的清洗流程。一个端到端的清洗管道示例def clean_dataframe(df: pd.DataFrame) - pd.DataFrame: 基于方法链的完整数据清洗管道。 return ( df # 拷贝避免修改原始数据规避 SettingWithCopyWarning .copy() # 标准化列名小写、去空白、空格换下划线 .rename(columnslambda x: x.lower().strip().replace( , _)) # 删除整行全为缺失的行 .dropna(howall) # 清洗字符串列 .assign( namelambda x: x[name].str.strip().str.title(), emaillambda x: x[email].str.lower().str.strip(), ) # 缺失值填充 .fillna({department: Unknown}) # 类型转换 .astype({age: Int64, department: category}) # 去重按 email 判定 .drop_duplicates(subset[email]) # 重置索引 .reset_index(dropTrue) ) df_clean clean_dataframe(df)要点逐条对应前面各节copy()对应 dataframe-operations.md 中修改子集前必须 copy的规范rename/assign/fillna/astype/drop_duplicates则对应本文第 2~4 节的各项技术。7.2 管道 校验报告可审计的清洗函数生产级的清洗函数应当返回清洗后的数据与清洗统计两部分让每次清洗可审计、可复现def clean_and_validate( df: pd.DataFrame, required_columns: list[str], unique_columns: list[str] | None None, ) - tuple[pd.DataFrame, dict]: 清洗 DataFrame 并返回校验报告。 # 校验必需列是否存在 missing_cols set(required_columns) - set(df.columns) if missing_cols: raise ValueError(fMissing required columns: {missing_cols}) # 记录清洗统计 stats { initial_rows: len(df), dropped_empty: 0, dropped_duplicates: 0, filled_missing: {}, } # 拷贝后清洗 df df.copy() # 删除整行空行 before len(df) df df.dropna(howall) stats[dropped_empty] before - len(df) # 按指定键去重 if unique_columns: before len(df) df df.drop_duplicates(subsetunique_columns) stats[dropped_duplicates] before - len(df) stats[final_rows] len(df) return df, stats该函数体现了技能 SKILL.md 中评估 → 变换 → 验证的工作流先对输入做契约校验必需列再逐类执行清洗并记录影响行数最后以(df, stats)形式输出可供下游继续处理与审计。八、最佳实践总结清洗代码的工程化要点与># BAD: 不理解影响就盲目 dropna可能丢失大量数据 df df.dropna() # 可能造成严重数据损失 # GOOD: 先调查再决策 print(fMissing values: {df.isna().sum()}) print(fRows affected: {df.isna().any(axis1).sum()}) # 基于数据量权衡后再决定删除还是填充 # BAD: 缺乏领域知识地填 0age0 显然不合法 df[age] df[age].fillna(0) # 年龄 0 不合法 # GOOD: 采用合理填充策略 df[age] df[age].fillna(df[age].median()) # BAD: 类型转换不做错误处理遇到 NaN 或非法值直接抛错 df[id] df[id].astype(int) # 遇到 NaN 或非法值会失败 # GOOD: 安全转换先 coerce 再转可空整数 df[id] pd.to_numeric(df[id], errorscoerce).astype(Int64)十、相关参考与深入阅读数据清洗不是孤立环节它与 pandas-pro 技能的其他参考文档共同构成完整的数据操作体系dataframe-operations.md —— 选择与过滤是清洗前的定位数据前置步骤aggregation-groupby.md —— 用聚合替代删除处理重复数据的高级方案performance-optimization.md —— 大规模数据清洗时的内存与性能优化merging-joining.md —— 多表合并后的联合去重与一致性校验SKILL.md —— 技能总览定义了评估 → 变换 → 验证 → 优化的完整工作流与 MUST DO/MUST NOT DO 约束。对于数据量达到百万行级别或需要在受限内存环境运行的清洗任务建议同时阅读 performance-optimization.md 中的分块读取chunksize、downcast降位宽、query()/eval()等加速手段让清洗正确与清洗高效同时成立。【免费下载链接】claude-skills67 Specialized Skills for Full-Stack Developers. Transform Claude Code into your expert pair programmer.项目地址: https://gitcode.com/GitHub_Trending/claud/claude-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价