2015-11-26 19 views
10

私はパンダのデータフレームを持っているが、次のように作成:高速代替

import pandas as pd 
def create(n): 
    df = pd.DataFrame({ 'gene':["foo", 
          "bar", 
          "qux", 
          "woz"], 
          'cell1':[433.96,735.62,483.42,10.33], 
          'cell2':[94.93,2214.38,97.93,1205.30], 
          'cell3':[1500,90,100,80]}) 
    df = df[["gene","cell1","cell2","cell3"]] 
    df = pd.concat([df]*n) 
    df = df.reset_index(drop=True) 
    return df 

をそれは次のようになります。

In [108]: create(1) 
Out[108]: 
    gene cell1 cell2 cell3 
0 foo 433.96 94.93 1500 
1 bar 735.62 2214.38  90 
2 qux 483.42 97.93 100 
3 woz 10.33 1205.30  80 

次にI特定のスコアを計算するために、各遺伝子の値を取る関数(行) を有する:

enter image description here

import numpy as np 
def sparseness(xvec): 
    n = len(xvec) 
    xvec_sum = np.sum(np.abs(xvec)) 
    xvecsq_sum = np.sum(np.square(xvec)) 

    denom = np.sqrt(n) - (xvec_sum/np.sqrt(xvecsq_sum)) 
    enum = np.sqrt(n) - 1 
    sparseness_x = denom/enum 

    return sparseness_x 

実際には、この機能を40K以上の行に適用する必要があります。

In [109]: df = create(10000) 
In [110]: express_df = df.ix[:,1:] 
In [111]: %timeit express_df.apply(sparseness, axis=1) 
1 loops, best of 3: 8.32 s per loop 

それを実装するためのより高速な代替は何ですか:そして現在、それは非常に遅い 使っパンダ「適用」を実行しますか?

答えて

12

より高速な方法は、関数のベクトル化バージョンを実装することです。これは2次元ndarrayで直接動作します。これはnumpyの多くの関数がaxisパラメータを使って制御された2次元ndarrayで動作できるので、非常に便利です。可能な実装:

def sparseness2(xs): 
    nr = np.sqrt(xs.shape[1]) 
    a = np.sum(np.abs(xs), axis=1) 
    b = np.sqrt(np.sum(np.square(xs), axis=1)) 
    sparseness = (nr - a/b)/(nr - 1) 
    return sparseness 

res_arr = sparseness2(express_df.values) 
res2 = pd.Series(res_arr, index=express_df.index) 

いくつかのテストは:

from pandas.util.testing import assert_series_equal 
res1 = express_df.apply(sparseness, axis=1) 
assert_series_equal(res1, res2) #OK 
%timeit sparseness2(express_df.values) 
# 1000 loops, best of 3: 655 µs per loop 
8

ここでは全体のデータフレーム全体で一度にこれらすべての操作を実行するnp.einsumを使用して1つのベクトル化のアプローチです。今、このnp.einsumは、このような乗算と加算の目的ではかなり効率的です。我々のケースでは、xvec_sumのケースとxvecsq_sumケースの2乗と合計の1次元に沿って合計を実行するためにそれを使用することができます。

def sparseness_vectorized(A): 
    nsqrt = np.sqrt(A.shape[1]) 
    B = np.einsum('ij->i',np.abs(A))/np.sqrt(np.einsum('ij,ij->i',A,A))  
    denom = nsqrt - B 
    enum = nsqrt - 1 
    return denom/enum 

ランタイムテスト - -

このセクションでは、問題になっているものを含む問題を解決するために、これまで記載されているすべてのアプローチを比較しimplmentationは次のようになります。

In [235]: df = create(1000) 
    ...: express_df = df.ix[:,1:] 
    ...: 

In [236]: %timeit express_df.apply(sparseness, axis=1) 
1 loops, best of 3: 1.36 s per loop 

In [237]: %timeit sparseness2(express_df.values) 
1000 loops, best of 3: 247 µs per loop 

In [238]: %timeit sparseness_vectorized(express_df.values) 
1000 loops, best of 3: 231 µs per loop 



In [239]: df = create(5000) 
    ...: express_df = df.ix[:,1:] 
    ...: 

In [240]: %timeit express_df.apply(sparseness, axis=1) 
1 loops, best of 3: 6.66 s per loop 

In [241]: %timeit sparseness2(express_df.values) 
1000 loops, best of 3: 1.14 ms per loop 

In [242]: %timeit sparseness_vectorized(express_df.values) 
1000 loops, best of 3: 1.06 ms per loop