【问题标题】:Python selecting multiple ranges with numpy\pandasPython 用 numpy\pandas 选择多个范围
【发布时间】:2015-09-15 05:20:30
【问题描述】:

是否可以一次性有效地选择 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 的情况下选择 100 到 150 和 200:300?这甚至可能吗?

上述操作在使用 pd.concat 时存在瓶颈,最终可以使用 np.vstack 加速......但我仍然想一次选择两个范围,而不像 concat 那样复制底层数据做。

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

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

【问题讨论】:

    标签: python numpy pandas range


    【解决方案1】:

    我相信您首先需要列出目标行,然后使用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
    

    【讨论】:

    • 1.你的一些理解是多余的:它只是range(100, 150) + range(200, 250)(也更短)。 2. IINM,你正在用你写的东西从 pandas 速度转移到 Python 速度。
    • @AmiTavory 谢谢。我不知道可以添加这样的范围。
    • @AmiTavory 你不能在 Python 3 中添加这样的范围。
    • @TheBlackCat 谢谢。所以在 Py3 中它将是 list(range(...)) + list(range(...))?
    • @AmiTavory 是的,尽管这在 Python 2 和 Python 3 中同样适用。我尝试尽可能通用地编写我的代码。
    【解决方案2】:

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

    连接

    >>> %%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
    

    因此,提供索引列表或逻辑索引似乎是最快的,速度大致相当(我不会对这么小的速度差异给予任何重视)。

    【讨论】:

    • 为什么要在 timeit 循环中创建数据?
    • 使用%%timeit时,%%timeit行上的代码被认为是设置代码,不计入计时。我这样做是为了确保每次重复都会重新生成数据。 pandas 和/或 numpy 会做一些缓存,如果我不这样做的话会搞砸时间。
    • 有趣。感谢您的回复。
    • 感谢您的广泛评论!因此,如果您直接访问连续范围,就没有办法接近您将获得的时间吗?我已经编辑了我的答案,以包括 (%timeit -n 10000 x = data[100:150]; 10000 循环,最好的 3:每个循环 94 µs) 的时间,因为评论中的缩进很糟糕
    • @AlessandroMariani 恐怕不会。您可以将 numpy 数组(pandas 使用)视为一个连续的内存块,nth 元素 n 位于黑色内存的nth 区域中(从技术上讲,它只需要跨步)。 numpy 用于快速计算的算法需要这个。切片只是该内存块的一部分的“视图”,而无需复制任何内容。但是为了让它像数组一样工作,它仍然必须是连续的。如果要使用不连续的片段,则需要将这些片段复制到新的连续内存块中,这很慢。
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      • 2018-08-18
      • 1970-01-01
      相关资源
      最近更新 更多