我有一个包含一列的数据框。我想编写一个函数来返回给定键值的列值;如果密钥不在索引中,则为不同的(常量)值。我能想到(至少)两种合理的方法来实现这一点 - 除了速度之外,是否有理由比另一种更好?
并且w / r / t速度,len(df)= 10k且len(ids_to_check)= 20k,try / except大约慢2倍。这对我来说是令人惊讶的,因为另一种方法必须遍历索引两次。 对此行为有任何直观的解释吗?
使用try
/ except
块
def attempt_1(id_val,df):
try:
return df.loc[id_val]
except KeyError:
return constant_val
%timeit [attempt_1(i,df) for i in ids_to_check]
1 loops, best of 3: 480 ms per loop
使用in
来测试id_val
是否在索引中
def attempt_2(id_val,df):
if id_val in df.index:
return df.loc[id_val]
else:
return constant_val
%timeit [attempt_2(i,df) for i in ids_to_check]
1 loops, best of 3: 235 ms per loop
答案 0 :(得分:0)
创建测试框架
In [22]: df = DataFrame(dict(A = np.random.randn(10000)))
选择一些ID
In [21]: ids_to_check = np.random.choice(np.arange(0,20000),size=10000,replace=False)
你的方法
In [18]: %timeit [attempt_2(i,df) for i in ids_to_check]
1 loops, best of 3: 409 ms per loop
In [16]: %timeit [attempt_1(i,df) for i in ids_to_check]
1 loops, best of 3: 620 ms per loop
使用矢量化查找的有效方法。如果位置值在索引中,则isin
返回一个布尔数组;索引这个很快。
然后我重新索引以恢复原始索引并填充缺失条目的值
In [19]: %timeit df.A.loc[df.index.isin(ids_to_check)].reindex(df.index).fillna(-100)
100 loops, best of 3: 6.74 ms per loop
这会返回一个系列;很容易就可以返回DataFrame
In [20]: df.A.loc[df.index.isin(np.random.choice(np.arange(0,20000),size=10000,replace=False))].reindex(df.index).fillna(-100)
Out[20]:
0 -100.000000
1 -0.485421
2 -0.397338
3 -100.000000
4 0.573031
5 -100.000000
6 0.359699
7 0.298462
8 -100.000000
9 -1.274819
10 -100.000000
11 0.112869
12 -100.000000
13 -2.251186
14 -0.846211
...
9985 -100.000000
9986 -0.988055
9987 -0.080460
9988 -100.000000
9989 1.007490
9990 -1.454466
9991 0.875455
9992 -100.000000
9993 -100.000000
9994 0.194506
9995 -100.000000
9996 -100.000000
9997 -100.000000
9998 -0.477828
9999 -0.777487
Name: A, Length: 10000, dtype: float64
所以答案总是使用矢量化方法,永远不要循环。