Python 使用 numpy\pandas 选择多个范围

Python selecting multiple ranges with numpy\pandas

有没有 select numpy 数组或 pandas 数据帧中的多个范围有效地一次性完成?

import pandas as pd
import numpy as np
from time import time

data = pd.DataFrame(np.random.sample((10000,10)))

%timeit -n 10000 result = pd.concat((data[100:150], data[200:300]))
10000 loops, best of 3: 1.47 ms per loop

在上面的例子中,如何在不使用concat的情况下select从100到150和200:300?这可能吗?

上述操作在使用 pd.concat 时存在瓶颈,最终可以使用 np.vstack 加速...但我仍然希望 select 这两个范围全部立即无需像 concat 那样复制底层数据。

TIME 是至关重要的,因为如果您直接访问连续范围,我希望尽可能接近您获得的时间,如下所示:

%timeit -n 10000  result = data[100:150]
10000 loops, best of 3: 94 µs per loop

您可以组合布尔条件,并将它们传递给下标运算符:

data[((100 <= data.index) & (data.index < 150)) | ((200 <= data.index) & (data.index < 300))]

(注意括号,顺便说一句 - 它们不合时宜,但优先顺序需要它们。)

我相信您首先需要列出目标行,然后使用 iloc

rows = [i for i in list(range(100, 150)) + list(range(200, 250))]
>>> data.iloc[rows, :]
            0         1         2         3         4         5         6         7         8         9
100  0.936412  0.875215  0.626169  0.362366  0.086108  0.709103  0.748132  0.696450  0.814539  0.502694
101  0.011131  0.733182  0.127739  0.743762  0.954454  0.018809  0.119522  0.319173  0.546778  0.982340
102  0.412659  0.977685  0.981917  0.319247  0.626653  0.845410  0.828058  0.506033  0.283324  0.495679
..        ...       ...       ...       ...       ...       ...       ...       ...       ...       ...
247  0.827967  0.803476  0.637800  0.603473  0.968779  0.976671  0.747728  0.029828  0.391113  0.381155
248  0.394331  0.120555  0.875771  0.529207  0.143756  0.334991  0.989489  0.584157  0.730615  0.187992
249  0.634841  0.624685  0.746429  0.374769  0.632195  0.922843  0.200508  0.024452  0.223971  0.457757

[100 rows x 10 columns]

%timeit rows = [i for i in list(range(100, 150)) + list(range(200, 300))]; data.iloc[rows, :]
1000 loops, best of 3: 283 µs per loop

%timeit pd.concat([data[100:150], data[200:300]])
1000 loops, best of 3: 927 µs per loop

我能想到几种方法。我们可以尝试一下,看看哪个最快。但是,您将无法避免复制。没有副本就无法处理不连续的范围。

连接

>>> %%timeit -n 10000  data = pd.DataFrame(np.random.sample((10000,10)))
... result = pd.concat((data[100:150], data[200:300]))
...
10000 loops, best of 3: 3.81 ms per loop

索引列表

>>> %%timeit -n 10000  data = pd.DataFrame(np.random.sample((10000,10)))
... result = data.iloc[list(range(100, 150))+list(range(200, 300))]
...
10000 loops, best of 3: 479 µs per loop

逻辑索引:

>>> %%timeit -n 10000  data = pd.DataFrame(np.random.sample((10000,10)))
... result = data[((100 <= data.index) & (data.index < 150)) | 
...               ((200 <= data.index) & (data.index < 300))]
...
10000 loops, best of 3: 580 µs per loop

切片并放下

>>> %%timeit -n 10000  data = pd.DataFrame(np.random.sample((10000,10)))
... result = data[100:300].drop(np.arange(150, 200))
...
10000 loops, best of 3: 1.22 ms per loop

所以看起来提供索引列表或逻辑索引是最快的,速度大致相当(我不会重视那么小的速度差异)。