2013-05-05 117 views
9

我經常需要過濾熊貓數據幀dfdf[df['col_name']=='string_value'],我想加快行選擇操作,有沒有快速的方法來做到這一點?如何通過字符串匹配加速熊貓行過濾?

例如,

In [1]: df = mul_df(3000,2000,3).reset_index() 

In [2]: timeit df[df['STK_ID']=='A0003'] 
1 loops, best of 3: 1.52 s per loop 

能1.52s可以縮短?

注:

mul_df()是函數來創建多級數據幀:

>>> mul_df(4,2,3) 
       COL000 COL001 COL002 
STK_ID RPT_Date       
A0000 B000  0.6399 0.0062 1.0022 
     B001  -0.2881 -2.0604 1.2481 
A0001 B000  0.7070 -0.9539 -0.5268 
     B001  0.8860 -0.5367 -2.4492 
A0002 B000  -2.4738 0.9529 -0.9789 
     B001  0.1392 -1.0931 -0.2077 
A0003 B000  -1.1377 0.5455 -0.2290 
     B001  1.0083 0.2746 -0.3934 

下面是()mul_df的代碼:

import itertools 
import numpy as np 
import pandas as pd 

def mul_df(level1_rownum, level2_rownum, col_num, data_ty='float32'): 
    ''' create multilevel dataframe, for example: mul_df(4,2,6)''' 

    index_name = ['STK_ID','RPT_Date'] 
    col_name = ['COL'+str(x).zfill(3) for x in range(col_num)] 

    first_level_dt = [['A'+str(x).zfill(4)]*level2_rownum for x in range(level1_rownum)] 
    first_level_dt = list(itertools.chain(*first_level_dt)) #flatten the list 
    second_level_dt = ['B'+str(x).zfill(3) for x in range(level2_rownum)]*level1_rownum 

    dt = pd.DataFrame(np.random.randn(level1_rownum*level2_rownum, col_num), columns=col_name, dtype = data_ty) 
    dt[index_name[0]] = first_level_dt 
    dt[index_name[1]] = second_level_dt 

    rst = dt.set_index(index_name, drop=True, inplace=False) 
    return rst 
+3

爲什麼不把它作爲一個索引(或者如果它不是一個索引,將其設置爲索引)?在索引上選擇要快得多('df.ix ['A0003']'):對我而言,194 us vs 646 ms。 – joris 2013-05-05 12:53:06

+0

這只是一個示例。很多時候,我們需要按列而不是索引來選擇;將其設置爲索引是一種選擇,但它引入了其他問題(已存在索引,更改數據結構等)(如果我們將數據庫視爲數據庫表,則非常常見:SELECT * FROM table_name WHERE col_name ='string_value ',不是嗎?) – bigbug 2013-05-05 13:05:56

回答

12

我一直希望將二叉搜索索引添加到DataFrame對象。您可以通過列排序,做這個自己的DIY方法:

In [11]: df = df.sort('STK_ID') # skip this if you're sure it's sorted 

In [12]: df['STK_ID'].searchsorted('A0003', 'left') 
Out[12]: 6000 

In [13]: df['STK_ID'].searchsorted('A0003', 'right') 
Out[13]: 8000 

In [14]: timeit df[6000:8000] 
10000 loops, best of 3: 134 µs per loop 

這是快,因爲它總是檢索看法,並不複製任何數據。

+0

直觀的解決方案,謝謝。希望它可以嵌入熊貓行選擇sytax中,例如「df [df ['col_name'] =='string_value']」 – bigbug 2013-05-07 01:56:16

+1

我希望在文檔的某處提到這一點,會節省很多時間... – user2808117 2014-01-23 15:38:46

+0

「排序」方法在Pandas 19.2及更高版本中已棄用。改爲使用'sort_values'方法。 – Jeff 2017-11-13 19:40:57

3

出人意料的是,與.values工作數組而不是Series對我來說要快得多:

>>> time df = mul_df(3000, 2000, 3).reset_index() 
CPU times: user 5.96 s, sys: 0.81 s, total: 6.78 s 
Wall time: 6.78 s 
>>> timeit df[df["STK_ID"] == "A0003"] 
1 loops, best of 3: 841 ms per loop 
>>> timeit df[df["STK_ID"].values == "A0003"] 
1 loops, best of 3: 210 ms per loop 
3

取決於你想要什麼以後與選擇做,如果你不得不做出這種多項選擇中,groupby功能還可以使事情更快(至少例子)。

即使你只需要選擇一個STRING_VALUE行,這是一個有點快(但是不要太多):

In [11]: %timeit df[df['STK_ID']=='A0003'] 
1 loops, best of 3: 626 ms per loop 

In [12]: %timeit df.groupby("STK_ID").get_group("A0003") 
1 loops, best of 3: 459 ms per loop 

但後續調用的GroupBy對象將是非常快的(例如,爲了選擇其他sting_values的行):

In [25]: grouped = df.groupby("STK_ID") 

In [26]: %timeit grouped.get_group("A0003") 
1 loops, best of 3: 333 us per loop