Indexing是否会使Pandas数据帧更快?

时间:2015-12-02 03:15:08

标签: python pandas

我有一个拥有超过百万条记录的pandas数据框。其中一个列是datetime。我的数据样本如下:

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的答案是&#39;否&#39;,在熊猫的特定时间段内获取记录的常用有效方法是什么?

2 个答案:

答案 0 :(得分:9)

让我们创建一个包含100万行和时间性能的数据帧。该索引是熊猫时间戳。

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

以下是从最快到最慢排序的结果(在同一台机器上测试,均为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)

以下是将Datetime索引作为列的时间:

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时效果也一样。

答案 1 :(得分: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

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

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