2017-01-28 11 views
5

質問:ベクトル化の道

概要:

私は特定の条件が見られている最初の日付を取得するためのベクトル化方法を探しています。条件は、dfDaysの価格が>の場合、dfWeeks.targetで指定された目標価格です。この条件は、ターゲットが設定された日以降にヒットする必要があります。

applyまたはそれに類する類似の時系列解析を、パンダでベクター化された方法で実行する方法はありますか?


データ:

freq='D'テストデータフレーム

np.random.seed(seed=1) 
rng = pd.date_range('1/1/2000', '2000-07-31',freq='D') 
weeks = np.random.uniform(low=1.03, high=3, size=(len(rng),)) 
ts2 = pd.Series(weeks 
       ,index=rng) 
dfDays = pd.DataFrame({'price':ts2}) 

今すぐ両方のDにインデックスを整列するために使用reindexリサンプリングfreq='1W-Mon'データフレーム

dfWeeks = dfDays.resample('1W-Mon').first() 
dfWeeks['target'] = (dfWeeks['price'] + .5).round(2) 

を作成して生成しますF:

dfWeeks = dfWeeks.reindex(dfDays.index) 

のでdfWeeksは、我々はdfWeeks

match = dfDays[dfDays.price >= dfWeeks.target.loc['2000-01-03']] 

から最初の目標に焦点を当てた場合は最初のマッチがである

dfWeeks.dropna().head() 

       price target 
2000-01-03 1.851533 2.35 
2000-01-10 1.625595 2.13 
2000-01-17 1.855813 2.36 
2000-01-24 2.130619 2.63 
2000-01-31 2.756487 3.26 

を使用する目標値を含むデータフレームであります過去があまり有効でないため、2000-01-12のエントリが最初の有効な一致です。

match.head() 

      price 
2000-01-02 2.449039 
2000-01-12 2.379882 
2000-01-14 2.759891 
2000-01-16 2.350821 
2000-01-21 2.607467 

enter image description here

applyやベクトル化の方法でdfWeekstargetエントリに対して同様のでこれを行う方法はありますか?

所望の出力:

   price target target_hit 
2000-01-03 1.851533 2.35 2000-01-12 
2000-01-10 1.625595 2.13 2000-01-12 
2000-01-17 1.855813 2.36 2000-01-21 
2000-01-24 2.130619 2.63 2000-01-25 
2000-01-31 2.756487 3.26 nan 
+0

私は論理を理解していません - どのようにして目的のデータセットの 'target'と' target_hit'カラムを得ましたか? – MaxU

+0

[XY問題]のように見えます。 stackexchange.com/a/66378/348814)、その特定のソリューションに集中しているときは、より良いものがあるかもしれません。だからこそ私はあなたが達成したいことを理解しようとしています – MaxU

+1

@マックス、私は達成しようとしていることの概要を投稿を更新しました。 – ade1e

答えて

5

pandas

def find_match(x): 
    match = dfDays.query('index > @x.name & price >= @x.target') 
    if not match.empty: 
     return match.index[0] 

dfWeeks.assign(target_hit=dfWeeks.apply(find_match, 1)) 

numpy

timing = dfWeeks.index.values[:, None] < dfDays.index.values 
target_hit = dfWeeks.target.values[:, None] <= dfDays.price.values 
matches = timing & target_hit 
got_match = matches.any(1) 
first = matches.argmax(1)[got_match] 

dfWeeks.loc[got_match, 'target_hit'] = dfDays.index.values[first] 
dfWeeks 

両方

   price target target_hit 
2000-01-03 1.851533 2.35 2000-01-12 
2000-01-10 1.625595 2.13 2000-01-12 
2000-01-17 1.855813 2.36 2000-01-21 
2000-01-24 2.130619 2.63 2000-01-25 
2000-01-31 2.756487 3.26  NaT 
2000-02-07 1.859582 2.36 2000-02-09 
2000-02-14 1.066028 1.57 2000-02-15 
2000-02-21 1.912350 2.41 2000-03-09 
2000-02-28 1.446907 1.95 2000-02-29 
2000-03-06 2.408524 2.91 2000-03-28 
2000-03-13 2.337675 2.84 2000-03-17 
2000-03-20 2.620561 3.12  NaT 
2000-03-27 2.770113 3.27  NaT 
2000-04-03 2.930735 3.43  NaT 
2000-04-10 1.834030 2.33 2000-04-12 
2000-04-17 2.068304 2.57 2000-04-19 
2000-04-24 2.391067 2.89 2000-05-11 
2000-05-01 2.518262 3.02  NaT 
2000-05-08 1.085764 1.59 2000-05-10 
2000-05-15 1.579992 2.08 2000-05-16 
2000-05-22 2.619997 3.12  NaT 
2000-05-29 1.269047 1.77 2000-05-31 
2000-06-05 1.171789 1.67 2000-06-06 
2000-06-12 2.175277 2.68 2000-06-20 
2000-06-19 1.338879 1.84 2000-06-20 
2000-06-26 2.977574 3.48  NaT 
2000-07-03 1.160680 1.66 2000-07-04 
2000-07-10 2.615366 3.12  NaT 
2000-07-17 2.478080 2.98  NaT 
2000-07-24 2.899562 3.40  NaT 
2000-07-31 2.220492 2.72  NaT 
+0

私はこの質問を数日間残してから、@ piRSquaredの応答がなければあなたの助けを求めます。あなたの助けを借りて幸運です! – ade1e

+1

'numpy'アプローチでも更新されました。私が助けることができてうれしい – piRSquared

+1

'numpy'のソリューションは、私の実際のデータに実装するのがとても簡単です。素晴らしいです! – ade1e

1

を得ちょうどクエリの時間を追加しました。 Numpyが本当にここで輝いています。

誰もが自分のコンピュータで同じものをテストして結果を確認することはできません。

import pandas as pd 
import numpy as np 

np.random.seed(seed=1) 
rng = pd.date_range('1/1/2000', '2000-07-31',freq='D') 
weeks = np.random.uniform(low=1.03, high=3, size=(len(rng),)) 
ts2 = pd.Series(weeks 
       ,index=rng) 
dfDays = pd.DataFrame({'price':ts2}) 
dfWeeks = dfDays.resample('1W-Mon').first() 
dfWeeks['target'] = (dfWeeks['price'] + .5).round(2) 

パンダ

%%timeit 
def find_match(x): 
    match = dfDays.query('index > @x.name & price >= @x.target') 
    if not match.empty: 
     return match.index[0] 

dfWeeks.assign(target_hit=dfWeeks.apply(find_match, 1)) 

10 loops, best of 3: 66 ms per loop

numpyの

%timeit 
timing = dfWeeks.index.values[:, None] < dfDays.index.values 
target_hit = dfWeeks.target.values[:, None] <= dfDays.price.values 
matches = timing & target_hit 
got_match = matches.any(1) 
first = matches.argmax(1)[got_match] 

dfWeeks.loc[got_match, 'target_hit'] = dfDays.index.values[first] 
dfWeeks 

は最も遅い実行が最速に比べ4.10倍の時間がかかりました。これは、 は中間結果がキャッシュされていることを意味します。 1000 loops, best of 3: 999 µs per loop