【问题标题】:Does Indexing makes Slice of pandas dataframe faster?索引是否使 Slice of pandas 数据帧更快?
【发布时间】:2015-12-02 03:15:08
【问题描述】:

我有一个包含超过百万条记录的 pandas 数据框。其中一列是日期时间。我的数据样本如下:

time,x,y,z
2015-05-01 10:00:00,111,222,333
2015-05-01 10:00:03,112,223,334
...

我需要在特定期间有效地获取记录。以下幼稚的方式非常耗时。

new_df = df[(df["time"] > start_time) & (df["time"] < end_time)]

我知道在像 MySQL 这样的 DBMS 上,按时间字段建立索引对于通过指定时间段来获取记录是有效的。

我的问题是

  1. df.index = df.time 等 pandas 的索引是否会使切片过程更快?
  2. 如果Q1的答案是“否”,那么在pandas中获取特定时间段内记录的常用有效方法是什么?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    让我们创建一个具有 100 万行和时间性能的数据框。索引是 Pandas 时间戳。

    df = pd.DataFrame(np.random.randn(1000000, 3), 
                      columns=list('ABC'), 
                      index=pd.DatetimeIndex(start='2015-1-1', freq='10s', periods=1000000))
    

    以下是从最快到最慢排序的结果(在同一台机器上使用 v. 0.14.1(不要问...)和最新版本 0.17.1 进行测试):

    %timeit df2 = df['2015-2-1':'2015-3-1']
    1000 loops, best of 3: 459 µs per loop (v. 0.14.1)
    1000 loops, best of 3: 664 µs per loop (v. 0.17.1)
    
    %timeit df2 = df.ix['2015-2-1':'2015-3-1']
    1000 loops, best of 3: 469 µs per loop (v. 0.14.1)
    1000 loops, best of 3: 662 µs per loop (v. 0.17.1)
    
    %timeit df2 = df.loc[(df.index >= '2015-2-1') & (df.index <= '2015-3-1'), :]
    100 loops, best of 3: 8.86 ms per loop (v. 0.14.1)
    100 loops, best of 3: 9.28 ms per loop (v. 0.17.1)
    
    %timeit df2 = df.loc['2015-2-1':'2015-3-1', :]
    1 loops, best of 3: 341 ms per loop (v. 0.14.1)
    1000 loops, best of 3: 677 µs per loop (v. 0.17.1)
    

    以下是以日期时间索引为列的时间:

    df.reset_index(inplace=True)
    
    %timeit df2 = df.loc[(df['index'] >= '2015-2-1') & (df['index'] <= '2015-3-1')]
    100 loops, best of 3: 12.6 ms per loop (v. 0.14.1)
    100 loops, best of 3: 13 ms per loop (v. 0.17.1)
    
    %timeit df2 = df.loc[(df['index'] >= '2015-2-1') & (df['index'] <= '2015-3-1'), :]
    100 loops, best of 3: 12.8 ms per loop (v. 0.14.1)
    100 loops, best of 3: 12.7 ms per loop (v. 0.17.1)
    

    上述所有索引技术都会产生相同的数据帧:

    >>> df2.shape
    (250560, 3)
    

    在这种情况下,前两种方法中的任何一种似乎都是最好的,而第四种方法在使用最新版本的 Pandas 时也同样有效。

    【讨论】:

    • 您使用 .loc 的时间非常奇怪。你用的是什么版本? (IOW on >= 0.16.2 ,1st 和 4th 几乎相同)
    • @Jeff 我最初使用旧版本的 Pandas 进行了测试,但刚刚更新了结果以与最新版本进行比较。
    【解决方案2】:

    我从未处理过这么大的数据集,但也许您可以尝试将时间列重铸为日期时间索引,然后直接切片。像这样的。

    timedata.txt (extended from your example):
    
    time,x,y,z
    2015-05-01 10:00:00,111,222,333
    2015-05-01 10:00:03,112,223,334
    2015-05-01 10:00:05,112,223,335
    2015-05-01 10:00:08,112,223,336
    2015-05-01 10:00:13,112,223,337
    2015-05-01 10:00:21,112,223,338
    
    df = pd.read_csv('timedata.txt')
    df.time = pd.to_datetime(df.time)
    df = df.set_index('time')
    print(df['2015-05-01 10:00:02':'2015-05-01 10:00:14'])
    
                           x    y    z
    time                              
    2015-05-01 10:00:03  112  223  334
    2015-05-01 10:00:05  112  223  335
    2015-05-01 10:00:08  112  223  336
    2015-05-01 10:00:13  112  223  337
    

    请注意,在示例中,用于切片的时间不在列中,因此这适用于您只知道时间间隔的情况。

    如果您的数据有固定的时间段,您可以创建一个日期时间索引,该索引可以提供更多选项。我不想假设你的时间段是固定的,所以为更一般的情况构建了这个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-31
      • 2019-02-01
      • 2019-07-22
      相关资源
      最近更新 更多