2016-08-14 4 views
3

ほとんどの場合、applyはデータフレーム上で操作プロセスを加速するようです。しかし、私がapplyを使用すると、スピードアップが見つからない。ここに私の例が来る、私は私が何をしたいのか2列なぜ適用されるのは、pandasデータフレームのfor-loopよりも速くないのですか?

>>>df 
index col1 col2 
1 10 20 
2 20 30 
3 30 40 

とのデータフレームを持っていることはcol1に機能R(x)を実装することにより、データフレームの各行の値を計算することで、結果がでた値によって分割されますcol2。たとえば、最初の行の結果はR(10)/20である必要があります。 は、だからここそれから私は_fapplyに呼び出す

def _f(input): 
    return R(input['col1'])/input['col2'] 

applyに呼び出される私の関数である:df.apply(_f, axis=1)

しかし、私はこのケースで見つけ、apply

のように、forループよりもはるかに遅いです
for i in list(df.index) 
    new_df.loc[i] = R(df.loc[i,'col1'])/df.loc[i,'col2'] 

誰もその理由を説明できますか?

+0

をパフォーマンスを圧迫する使用numba(JITコンパイラ)

  • 使用pandas.eval
  • C拡張を書くがあるかもしれませんデータの最初の行について面白い何か? applyは、最初の行で関数を2回呼び出して、返されるデータの形状を判別し、どのように組み合わされるのかをインテリジェントに把握します。これは仕様によるものであり、ドキュメントによるものです。 ここでのメモを参照してください。http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html se – AZhao

  • 答えて

    7

    .applyではありません。は、軸上の反復よりも一般的に高速です。私はフードの下では、このケースでは毎回関数呼び出しのオーバヘッドが発生することを除いて、軸上のループに過ぎないと考えています。

    source codeを見ると、指示された軸を反復して関数を適用し、個々の結果を一連の辞書として構築し、最終的にaを返す辞書のデータフレームコンストラクタを呼び出していることがわかります新しいデータフレーム:具体的に

    if axis == 0: 
         series_gen = (self._ixs(i, axis=1) 
             for i in range(len(self.columns))) 
         res_index = self.columns 
         res_columns = self.index 
        elif axis == 1: 
         res_index = self.index 
         res_columns = self.columns 
         values = self.values 
         series_gen = (Series.from_array(arr, index=res_columns, name=name, 
                 dtype=dtype) 
             for i, (arr, name) in enumerate(zip(values, 
                      res_index))) 
        else: # pragma : no cover 
         raise AssertionError('Axis must be 0 or 1, got %s' % str(axis)) 
    
        i = None 
        keys = [] 
        results = {} 
        if ignore_failures: 
         successes = [] 
         for i, v in enumerate(series_gen): 
          try: 
           results[i] = func(v) 
           keys.append(v.name) 
           successes.append(i) 
          except Exception: 
           pass 
         # so will work with MultiIndex 
         if len(successes) < len(res_index): 
          res_index = res_index.take(successes) 
        else: 
         try: 
          for i, v in enumerate(series_gen): 
           results[i] = func(v) 
           keys.append(v.name) 
         except Exception as e: 
          if hasattr(e, 'args'): 
           # make sure i is defined 
           if i is not None: 
            k = res_index[i] 
            e.args = e.args + ('occurred at index %s' % 
                 pprint_thing(k),) 
          raise 
    
        if len(results) > 0 and is_sequence(results[0]): 
         if not isinstance(results[0], Series): 
          index = res_columns 
         else: 
          index = None 
    
         result = self._constructor(data=results, index=index) 
         result.columns = res_index 
    
         if axis == 1: 
          result = result.T 
         result = result._convert(datetime=True, timedelta=True, copy=False) 
    
        else: 
    
         result = Series(results) 
         result.index = res_index 
    
        return result 
    

    series_genが要求された軸に基づいて構築された
    for i, v in enumerate(series_gen): 
           results[i] = func(v) 
           keys.append(v.name) 
    

    機能のパフォーマンスを向上させるには、hereのアドバイスに従ってください。

    基本的に、あなたのオプションは次のとおりです。

    1. は、大規模なデータフレームの外へ
    +1

    非常に印象的なソースコードの内訳です。 – AZhao

    関連する問題