2014-04-30 55 views
1

我想知道我如何可以從具有開始和結束日期列的定義表中加入數據到我的事件表中,日期列在開始日期和enddate列。加入2個數據幀與開始日期和結束日期列

例:

Table A: Columns = [Date, Reading] 
Table B: Columns = [StartDate, EndDate, Amount] 

在SQL我將做到以下幾點:

Select Date, Reading, Amount From 
    A Join B on B.StartDate <= A.Date and B.EndDate > B.Date 

我試圖創建將在表B中篩選功能,然後使用應用像下面。

def find(d): 
    r = B[(B['StartDate'] <= d['Date']) & (B['EndDate'] > d['Date'])]['Amount']   
    if r.count()>0: 
     return r.index[0] 
    return 0 

A['Amount'] = A.apply(find, axis=1) 

這可以工作,但它非常慢,因爲我的事件表大小約爲20MB。

謝謝

+0

你能告訴一個小樣本表「A」和「B」? –

回答

0

在一個虛擬的數據和40K行中A和100行中B設置,下面 辦法是約1000倍比使用.apply與所提供的功能,更快。

假設乙看起來如下幀,

>>> B 
    StartDate EndDate Amount 
0 2000-01-01 2000-01-16  10 
1 2000-02-01 2000-02-16  20 
2 2000-03-01 2000-03-16  30 
3 2000-04-01 2000-04-16  40 
4 2000-05-01 2000-05-16  50 
     ...  ...  ... 

[100 rows x 3 columns] 

B可被翻譯,如下所示,與一個索引的TimeSeries該 含有B的範圍和相應的「金額定義每天' 值。

def make_series(start, end, amount): 
    idx = pd.date_range(start, end, freq='D', closed='left') 
    return pd.Series([amount] * len(idx), index=idx) 

def make_series2(s): 
    idx = pd.date_range(s['StartDate'], s['EndDate'], freq='D', closed='left') 
    return pd.Series([s['Amount']] * len(idx), index=idx) 

# for non-overlapping ranges 
>>> B2 = pd.concat([make_series(s, e, a) for _, s, e, a in B.itertuples()]) 

# for overlapping ranges 
>>> B2 = B.apply(make_series2, axis=1).bfill().T[0] 

>>> timeit B2 = pd.concat([make_series(s, e, a) for _, s, e, a in B.itertuples()]) 
100 loops, best of 3: 15.9 ms per loop 
>>> timeit B2 = B.apply(make_series2, axis=1).bfill().T[0] 
10 loops, best of 3: 54.9 ms per loop 

>>> B2 
2000-01-01 10 
2000-01-02 10 
... 
2008-04-14 1000 
2008-04-15 1000 
Length: 1500 

的最後一步是索引到B2使用A.Date

>>> A['Amount'] = B2[A.Date].fillna(0).values 

>>> timeit A['Amount'] = B2[A.Date].fillna(0).values 
1000 loops, best of 3: 1.91 ms per loop 

爲了便於比較,這裏的apply在同一幀使用timeit:

>>> timeit A.apply(find, axis=1) 
1 loops, best of 3: 26.3 s per loop 
相關問題