Pandas:从数据框中选择时速度慢
Pandas: slow when selecting from dataframe
我有一个 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
我正在尝试寻找一种有效的方法来查询我的数据。在 pandas 中有更好的方法吗?
是的。这可以在 pandas 中执行。我为示例创建了一些示例数据。
以下行对 '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
将列设置为索引确实提高了我的性能。
使用您原来的 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
,而不是索引本身)。
第二个注意事项:如果这种规模的性能对你很重要,那么在很多情况下,如果你需要以这种方式重复访问单个行,或者你是否可以这样做,那么考虑更大的图景也很有用更矢量化。
更改此行:
df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]
为此:
df2 = df[(df['name1'] == 'bob')]
df3 = df2[(df2['name2'] == 'greg')]
为我减少了一半的时间。
我有一个 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
我正在尝试寻找一种有效的方法来查询我的数据。在 pandas 中有更好的方法吗?
是的。这可以在 pandas 中执行。我为示例创建了一些示例数据。
以下行对 '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
将列设置为索引确实提高了我的性能。
使用您原来的 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
,而不是索引本身)。
第二个注意事项:如果这种规模的性能对你很重要,那么在很多情况下,如果你需要以这种方式重复访问单个行,或者你是否可以这样做,那么考虑更大的图景也很有用更矢量化。
更改此行:
df[(df['name1'] == 'bob') & (df['name2'] == 'greg')]
为此:
df2 = df[(df['name1'] == 'bob')]
df3 = df2[(df2['name2'] == 'greg')]
为我减少了一半的时间。