对 DataFrame 列进行条件划分是数据预处理中的高频操作。比如把销售额按数值大小归入“高、中、低”三档,或者把订单状态码转换成可读的文本描述。这类任务如果直接用条件判断语句逐行处理,代码会迅速膨胀,而且规则一旦调整,维护成本很高。用字典来集中管理映射关系,再配合 Pandas 的向量化方法,可以让代码保持简洁,执行效率也更高。下面从几个实际场景出发,介绍如何用字典值进行条件划分。

典型场景与字典结构设计
条件划分本质上是一个从原值到目标值的映射,只不过映射规则可能基于精确相等,也可能基于数值区间。精确映射常见于类别编码转换,例如把状态码 1、2、3 分别对应为“待支付”“已支付”“已取消”。此时字典的键就是原列中出现的具体值,值是目标标签。另一种是区间映射,例如把年龄分成“青年”“中年”“老年”,这时无法直接写出所有年龄的具体键,需要引入区间边界。
针对区间映射,字典的键可以设计成区间起点,值对应标签,再用二分查找确定落点;也可以先构造边界列表和标签列表,然后交给 Pandas 的 cut 函数处理。前者的优势是规则完全由字典管理,改动时只需要调整字典,后者则利用了 Pandas 内置的分箱能力,处理大量区间时性能更好。无论哪种方式,核心思想都是把条件逻辑数据化,而不是硬编码在流程里。
在设计字典时,要特别注意键的数据类型必须和 DataFrame 列的数据类型一致。如果列是整数类型,字典的键就应该用整数而不是字符串,否则映射会失败且不会报错,只会产生一大堆 NaN。这一点在从配置文件或数据库加载映射规则时尤其容易踩坑。
用 map 方法实现精确值映射
对于键值一一对应的场景,Pandas 的 map 方法是最直接的工具。它接受一个字典或 Series,将原列中的每个值替换为字典中对应的值,找不到键时返回 NaN。下面是一个完整的示例,把订单状态码转换为中文描述。
import pandas as pd
# 创建示例数据
df = pd.DataFrame({
'order_id': [101, 102, 103, 104, 105],
'status_code': [1, 2, 1, 3, 2]
})
# 定义状态码到状态的映射字典
status_map = {
1: '待支付',
2: '已支付',
3: '已取消'
}
# 使用 map 进行条件划分
df['status_label'] = df['status_code'].map(status_map)
print(df)
# order_id status_code status_label
# 0 101 1 待支付
# 1 102 2 已支付
# 2 103 1 待支付
# 3 104 3 已取消
# 4 105 2 已支付
上面代码中,map 在底层使用哈希表查找,时间复杂度接近 O(1),即使数据量达到百万级也能快速完成。如果原列中存在字典里没有的值,例如状态码 4,映射结果会变成 NaN。实际业务中通常需要为未知值提供一个默认标签,可以在映射后使用 fillna 补充,或者先构造一个带有默认值的字典。
另一种做法是利用 replace 方法,它同样支持字典映射,但行为略有差异。replace 可以同时处理多列,并且对 NaN 的处理方式更灵活。对于单列精确替换,map 的性能略优于 replace,因为 map 不涉及列级别的匹配逻辑。如果映射规则只作用于某一列,建议优先使用 map;如果需要对整个 DataFrame 的多列统一替换,replace 会更方便。
用 cut 与字典配合处理区间划分
区间划分比精确映射更复杂一点,因为一个区间的开闭、边界值归属都需要明确。Pandas 提供了 cut 函数来将连续数值切分成离散区间。虽然 cut 本身不直接接受字典,但可以将字典的键和值拆成边界列表和标签列表,再传入 cut。下面这个例子把年龄划分为三个区间:0-18 为“未成年”,19-35 为“青年”,36 以上为“中年及以上”。
import pandas as pd
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六', '钱七'],
'age': [16, 28, 45, 33, 8]
})
# 区间字典:键为区间下界,值为标签
age_bins_dict = {
0: '未成年',
19: '青年',
36: '中年及以上'
}
# 拆分字典得到边界和标签
bins = sorted(age_bins_dict.keys()) + [float('inf')] # 添加无穷大作为最后一个上界
labels = [age_bins_dict[b] for b in sorted(age_bins_dict.keys())]
# 使用 cut 进行区间划分,right=False 表示左闭右开
df['age_group'] = pd.cut(df['age'], bins=bins, labels=labels, right=False)
print(df)
# name age age_group
# 0 张三 16 未成年
# 1 李四 28 青年
# 2 王五 45 中年及以上
# 3 赵六 33 青年
# 4 钱七 8 未成年
上面的代码中,bins 列表的第一个元素是 0,表示第一个区间的起点为 0,最后一个元素是无穷大,保证所有年龄都能落入某个区间。参数 right=False 指定区间为左闭右开,比如 19 岁时会归入“青年”,而 36 岁时归入“中年及以上”。如果希望右闭左开,可以改为 right=True,但此时边界值的分配会改变,需要根据业务需求确定。
当区间数量很多或者规则经常变动时,手动维护边界列表和标签列表容易出现顺序错位。一个更稳健的方式是把字典设计成“区间描述”与“标签”的映射,例如 {'0-18': '未成年', '19-35': '青年', '36+': '中年及以上'},然后编写一个小函数解析区间字符串生成 bins 和 labels。这样修改规则时只需要改动字典字符串,逻辑代码保持稳定。
动态字典与未知值处理技巧
在实际项目中,映射字典往往不是硬编码在脚本里的,而是从配置文件、数据库或远程接口动态加载。此时可以把字典的构建逻辑独立出来,例如使用 JSON 文件存储规则,启动时加载并转换为 Python 字典。加载后建议验证键的数据类型,因为 JSON 中的数字默认可能是整数或浮点数,如果原列是整数而 JSON 中键是浮点数 1.0,直接 map 会导致映射失败。
import json
import pandas as pd
from collections import defaultdict
# 假设从配置文件中读取规则
config_json = '{"1": "待支付", "2": "已支付", "3": "已取消"}'
raw_map = json.loads(config_json)
# 将字符串键转换为整数键,保证与列类型一致
status_map = {int(k): v for k, v in raw_map.items()}
# 使用 defaultdict 提供默认值,避免未知键产生 NaN
default_status = '未知状态'
safe_map = defaultdict(lambda: default_status, status_map)
df = pd.DataFrame({'status_code': [1, 2, 4, 3]})
df['status_label'] = df['status_code'].map(safe_map)
print(df)
# status_code status_label
# 0 1 待支付
# 1 2 已支付
# 2 4 未知状态
# 3 3 已取消
这里用 defaultdict 的好处是,map 在遇到未知键时不会返回 NaN,而是调用默认值工厂函数得到“未知状态”。但需要注意,defaultdict 的工厂函数返回的是一个固定字符串,如果默认值需要根据原值动态变化,就需要结合 apply 和自定义函数来处理。
对于区间划分的未知值,例如数值超出所有区间,使用 cut 时可以通过设置 bins 的两端为负无穷和正无穷来避免 NaN。如果数据中有缺失值,map 和 cut 都会保留 NaN,可以在映射后用 fillna 统一填充一个默认类别,比如“未分类”。这些细节处理得当,整个条件转换流程才会既健壮又容易阅读。
Pandas DataFrame条件划分字典值修改时间:2026-09-23 15:09:06