优化Python代码 - 由于pandas.core.series.Series .__ getitem__导致的开销

时间:2014-09-23 16:09:05

标签: python optimization pandas

我有pandas数据对象 - data - 存储为系列丛书。第一个系列在ID1上编号,第二个在ID2上编号。

ID1      ID2
1        10259           0.063979
         14166           0.120145
         14167           0.177417
         14244           0.277926
         14245           0.436048
         15021           0.624367
         15260           0.770925
         15433           0.918439
         15763           1.000000
...
1453     812690          0.752274
         813000          0.755041
         813209          0.756425
         814045          0.778434
         814474          0.910647
         814475          1.000000
Length: 19726, dtype: float64

我有一个函数,它使用来自此对象的值进行进一步的数据处理。这是功能:

#Function
def getData(ID1, randomDraw): 
    dataID2 = data[ID1]
    value = dataID2.index[np.searchsorted(dataID2, randomDraw, side='left').iloc[0]]
    return value

我使用np.vectorizeDataFrame - dataFrame上应用此功能 - 该行有大约2200万行。

dataFrame['ID2'] = np.vectorize(getData)(dataFrame['ID1'], dataFrame['RAND'])

其中ID1RAND是包含正在输入函数的值的列。

代码大约需要6个小时来处理所有内容。 Java中的类似实现只需要大约6分钟即可获得2200万行数据。

在我的程序上运行分析器时,我发现最昂贵的调用是data的索引,而第二个最昂贵的调用是searchsorted

Function Name: pandas.core.series.Series.__getitem__
Elapsed inclusive time percentage: 54.44

Function Name: numpy.core.fromnumeric.searchsorted  
Elapsed inclusive time percentage: 25.49    

使用data.loc[ID1]获取数据会使程序更慢。我怎样才能让它更快?据我所知Python无法达到与Java相同的效率,但与6分钟相比,6小时似乎没有太大差别。也许我应该使用不同的数据结构/功能?我正在使用Python 2.7PTVS IDE。

添加最低工作示例:

import numpy as np
import pandas as pd

np.random.seed = 0

#Creating a dummy data object - Series within Series
alt = pd.Series(np.array([ 0.25, 0.50,  0.75,  1.00]), index=np.arange(1,5))
data = pd.Series([alt]*1500, index=np.arange(1,1501))

#Creating dataFrame - 
nRows = 200000
d = {'ID1': np.random.randint(1500, size=nRows) + 1
     ,'RAND': np.random.uniform(low=0.0, high=1.0, size=nRows)}
dataFrame = pd.DataFrame(d)

#Function
def getData(ID1, randomDraw): 
    dataID2 = data[ID1]
    value = dataID2.index[np.searchsorted(dataID2, randomDraw, side='left').iloc[0]]
    return value

dataFrame['ID2'] = np.vectorize(getData)(dataFrame['ID1'], dataFrame['RAND'])

1 个答案:

答案 0 :(得分:1)

使用此代码可以获得更好的性能:

>>> def getData(ts):
...     dataID2 = data[ts.name]
...     i = np.searchsorted(dataID2.values, ts.values, side='left')
...     return dataID2.index[i]
... 
>>> dataFrame['ID2'] = dataFrame.groupby('ID1')['RAND'].transform(getData)