简短的回答
有比蛮力循环更快的矢量化方法来做到这一点。保持 Pandas 级别的一个特定选项是
(tra_df.groupby(tra_df.columns.tolist())
.size()
.reindex(tst_df.values.T.tolist(), fill_value=0)
这应该会为您提供巨大的性能提升,可以通过 NumPy 矢量化解决方案进一步改进,具体取决于您对什么满意。
长答案
假设您的训练和测试数据看起来像这样。
import pandas as pd; import numpy as np; from numpy.random import RandomState
rnd_st = RandomState(8675309)
tra_df = pd.DataFrame(dict(A=rnd_st.randint(0, 10, 10**3),
B=rnd_st.randint(0, 10, 10**3)))
tst_df = pd.DataFrame(dict(A=rnd_st.randint(0, 10, 10**3),
B=rnd_st.randint(0, 10, 10**3)))
首先,您并没有真正正确地使用 Pandas
def f(A, B, x, y):
data = df.loc[df[A].isin([x]) & df.B.isin([y])]
return len(data)
isin
不是为了匹配像这样的单个值,而是当你没有其他选项时的一个列表或一组值。在您的情况下,您可以直接使用
(df.A == x) & (df.B == y)
此外,再次索引您的 DataFramedf.loc
只是为了获取它的长度是没有意义的……您不妨sum
直接在布尔向量上使用来计算匹配项。将它们放在一起并apply
在测试数据帧上使用,您可以通过以下方式实现相同的输出
tst_df.apply(lambda x: ((tra_df.A == x.A) & (tra_df.B == x.B)).sum(), axis=1)
但这仍然非常慢 - 将上述方法包装在一个函数中,并将其与样本数据上的原始方法进行比较
%timeit your_way(tra_df, test_df)
1 loops, best of 3: 819 ms per loop
%timeit direct_er_way(tra_df, test_df)
1 loops, best of 3: 673 ms per loop
groupby
使用and then会快得多reindex
,因为它提供了一个矢量化解决方案,而不是暴力循环,我们可以有效地散列计数。
(tra_df.groupby(tra_df.columns.tolist())
.size()
.reindex(tst_df.values.T.tolist(), fill_value=0)
基准测试,
%timeit groupby_way()
100 loops, best of 3: 3.04 ms per loop
我对 NumPy 不是很精通,但我可以放心地假设,如果这个功能仍然不够快,无法满足您的需求,那么下一步是避免一些开销的 NumPy 矢量化解决方案。