我想通过使用来减少一些时间lookup
after idxmin
,而不是调用min
and idxmin
。在我看来,第一个应该更有效,因为在第二个中需要搜索两次值(一次搜索最小值,另一次搜索最小值的索引 - 即 2 倍 O(NxM)),而在首先,搜索索引 (O(NxM)),然后使用索引来定位值 (O(N))
请检查这个问题 https://stackoverflow.com/questions/51931137/is-there-a-vectorized-way-to-access-values-of-column-explicitely-indicated-in-an这样你就可以了解我的推理的背景和更多细节。
结果开始出乎意料,所以我继续进行了一些测试:
我使用了 100000 行 x 10 列的数据框(添加更多行结果会变得更糟):
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(0,100,size=(100000, 10)), columns=[f'option_{x}' for x in range(1,11)]).reset_index()
df['min_column'] = df.filter(like='option').idxmin(1)
然后我做了一些计时:
%timeit -n 100 df.filter(like='option').min(1)
# 12.2 ms ± 599 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit -n 100 df.lookup(df.index, df['min_column'])
# 46.9 ms ± 526 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
请注意,即使min_columns
被预先计算为lookup
,结果比单纯寻找最小值差 4 倍。
其他尺寸对比:
RowsxCols min lookup
100000x10 12.2ms 46.9ms
1000000x10 162ms 682ms
10000x1000 173ms 220ms
1000x10000 295ms 7.97ms
从上表中可以看出,正如预期的那样,通过添加行 (1000000x10),结果并没有得到任何改善,并且在添加更多列 (10000x1000) 时,结果也只是略有改善。这种追赶是有道理的,但在我看来,它应该更大,索引应该比搜索更快(参见更新的 numpy 结果),并且只有在极端情况下(几乎不切实际,例如 1000x10000)我才开始看到优势。
这种行为有什么解释吗?
UPDATE:
我用 numpy 测试了这个,得到了预期的行为:
vals = np.random.randint(0,10,size=(100000, 10))
%timeit -n 100 np.min(vals, axis=1)
2.83 ms ± 235 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
idx_min = np.argmin(vals, axis=1)
%timeit -n 100 vals[np.arange(len(idx_min)), idx_min]
1.63 ms ± 243 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
比较结果(numpy):
RowsxCols min indexing using []
100000x10 2.83ms 1.63ms
1000000x10 24.6ms 15.4ms
100000x100 14.5ms 3.38ms
10000x1000 11.1ms 0.377ms