Python 熊猫:从数据帧中选择时变慢

Python 熊猫:从数据帧中选择时变慢,python,pandas,Python,Pandas,我有一个从数据库中获取的字典列表创建的数据框。我尝试将其用作内存中的数据库,我使用以下函数查询该数据库: 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

我有一个从数据库中获取的字典列表创建的数据框。我尝试将其用作内存中的数据库,我使用以下函数查询该数据库:

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]
In [25]: %timeit filter_entities(df, df['name1'][100], df['name2'][100])

1000 loops, best of 3: 1.36 ms per loop
这样做似乎比我预期的慢得多。即使在几百行上进行测试,每次调用也需要大约1ms的时间。在创建dataframe时,我尝试在这些列上设置索引,但这并不影响性能:

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

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

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

下一行为“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

将列设置为索引确实提高了我的性能

使用原始的
过滤\u实体
功能:

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]
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\u entities
函数中花费的大部分时间用于布尔比较(创建
,而不是索引本身)

第二个注意事项:如果这种规模上的性能对您很重要,那么在许多情况下,如果您需要以这种方式重复访问单个行,或者如果您可以进行更矢量化的访问,那么考虑更大的范围也是很有用的。

更改此行:

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

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

对我来说,时间缩短了一半。

你能提供一个可重复的例子吗?(一些虚拟数据的大小与您已经遇到的问题相同)顺便问一下,最后一个函数(
rows.iloc[0]
)是否正确?因为这将只返回过滤数据的第一行。有关可复制的示例,请参阅我的编辑。是的,我只寻找一行,但是删除那部分并不会使它更快。你知道名称1和名称2的组合总是唯一的吗?或者有没有可能有多行匹配选择?这有什么不同(本质上,您也在做布尔选择,但只是在一行中,而不是在一个函数中)或者比OP更快?这里的性能差异可以忽略不计。为什么迭代6行并比较2个值需要2毫秒?在我的计算机上,使用python循环需要1µs。你是对的,我使用的索引是错误的,因为我认为它会加快布尔索引的创建,但事实并非如此。我还将研究矢量化,因为我需要做很多这方面的工作。谢谢