熊猫:从数据框中选择时速度慢

时间:2015-02-03 16:02:31

标签: python pandas

我有一个DataFrame,它是从我从数据库中获取的字典列表创建的。我正在尝试将其用作内存数据库,我使用以下函数进行查询:

def filter_entities(df, name1, name2):
    key = ((df.name1 == name1) &
           (df.name2 == name2))

    rows = df.loc[key]
    if len(rows) == 0:
        return None
    return rows.iloc[0]

这样做似乎比我预期的要慢得多。即使在几百行上进行测试,每次调用大约需要1毫秒。我在创建数据帧时尝试在这些列上设置索引,但它不会影响性能:

entities.set_index(['name1', 'name2'], drop=False, inplace=True)

以下是创建测试数据集的快捷方法:

import random, string
import pandas as pd
df = pd.DataFrame([{
   'name1': ''.join([random.choice(string.letters) for i in range(10)]),
   'name2': ''.join([random.choice(string.letters) for i in range(10)]),
   'val1': random.randint(0, 2**16),
   'val2': random.randint(0, 2**16),
   'val3': random.randint(0, 2**16),
   } for j in range(1000)])

In[27]: %timeit filter_entities(df, df['name1'][100], df['name2'][100])
1000 loops, best of 3: 1.91 ms per loop

我正在尝试找到一种有效的方法来查询我的数据。在熊猫中有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

将列设置为索引确实可以改善我的性能。

使用原始filter_entities功能:

In [25]: %timeit filter_entities(df, df['name1'][100], df['name2'][100])

1000 loops, best of 3: 1.36 ms per loop

将列设置为索引,然后将该索引编入索引:

In [26]: df2 = df.set_index(['name1', 'name2'])

In [27]: %timeit df2.loc[df['name1'][100], df['name2'][100]]
10000 loops, best of 3: 160 µs per loop

请注意,在filter_entities函数中花费的大部分时间用于布尔比较(创建key,而不是用于索引本身)。

第二个注意事项:如果这个等级的表现对你很重要,那么在很多情况下,如果你需要反复以这种方式访问​​各个行,或者你可以做更多的矢量化,那么考虑更大的图片也是有用的。

答案 1 :(得分:0)

是。这可以在熊猫中进行。我为该示例创建了一些示例数据。

以下行为“name1”等于bob且“name2”等于greg的列的数据框设置子集。

df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]

完整代码:

import pandas as pd

data = [{'name1': 'bob', 'name2':  'greg', 'value': 1},
        {'name1': 'bob', 'name2':  'greg', 'value': 2},
        {'name1': 'jim', 'name2':  'greg', 'value': 3},
        {'name1': 'bob', 'name2':  'greg', 'value': 4},
        {'name1': 'bob', 'name2':  'tim', 'value': 5},
        {'name1': 'bob', 'name2':  'jo', 'value': 6}]

    df = pd.DataFrame(data)
    print df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]

      name1 name2  value
    0   bob  greg      1
    1   bob  greg      2
    3   bob  greg      4

def filter_entities(entities, name1, name2):
    key = ((entities.name1 == name1) &
           (entities.name2 == name2))

    rows = entities.loc[key]
    if len(rows) == 0:
        return None
    return rows.iloc[0]

%timeit test1 = df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]
%timeit test2 = filter_entities(df, 'bob', 'greg')

100 loops, best of 3: 2.02 ms per loop
100 loops, best of 3: 2.31 ms per loop

答案 2 :(得分:0)

更改此行:

df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]

对此:

df2 = df[(df['name1'] == 'bob')]
df3 = df2[(df2['name2'] == 'greg')]

为我减少了一半的时间。