2016-05-30 11 views
2

私は多くの行を持つデータフレームを持っています。私はこのようなカスタム関数から生成されたデータを使用して列を、追加しています:それは正常に動作しているPandas、列値の一意のサブセットに基づいて列を追加します

import numpy 

df['new_column'] = numpy.vectorize(fx)(df['col_a'], df['col_b']) 
# takes 180964.377 ms 

、私は何をしようとしていますが、それをスピードアップです。実際にはcol_acol_bというユニークな組み合わせの小さなグループしかありません。反復の多くは冗長です。私はたぶんpandasがそれだけでそれを理解するだろうと思っていたが、そうは思わない。冗長データがたくさんあるので、(私は何をしようとしていますが、大きなデータフレームを更新している、

df_unique['new_column'] = numpy.vectorize(fx)(df_unique['col_a'], df_unique['col_b']) 
# takes 14611.357 ms 

:私もこれを実行することによって可能スピードアップの自分自身を納得させ

print len(df.index) #prints 127255 
df_unique = df.copy().drop_duplicates(['col_a', 'col_b']) 
print len(df_unique.index) #prints 9834 

:これを考えてみましょうdf 127255行)、最小限の回数(9834回)のfx関数を実行するだけで済みます。これは、すべての重複行がcol_acol_bのためです。もちろん、col_acol_bの値が同じdfに複数の行がありますが、それはOKです。dfの他の列は異なるため、各行が一意になります。

私はdf_uniqueデータフレームをループにループの反復ノーマルを作成し、df上の条件付きのアップデートを行う前に、私は更新のこの種を行うより、「神託」きちんとした方法があったかお聞きしたかったのです。どうもありがとう。

** UPDATE **

私はこのような、上記のループのための簡単な作成

は、このforループを持つので
df = ... 
df_unique = df.copy().drop_duplicates(['col_a', 'col_b']) 
df_unique['new_column'] = np.vectorize(fx)(df_unique['col_a'], df_unique['col_b']) 
for index, row in df_unique.iterrows():   
    df.loc[(df['col_a'] == row['col_a']) & (df['col_b'] == row['col_b']),'new_column'] = row['new_column'] 
# takes 165971.890 

わずかな性能向上があるかもしれないではなく、ほとんど私は希望期待しています。

FYI

これはfx機能です。それはmysqlデータベースを照会します。

def fx(d): 
    exp_date = datetime.strptime(d.col_a, '%m/%d/%Y') 
    if exp_date.weekday() == 5: 
     exp_date -= timedelta(days=1) 

    p = pandas.read_sql("select stat from table where a = '%s' and b_date = '%s';" % (d.col_a,exp_date.strftime('%Y-%m-%d')),engine) 
    if len(p.index) == 0: 
     return None 
    else: 
     return p.iloc[0].close 
+0

「col_a」、「col_b」にはどのような種類のデータがありますか?彼らはすでに分類されていますか? – ptrj

+0

これらは両方とも文字列ですが、col_bは日付文字列です。かなり彼らはソートされていることを確認します。彼らはそうであるように見えます。 –

答えて

1

UPDATE:

tab = pd.read_sql('select stat,a,b_date from table', engine) 
df.merge(tab, left_on=[...], right_on=[...], how='left') 

OLD:あなたはtab DFにtableテーブルに属するあなたの3つの列['stat','a','b_date']を読むために管理することができるかどう

あなたはこのようにそれをマージすることができ答え:

あなたは事前に計算df_unique DFが元df DFと結合/マージすることができます

df['new_column'] = df.merge(df_unique, on=['col_a','col_b'], how='left')['new_column'] 
+0

とても素敵で速いです、ありがとうございます。私は 'df_unique' DFを更新するためにちょうど同じものと比較して、14960ミリ秒を測定しました。 –

+1

@jeffery_the_wind [受諾](http://meta.stackexchange.com/a/5235)が最も役立つ回答と考えてください。これはあなたの質問に答えられたことを示しています。 PSはあなたの 'fx'関数のコードを投稿することを提案していますので、コミュニティはそれを最適化しようとする可能性があります。 – MaxU

+0

私はすべてを通過する時間がありませんでしたが、この答えは最も単純で、スピードは本当に良いです。私はまた、numpy.vectorizeをdataframe.applyで置き換えると思っていますが、他の答えからも速度はやや向上しています。 –

1

MaxUの答えは、すでにあなたが望むものになることがあります。しかし、もう少し速いかもしれない別のアプローチを示します(私は測定しませんでした)。

私がいることを前提としています

  • dfが(ない場合は、あなたには、いくつかの一時を作成することが一意のインデックスを持っている(これは重要です)、すべて同じエントリが連続した行になるように

    1. df[['col_a', 'col_b']]がソートされていますユニークなインデックス)。

    私はdf_unique.indexdf.indexのサブセットであるという事実を使用します。

  • +0

    +1は 'apply'関数のために+1します。私はこれを見ていたが、議論として全体の行を取ることを認識していなかった。私はffillメソッドが完全に私のために働いていないと思う。私は関数が 'None'を返すとは言いませんでしたので、NaNのままにする必要のある行がいくつかありますが、ffillがそれらをすべて埋め込んでいると思います。 –

    +0

    @jeffery_the_windああ、そうだ。回避策は 'df_unique'中の' None''sをいくつかの中立値(例えば-1)で満たし、 'df'、' fillna'に代入し、-1をNone/np.nanに戻すことです。しかし、これとは別に、ソリューション全体はむしろハックです。速度を上げる必要がなければ、 'merge'を使うだけで安全です。 – ptrj

    関連する問題