我正在寻找更高效的
df.reindex(labels).dropna(subset=[0])
避免在结果中包含缺少标签的NaN行,而不必在reindex
将它们放入后删除它们。
同样地,我正在寻找一个有效版本的
df.loc[labels]
无声地忽略不在df.index
中的标签,即结果的行数可能少于labels
的元素。
当行,列和标签的数量都很大并且存在明显的未命中率时,我需要一些有效的东西。具体来说,我正在寻找数据集长度的次线性。
以下是@ MaxU回答后问题的具体演示:
In [2]: L = 10**7
...: M = 10**4
...: N = 10**9
...: np.random.seed([3, 1415])
...: df = pd.DataFrame(np.random.rand(L, 2))
...: labels = np.random.randint(N, size=M)
...: M-len(set(labels))
...:
...:
Out[2]: 0
In [3]: %timeit df[df.index.isin(set(labels))]
904 ms ± 59.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [4]: %timeit df.loc[df.index.intersection(set(labels))]
207 ms ± 11.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [5]: %timeit df.loc[np.intersect1d(df.index, labels)]
427 ms ± 37 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [6]: %timeit df.loc[labels[labels<L]]
329 µs ± 23 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [7]: %timeit df.iloc[labels[labels<L]]
161 µs ± 8.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
最后两个示例比在df.index
上迭代的示例快〜1000倍。这表明df.loc[labels]
不会迭代索引,并且数据帧具有有效的索引结构,即df.index
确实索引。
所以问题是当df.loc[labels[labels<L]]
不是连续的数字序列时,如何获得与df.index
一样高效的东西。部分解决方案是原始的
In [8]: %timeit df.reindex(labels).dropna(subset=[0])
1.81 ms ± 187 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
这仍然比建议的解决方案快〜100倍,但仍然可能会失去一个数量级。
进一步证明,即使没有对索引进行上瘾,也可以获得次线性表现,并使用字符串索引重复上述内容
In [16]: df.index=df.index.map(str)
...: labels = np.array(list(map(str, labels)))
...:
...:
In [17]: %timeit df[df.index.isin(set(labels))]
657 ms ± 48.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [18]: %timeit df.loc[df.index.intersection(set(labels))]
974 ms ± 160 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [19]: %timeit df.reindex(labels).dropna()
8.7 ms ± 121 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
所以要清楚我要追求比df.reindex(labels).dropna()
更有效率的东西。这在df.shape[0]
中已经是次线性的,并且没有对索引做出任何假设,因此解决方案也应如此。
我想解决的问题是,df.reindex(labels)
将包含NaN
行,用于丢失标签,然后需要使用dropna
删除。我追求的是相当于df.reindex(labels)
的{@ 1}},并没有将它们放在那里,而没有扫描整个df.index
以找出丢失的标签。这至少在原则上是必要的:如果reindex
可以通过插入虚拟行来有效地处理丢失的标签,那么应该可以通过无所事事来更有效地处理它们。
答案 0 :(得分:3)
以下是不同方法的小比较。
样品DF(形状:10.000.000 x 2):
np.random.seed([3, 1415])
df = pd.DataFrame(np.random.rand(10**7, 2))
labels = np.random.randint(10**9, size=10**4)
In [88]: df.shape
Out[88]: (10000000, 2)
有效(现有标签):
In [89]: (labels <= 10**7).sum()
Out[89]: 1008
无效(不是现有标签):
In [90]: (labels > 10**7).sum()
Out[90]: 98992
<强>时序:强>
In [103]: %timeit df[df.index.isin(set(labels))]
943 ms ± 7.86 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [104]: %timeit df.loc[df.index.intersection(set(labels))]
360 ms ± 1.65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [105]: %timeit df.loc[np.intersect1d(df.index, labels)]
513 ms ± 655 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)