资讯动态

Python分析特征数据类别与预处理方法速学

发布时间:2026/10/14 8:23:14 来源:尧图企业网站定制
前言做数据相关的活儿八成时间花在把数据收拾干净上——这一步叫预处理。它要回答的问题很朴素一列数据里哪些是数值、哪些是类别标签缺的值怎么发现、怎么补类别怎么变成模型能吃的数字数值量纲差太远怎么拉齐要先纠正一个很常见的误解预处理必须用 pandas、numpy、scikit-learn。这些库确实好用但预处理的每一个基本操作都能用标准库做出来——数数用collections.Counter统计用statistics缺失判断用math.isnan独热编码和标准化各写十几行即可。理解这些手写实现才能真正看懂第三方库的fit/transform在干什么否则只是照着 API 抄出错也不知道错在哪。本文示例全部只用 Python 标准库基于 Python 3.8。涉及第三方库的地方只讲思路并注明以各库官方文档为准不给具体到参数名的调用。一、先给特征分类拿到一列数据第一步是判断它属于哪一类因为不同类别走不同处理特征类别例子能否直接算加减乘除典型处理数值型连续身高、价格能标准化 / 归一化数值型离散计数点击次数能可能需要对数变换类别型无序城市、颜色不能独热编码类别型有序低/中/高不能有序映射为整数文本型评论不能分词 / 向量化时间型下单时刻不能拆成 年/月/日/星期 等最容易出错的是把类别当数值把城市编码成 1、2、3 然后送去算平均得到的数字没有任何意义。无序类别只能用独热编码这类方式展开。二、缺失值怎么发现怎么处理标准库里表示缺失有两套None空对象和浮点nanNot a Number。判断方式不同千万别乱用等式。# 适用于 Python 3.8import mathvalues [1.0, None, 3.0, float(nan), 5.0]for v in values:if v is None:print(None 类型缺失)elif isinstance(v, float) and math.isnan(v):print(nan 类型缺失)else:print(有效值, v)关键点nan不等于任何东西包括它自己。所以v float(nan)永远是False必须用math.isnan(v)。None则要用is None判断。# 适用于 Python 3.8import mathnan float(nan)print(nan nan) # False —— 反直觉但必须记住print(math.isnan(nan)) # Trueprint(None None) # True处理缺失有三种主流思路丢弃样本或该列整行删掉、填充用均值、中位数、众数或固定值、标记额外加一列是否缺失。选哪种取决于缺失比例和缺失是否有意义。三、类别特征计数与频次统计数据里每个类别出现了几次标准库一行就能搞定# 适用于 Python 3.8from collections import Countercities [北京, 上海, 北京, 广州, 北京, 上海]counter Counter(cities)print(counter) # Counter({北京: 3, 上海: 2, 广州: 1})total len(cities)for city, n in counter.most_common():print(f{city}: {n} 次占比 {n / total:.1%})Counter.most_common()按频次从高到低返回不给参数就返回全部。频次表有两个用途一是发现脏数据北京市和北京被当成两个类别二是在做独热编码时过滤掉极其稀有的类别避免列数爆炸。四、独热编码手写一遍就懂了独热编码one-hot encoding把每个无序类别变成一个只有一个 1、其余全 0的向量。手写实现也就十几行# 适用于 Python 3.8def build_vocab(column):从一列数据里收集所有类别按固定顺序排序保证映射稳定。return sorted({v for v in column if v is not None})def one_hot(value, vocab):返回长度等于类别数的 0/1 列表。vector [0] * len(vocab)if value in vocab:vector[vocab.index(value)] 1return vectorcities [北京, 上海, 北京, 广州]vocab build_vocab(cities)print(vocab) # [上海, 北京, 广州]for c in cities:print(c, one_hot(c, vocab))vocab词表必须在训练集上确定并固定下来再做验证集、测试集时复用同一份否则同一类别在不同批次里会映射到不同位置。这就是训练时fit、之后transform这个模式的由来。要提醒的是独热编码会让列数随类别数线性增长如果一个特征是用户 ID这种高基数类别展开后列数会大得离谱这时通常改用目标编码等手段具体做法以对应库的官方文档为准。五、标准化把量纲拉齐数值特征常常量纲差很远比如年龄 0~100 与收入 0~1000000。标准化standardization把它变成均值 0、标准差 1的分布# 适用于 Python 3.8import statisticsdef standardize(values):按 z-score 公式做标准化 (x - 均值) / 标准差。mean statistics.mean(values)stdev statistics.pstdev(values) # 总体标准差if stdev 0: # 全部相同避免除零return [0.0] * len(values)return [(x - mean) / stdev for x in values]data [10.0, 20.0, 30.0, 40.0, 50.0]scaled standardize(data)print([round(v, 3) for v in scaled]) # [-1.414, -0.707, 0.0, 0.707, 1.414]print(round(statistics.mean(scaled), 10)) # 0.0注意两点一是除零保护——某列所有值相同则标准差为 0必须单独处理二是训练集和测试集要用同一组均值和标准差即均值方差只能从训练集算不能各算各的。另一种常见做法是归一化min-max scaling把值压到 0~1公式是(x - min) / (max - min)同样要防除零且对离群点更敏感。常见坑点坑 1用判断nan。❌if v float(nan):—— 永远为假缺失值一个都抓不到。✅ 用math.isnan(v)判断None用v is None。坑 2把无序类别编码成 1/2/3 当数值用。❌ 城市映射成整数后算平均、算距离得出无意义的结果。✅ 无序类别用独热编码确实有序低/中/高才映射为有序整数。坑 3词表顺序不稳定。❌ 用set直接生成类别表并依赖它的迭代顺序 —— 顺序不保证映射会漂移。✅ 用sorted(...)固定顺序并保存下来给后续数据复用。坑 4训练集与测试集各算各的均值方差。❌ 各归一化各的 —— 训练时学到的尺度在测试时对不上评估失真。✅ 只从训练集计算参数测试集套用同一组参数。坑 5标准化时没防除零。❌ 某列全等时标准差为 0(x - mean) / 0抛ZeroDivisionError。✅ 先判断stdev 0或分母为 0返回全 0 或原值。坑 6把缺失值当成 0 直接参与平均。❌ 用 0 填充缺失均值和方差都被拉偏尤其在缺失比例高时。✅ 明确区分值为 0和值缺失填充用均值/中位数/众数或另加一列标记缺失。坑 7对高基数类别做独热。❌ 用户 ID 独热后列数上万内存和训练都扛不住。✅ 先做频次过滤或改用目标编码等手段以对应库官方文档为准。总结步骤标准库做法关键注意判特征类别人工判断 类型检查无序类别不能当数值缺失判断v is None/math.isnan(v)nan ! nan类别计数collections.Counter用来发现脏数据独热编码手写 vocab 0/1 向量词表固定、训练测试共用标准化statistics.mean/pstdev防除零、参数只从训练集算一句话总结预处理的核心不是调库而是理解每一列到底代表什么。先把特征分成数值、类别、文本、时间几类再分别处理缺失、编码与缩放这些步骤用标准库都能写清楚第三方库只是把它们打包得更快——具体 API 行为以各库官方文档为准不要凭印象调用。

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

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

免费获取报价 →
↑