【问题标题】:search performance in python pandas vs. numpy arraypython pandas 与 numpy 数组中的搜索性能
【发布时间】:2014-08-02 12:23:39
【问题描述】:

我正在尝试在 pandas 列中搜索字符串。我已经读过,首先对列进行排序并在值上使用 searchsorted 搜索字符串应该是最快的。我发现这比在同一个 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 数组的性能要好得多?以及如何使用从 pandas 表中提取的数据来实现相同的性能?

非常感谢。

【问题讨论】:

  • 我相信 pandas 虽然在它下面使用了 numpy 数组,但它会进行更多的 dtype 检查和对齐,所以速度较慢:stackoverflow.com/questions/19834075/…
  • 好的,但是在所有 3 种情况下,我都在 numpy 数组上进行操作。唯一的区别是,对于第一种情况,数组是原生构造为 numpy 数组,而在后两种情况下,数组是使用“值”从 pandas 数据帧中提取的。
  • 您的第二个设置是排序并返回数据帧的副本,第三个设置不这样做,但构造数据帧然后将数据作为 numpy 数组返回似乎有一些开销。我不知道 pandas 的完整内部工作原理来解释更多,但只为数据框的创建计时会很有用,这样您就可以通过.values 了解将数据作为 numpy 数组进行排序和访问的成本
  • setup 中的所有内容都不计入timeit 的计时器中
  • 啊,好吧,我误解了你的准确时间分析,是的,这很奇怪,除了排序的数据帧与未排序的数据帧之外,它们之间应该没有显着差异

标签: python arrays search numpy pandas


【解决方案1】:

我在 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

【讨论】:

  • 这很有趣。如果您完全按照上面打印的方式使用代码会发生什么?我已经添加了import timeit,所以它现在应该是一个自洽的python文件。
  • 我运行了您的代码并得到以下结果:2.11338382930262 1.2496556612022687 0.6459569358412409 这与您观察到的相反,然后我再次运行它并得到0.5910921373142628 1.7401513672084548 0.5598322421719786 如果您重新运行您的代码,您会得到随机结果吗?
  • 再次运行它并得到0.5474049547920004 0.6093832207843661 0.5601899379689712,对我来说似乎没有什么神秘之处
  • 不,其实是很一致的。数字略有不同,但不会太大。
  • 我现在在家中使用我的 Linux PC 重复测试(我从这里复制了代码),结果相同:1.6、5.5 和 3.2 秒。我想知道你的测试和我的测试有什么区别。
【解决方案2】:

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

这里是一个例子,a 是一个具有 S10 dtype 的数组,b 是一个具有 object 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

【讨论】:

  • 是的,我已经意识到了。因此,numpy 数组是dtype=np.object。它也无法解释 pandas 中排序数组和未排序数组之间的区别(案例 2 和 3)。
猜你喜欢
  • 2018-04-14
  • 2012-10-22
  • 2019-01-19
  • 2015-07-16
  • 2016-04-22
  • 1970-01-01
  • 2021-06-03
  • 1970-01-01
  • 2018-11-19
相关资源
最近更新 更多