2014-06-12 29 views
1

我想在熊猫列中搜索一个字符串。我已经读过,它应该是最快排序的第一列和搜索字符串使用搜索排序值。我发现这比在同一个numpy数组上搜索蛮力(array == string)要慢。要知道为什么,我已经进行了以下试验:python熊猫与numpy数组的搜索性能

import timeit 

setup4 = ''' 
import numpy as np, string, random 

d =  np.array([ 
      u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)) 
      for _ in range(20000) 
      ],dtype=np.object) 
''' 



setup5 = ''' 
import numpy as np, pandas as pd, string, random 

header = [ 
        u'A', 
        u'B', 
        u'C', 
        u'D', 
        u'E', 
        u'F', 
        u'G', 
        u'H', 
        u'I', 
        u'J', 
        u'K', 
        u'L', 
        u'M', 
        u'N' 
        ] 


data =  [[pd.to_datetime('20140505'), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u'sfgweorfjdfl', 
       u'dsiofqjwel;dmfv', 
       u'e3ruiwefjvgoiubg', 
       u'3124oirjrg;klhbas', 
       u';3rhfgfbnvsad3r', 
       pd.to_datetime('20140505'), 
       u'1234irtjurgbfas', 
       u'12;rhfd;hb;oasere', 
       u'124urgfdnv.,sadfg', 
       u'1rfnhsdjk.dhafgsrdew', 
       u'safeklrjh2nerfgsd.' 
       ] for _ in range(20000)] 

df = pd.DataFrame(data,columns=header) 
df_sorted = df.sort(['B','C']) 
e = df_sorted['B'].values 
''' 

setup6 = ''' 
import numpy as np, pandas as pd, string, random 

header = [ 
        u'A', 
        u'B', 
        u'C', 
        u'D', 
        u'E', 
        u'F', 
        u'G', 
        u'H', 
        u'I', 
        u'J', 
        u'K', 
        u'L', 
        u'M', 
        u'N' 
        ] 


data =  [[pd.to_datetime('20140505'), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u'sfgweorfjdfl', 
       u'dsiofqjwel;dmfv', 
       u'e3ruiwefjvgoiubg', 
       u'3124oirjrg;klhbas', 
       u';3rhfgfbnvsad3r', 
       pd.to_datetime('20140505'), 
       u'1234irtjurgbfas', 
       u'12;rhfd;hb;oasere', 
       u'124urgfdnv.,sadfg', 
       u'1rfnhsdjk.dhafgsrdew', 
       u'safeklrjh2nerfgsd.' 
       ] for _ in range(20000)] 

df = pd.DataFrame(data,columns=header) 
f = df['B'].values 
''' 

print(timeit.timeit("index = d == u'ASDASD123ASADKHX'", setup=setup4,number=1000)) 
print(timeit.timeit("index = e == u'ASDASD123ASADKHX'", setup=setup5,number=1000)) 
print(timeit.timeit("index = f == u'ASDASD123ASADKHX'", setup=setup6,number=1000)) 

结果如下:

print(timeit.timeit("index = d == u'ASDASD123ASADKHX'", setup=setup4,number=1000)) 
0.808505267014 

print(timeit.timeit("index = e == u'ASDASD123ASADKHX'", setup=setup5,number=1000)) 

3.06733738226 

print(timeit.timeit("index = f == u'ASDASD123ASADKHX'", setup=setup6,number=1000)) 
1.64207848896 

我的问题在这里:为什么是纯numpy的阵列上的表现好多了?我如何使用从熊猫表中提取的数据实现相同的性能?

非常感谢。

+1

我相信,大熊猫虽然用途它下面的numpy数组做更多的dtype检查和对齐,所以更慢:http://stackoverflow.com/questions/19834075/pandas-much-slower-than-numpy – EdChum

+0

好吧,但在所有3例,我运行在numpy数组上进行。唯一的区别是对于第一种情况,数组本身被构造为一个numpy数组,而在后两种情况下,数组是使用“值”从熊猫数据框中提取的。 – Felix

+0

您的第二个设置是排序并返回数据帧的副本,第三个设置不会执行此操作,但似乎在构建数据帧时会有一些开销,然后将数据作为numpy数组返回。我不知道熊猫的全部内部工作原理来解释更多的内容,但只需创建数据框就可以了,这样就可以了解通过'.values将数据排序和访问数据作为一个numpy数组的成本。 ' – EdChum

回答

0

DataFrame中的每个字符串都是一个对象,您从df['B'].values得到的是对象数组。但是,当您通过np.array()创建字符串数组时,它会返回一个数组,每个字符串使用相同的字节数。

下面是一个示例,aS10 dtype的数组,b是一个带有对象dtype的数组。

import numpy as np 
import random 
import string 
words = ["".join(random.choice(string.ascii_uppercase) for _ in range(10)) for _ in range(10000)] 
a = np.array(words) 
b = a.astype("O") 
%timeit a == "123" 
%timeit b == "123" 

输出:

10000 loops, best of 3: 122 µs per loop 
10000 loops, best of 3: 164 µs per loop 
+0

是的,我已经意识到这一点。因此,numpy数组是'dtype = np.object'。它也不能解释熊猫排序和未排序数组之间的差异(情况2和3)。 – Felix

0

我测试你的代码在IPython中,并得到了几乎所有相同的性能未排序的数据帧变种分开:

In [85]: 

import numpy as np, string, random 

d =  np.array([ 
      u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)) 
      for _ in range(20000) 
      ],dtype=np.object) 

header = [ 
        u'A', 
        u'B', 
        u'C', 
        u'D', 
        u'E', 
        u'F', 
        u'G', 
        u'H', 
        u'I', 
        u'J', 
        u'K', 
        u'L', 
        u'M', 
        u'N' 
        ] 


data =  [[pd.to_datetime('20140505'), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16)), 
       u'sfgweorfjdfl', 
       u'dsiofqjwel;dmfv', 
       u'e3ruiwefjvgoiubg', 
       u'3124oirjrg;klhbas', 
       u';3rhfgfbnvsad3r', 
       pd.to_datetime('20140505'), 
       u'1234irtjurgbfas', 
       u'12;rhfd;hb;oasere', 
       u'124urgfdnv.,sadfg', 
       u'1rfnhsdjk.dhafgsrdew', 
       u'safeklrjh2nerfgsd.' 
       ] for _ in range(20000)] 

df = pd.DataFrame(data,columns=header) 
df_sorted = df.sort(['B','C']) 
e = df_sorted['B'].values 
f = df['B'].values 
%timeit index = d == u'ASDASD123ASADKHX' 
%timeit index = e == u'ASDASD123ASADKHX' 
%timeit index = f == u'ASDASD123ASADKHX' 
1000 loops, best of 3: 536 µs per loop 
1000 loops, best of 3: 568 µs per loop 
1000 loops, best of 3: 538 µs per loop 
+0

这很有趣。如果您完全按照上面所述使用代码,会发生什么情况?我添加了'import timeit',所以它现在应该是一个自洽的python文件。 – Felix

+0

我跑你的代码,并得到如下:'2.11338382930262 1.2496556612022687 0.6459569358412409'是相反你观察到的东西,然后我又跑,并得到'0.5910921373142628 1.7401513672084548 0.5598322421719786'如果你重新运行你的代码你得到随机的结果? – EdChum

+0

只是跑了一遍,得到了'0.5474049547920004 0.6093832207843661 0.5601899379689712',这里对我来说似乎不是什么谜 – EdChum