在Pandas数据处理过程中,很多开发者习惯使用循环遍历DataFrame的行来完成查找操作,这种方式在数据量较小时没有明显问题,但当数据量达到万级甚至百万级时,执行效率会大幅下降。而NumPy作为Pandas的底层依赖库,其数组的向量化操作可以一次性对整列数据进行计算,避免逐行遍历的开销,非常适合用来优化DataFrame的查找逻辑。

向量化查找的基本原理
向量化查找的核心是利用NumPy数组的广播机制和布尔索引特性,将查找条件转换为布尔数组,再通过布尔数组筛选DataFrame中符合条件的行。这种方式不需要显式编写循环,所有操作都在底层C语言层面完成,执行速度远快于Python层面的循环。
首先需要明确,Pandas的Series和DataFrame的列本质都是基于NumPy数组实现的,因此可以直接将DataFrame的列转换为NumPy数组进行操作,也可以直接对Series使用NumPy的向量化函数。
基础单条件向量化查找
单条件查找是最基础的查找场景,比如查找DataFrame中某一列值等于指定值的行。下面通过一个示例展示具体实现:
import pandas as pd
import numpy as np
# 构造测试数据
data = {
"id": range(1, 11),
"name": ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑十一", "王十二"],
"score": [85, 92, 78, 90, 88, 76, 95, 89, 83, 91]
}
df = pd.DataFrame(data)
# 将score列转换为NumPy数组
score_arr = df["score"].values
# 构造查找条件:分数大于等于90
condition = score_arr >= 90
# 通过布尔数组筛选DataFrame
result = df[condition]
print(result)
上述代码中,df["score"].values会返回该列对应的NumPy数组,之后通过score_arr >= 90生成一个布尔类型的NumPy数组,每个元素对应原数组元素是否满足条件。最后将这个布尔数组作为DataFrame的索引,就可以直接筛选出所有符合条件的行。
多条件组合向量化查找
实际场景中往往需要多个条件组合查找,比如查找分数在85到95之间,且名字包含“王”的行。向量化查找同样支持多条件的逻辑组合,只需要使用NumPy的逻辑运算符即可。
NumPy中常用的逻辑运算符有:np.logical_and(与)、np.logical_or(或)、np.logical_not(非),这些运算符可以对布尔数组进行组合,生成最终的复合条件。
import pandas as pd
import numpy as np
# 沿用上面的测试数据
data = {
"id": range(1, 11),
"name": ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑十一", "王十二"],
"score": [85, 92, 78, 90, 88, 76, 95, 89, 83, 91]
}
df = pd.DataFrame(data)
# 转换对应列为NumPy数组
score_arr = df["score"].values
name_arr = df["name"].values
# 构造多条件:分数在85到95之间,且名字包含王
condition1 = np.logical_and(score_arr >= 85, score_arr <= 95)
condition2 = np.array(["王" in name for name in name_arr])
final_condition = np.logical_and(condition1, condition2)
result = df[final_condition]
print(result)
这里需要注意,字符串相关的判断无法直接通过NumPy数组的向量化运算符完成,因此先通过列表推导式生成包含判断结果的Python列表,再转换为NumPy数组,之后和其他数值条件组合即可。如果数据量非常大,也可以考虑使用NumPy的np.vectorize函数将字符串判断逻辑向量化,进一步提升效率。
向量化查找与循环查找的性能对比
为了直观展示向量化查找的优势,我们对两种方式的执行时间进行对比,测试数据为10万行的DataFrame:
import pandas as pd
import numpy as np
import time
# 构造10万行测试数据
np.random.seed(42)
data = {
"id": range(1, 100001),
"score": np.random.randint(0, 101, size=100000)
}
df = pd.DataFrame(data)
# 循环查找实现
def loop_search(df, target):
result = []
for idx, row in df.iterrows():
if row["score"] == target:
result.append(idx)
return result
# 向量化查找实现
def vector_search(df, target):
score_arr = df["score"].values
condition = score_arr == target
return df[condition].index.tolist()
# 测试查找分数为50的行
target = 50
# 循环查找计时
start = time.time()
loop_result = loop_search(df, target)
loop_time = time.time() - start
# 向量化查找计时
start = time.time()
vector_result = vector_search(df, target)
vector_time = time.time() - start
print(f"循环查找耗时:{loop_time:.4f}秒")
print(f"向量化查找耗时:{vector_time:.4f}秒")
print(f"向量化查找是循环查找的{loop_time/vector_time:.2f}倍快")
实际运行后可以看到,向量化查找的耗时要远远低于循环查找,在数据量越大时,两者的差距会越明显。因此在对DataFrame进行查找操作时,优先使用NumPy数组的向量化方式是非常有必要的。
注意事项
- 当查找条件涉及多个列的复杂逻辑时,尽量将每个列的查找条件分开构造,再使用NumPy逻辑运算符组合,避免一次性编写过于复杂的条件表达式,提升代码可读性。
- 如果查找的目标值是一个NumPy数组,需要判断DataFrame的列是否在目标数组中,可以使用
np.isin函数,这也是向量化操作的一种,比循环判断效率高很多。 - 向量化查找虽然效率高,但会一次性生成整个布尔数组,在数据量极大且内存有限时,需要考虑分块处理,避免内存溢出。
import pandas as pd
import numpy as np
data = {"id": range(1, 6), "score": [85, 92, 78, 90, 88]}
df = pd.DataFrame(data)
# 判断score是否在指定数组中
target_arr = np.array([85, 90, 88])
score_arr = df["score"].values
condition = np.isin(score_arr, target_arr)
result = df[condition]
print(result)
NumPy向量化查找Pandas_DataFrame数组操作修改时间:2026-06-20 21:42:37