在Pandas数据处理场景中,多列数据匹配后的条件赋值和结果填充是高频需求,比如根据用户的地区、等级、消费金额三个字段匹配对应的优惠额度,再填充到新列中。这类操作如果采用逐行循环的方式实现,会严重拖慢处理速度,而使用Pandas内置的向量化方法可以大幅提升效率。

方法一:布尔索引直接赋值
当需要匹配的条件逻辑比较简单时,可以直接使用布尔索引筛选符合条件的行,再对新列进行赋值。这种方式代码简洁,执行效率也比较高。
首先构造示例数据:
import pandas as pd
import numpy as np
# 构造原始数据
df = pd.DataFrame({
"region": ["华东", "华南", "华北", "华东", "华南"],
"level": ["A", "B", "A", "B", "A"],
"amount": [1200, 800, 1500, 900, 2000]
})
# 初始化结果列
df["discount"] = 0
假设匹配规则为:地区是华东、等级为A、消费金额大于1000的行,优惠额度为100,其他情况为0。使用布尔索引的实现代码如下:
# 多条件布尔索引匹配赋值 condition = (df["region"] == "华东") & (df["level"] == "A") & (df["amount"] > 1000) df.loc[condition, "discount"] = 100 print(df)
运行后可以看到只有第一行符合所有条件,discount列被赋值为100,其余行保持0。
方法二:np.where函数多条件赋值
如果赋值逻辑是二选一的场景,比如符合条件赋值为A,不符合赋值为B,使用np.where函数会更简洁,不需要提前初始化结果列。
沿用上面的示例数据,需求改为:地区是华南且等级为B的行,优惠额度为50,其余为20。实现代码如下:
# np.where实现二选一赋值
df["discount"] = np.where(
(df["region"] == "华南") & (df["level"] == "B"),
50,
20
)
print(df)
这种方式可以直接在一行代码中完成条件判断和赋值,逻辑清晰,执行效率也很高。
方法三:merge关联匹配填充
当匹配规则比较复杂,或者匹配条件对应的结果存储在另一张规则表中时,使用merge关联的方式会更合适,避免写冗长的条件判断逻辑。
首先构造规则表:
# 构造匹配规则表
rule_df = pd.DataFrame({
"region": ["华东", "华东", "华南", "华北"],
"level": ["A", "B", "A", "A"],
"min_amount": [1000, 800, 1500, 1200],
"discount": [100, 60, 120, 90]
})
规则表表示:华东A等级消费满1000优惠100,华东B等级消费满800优惠60,以此类推。现在需要将原始数据和规则表匹配,当原始数据的region、level和规则表一致,且amount大于等于min_amount时,填充对应的discount。实现代码如下:
# 先关联规则表
merged_df = pd.merge(
df,
rule_df,
on=["region", "level"],
how="left"
)
# 再根据金额条件筛选赋值
merged_df["final_discount"] = np.where(
merged_df["amount"] >= merged_df["min_amount"],
merged_df["discount"],
0
)
# 清理临时列
merged_df = merged_df.drop(columns=["min_amount", "discount"])
print(merged_df)
这种方式适合规则频繁变动的场景,只需要更新规则表即可,不需要修改核心匹配代码。
不同方法的性能对比
为了对比不同方法的效率,我们构造10万行数据测试三种方法的执行时间:
# 构造10万行测试数据
large_df = pd.DataFrame({
"region": np.random.choice(["华东", "华南", "华北"], 100000),
"level": np.random.choice(["A", "B", "C"], 100000),
"amount": np.random.randint(500, 3000, 100000)
})
# 测试布尔索引方法
%timeit large_df.loc[(large_df["region"]=="华东")&(large_df["level"]=="A")&(large_df["amount"]>1000), "discount"] = 100
# 测试np.where方法
%timeit large_df["discount"] = np.where((large_df["region"]=="华东")&(large_df["level"]=="A")&(large_df["amount"]>1000), 100, 0)
# 测试merge方法(规则表10条规则)
rule_df = pd.DataFrame({
"region": np.random.choice(["华东", "华南", "华北"], 10),
"level": np.random.choice(["A", "B", "C"], 10),
"min_amount": np.random.randint(500, 2000, 10),
"discount": np.random.randint(10, 200, 10)
})
%timeit pd.merge(large_df, rule_df, on=["region", "level"], how="left")
测试结果显示,布尔索引和np.where的执行时间都在毫秒级别,merge方法因为涉及表关联,耗时稍高,但仍然远快于循环遍历的方式。如果数据量超过百万行,建议优先选择布尔索引或np.where方法。
注意事项
- 多条件组合时,每个条件需要用括号包裹,条件之间用
&(与)、|(或)连接,不能用Python原生的and、or。 - 使用
loc赋值时,一定要先筛选行再指定列,避免出现链式赋值导致的警告和赋值失效问题。 - 如果匹配条件包含空值,需要先处理空值,否则布尔判断会返回NaN,导致赋值异常。
- 当匹配规则超过10个时,优先考虑merge关联的方式,代码的可维护性会更高。