2017-05-06 5 views
0

Iは次のようパンダのデータフレームを有する場合:現在パンダ/複数列のDASKを計算百分率 - 列並列動作

raw_data = { 
     'subject_id': ['1', '2', '3', '4', '5'], 
     'name': ['A', 'B', 'C', 'D', 'E'], 
     'nationality': ['DE', 'AUT', 'US', 'US', 'US'], 
     'alotdifferent': ['x', 'y', 'z', 'x', 'a'], 
     'target': [0,0,0,1,1], 
     'age_group' : [1, 2, 1, 3, 1]} 
df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'name', 'nationality', 'alotdifferent','target','age_group']) 
df_a.nationality = df_a.nationality.astype('category') 
df_a.alotdifferent = df_a.alotdifferent.astype('category') 
df_a.name = df_a.name.astype('category') 

、私が使用:

FACTOR_FIELDS = df_a.select_dtypes(include=['category']).columns 
columnsToDrop = ['alotdifferent'] 
columnsToBias_keep = FACTOR_FIELDS[~FACTOR_FIELDS.isin(columnsToDrop)] 
target = 'target' 

def quotients_slow(df_a): 
    # parallelism = 8 
    # original = dd.from_pandas(df.copy()) 
    original = df_a.copy() 
    output_df = original 
    ratio_weights = {} 

    for colname in columnsToBias_keep.union(columnsToDrop): 
     # group only a single time 
     grouped = original.groupby([colname, target]).size() 
     # calculate first ratio 
     df = grouped/original[target].sum() 
     nameCol = "pre_" + colname 
     grouped_res = df.reset_index(name=nameCol) 
     grouped_res = grouped_res[grouped_res[target] == 1] 
     grouped_res = grouped_res.drop(target, 1) 
     # todo persist the result in dict for transformer 
     result_1 = grouped_res 

     # calculate second ratio 
     df = (grouped/grouped.groupby(level=0).sum()) 
     nameCol_2 = "pre2_" + colname 
     grouped = df.reset_index(name=nameCol_2) 
     grouped_res = grouped[grouped[target] == 1] 
     grouped_res = grouped_res.drop(target, 1) 
     result_2 = grouped_res 

     # persist the result in dict for transformer 
     # this is required to separate fit and transform stage (later on in a sklearn transformer) 
     ratio_weights[nameCol] = result_1 
     ratio_weights[nameCol_2] = result_2 

     # retrieve results 
     res_1 = ratio_weights['pre_' + colname] 
     res_2 = ratio_weights['pre2_' + colname] 
     # merge ratio_weight with original dataframe 
     output_df = pd.merge(output_df, res_1, on=colname, how='left') 
     output_df = pd.merge(output_df, res_2, on=colname, how='left') 
     output_df.loc[(output_df[nameCol].isnull()), nameCol] = 0 
     output_df.loc[(output_df[nameCol_2].isnull()), nameCol_2] = 0 

     if colname in columnsToDrop: 
      output_df = output_df.drop(colname, 1) 

    return output_df 


quotients_slow(df_a) 

の比を計算します2つの方法で各(カテゴリ)の列ごとにtarget:1にグループ化します。この操作を複数の列に対して実行したいので、私はすべてを反復します。しかし、この操作は非常に遅いです。 ここにサンプル:10 loops, best of 3: 37 ms per loop。私の実際のデータセットでは、500,000行と100個ほどの列がありますが、これは本当に時間がかかります。

daskまたはpandasでスピードアップ(列の並行性、簡単な並列化)はできませんか?プレーンなパンダでより効率的に実装する可能性はありますか?商を計算するためにデータを渡す回数を減らすことは可能ですか?

編集の列の上に並列処理を実現するために、forループでdask.delayedを使用しようとすると、私は私が取得するために計算を呼び出す必要があるよう、列上のグラフを構築する方法を見つけ出すことはできません

タプル。

delayed_res_name = delayed(compute_weights)(df_a, 'name') 
a,b,c,d = delayed_res_name.compute() 
ratio_weights = {} 
ratio_weights[c] = a 
ratio_weights[d] = b 
+0

たぶん、単一のパスは、ここでは、デモに似可能です:https://jcrist.github.io/dask-sklearn-part-3.html –

+0

「ターゲットのコルの割合あなたの計算はここでは比類のない種類の割合を導いています。例えば、 'name:A' /' target:0'コンボは、5回の観測のうちの1回で発生します。しかし、 '1回の出現 'を' target'の '1'の値の合計で割っています。あなたが 'name:A' /' target:0'という3つのエントリを持っていても 'target'の' 1'という値が2つしかないと想像してください。 'name:A' /' target:0'比は1.5、つまり150%になるでしょうか? –

+0

あなたは正しいかもしれませんが、私はこれについて考える必要がありますが、要点はそのような部門を並列化/効率的に実装したいということです。実際、 'target:0'は無関係です。私は 'target:1'に興味があるだけでなく、各列ごとにグループごとに' target:1/allRecords'の割合が異なっていることを指摘しました。多分、これはより良い処方です。 –

答えて

1

ここでは、Pandasを使用して最初の商のための合理的に速い解決策があります。 subject_idの割合を計算するのに興味がないと仮定します。私はまた、より多くのエッジケースをカバーするためにいくつかのデータをサンプルに追加しました。

まず、サンプルデータを生成します。

raw_data = { 
    'subject_id': ['1', '2', '3', '4', '5', '6','7'], 
    'name': ['A', 'B', 'C', 'D', 'E', 'A','A'], 
    'nationality': ['DE', 'AUT', 'US', 'US', 'US', 'DE','DE'], 
    'alotdifferent': ['x', 'y', 'z', 'x', 'a','x','z'], 
    'target': [0,0,0,1,1,0,1], 
    'age_group' : [1, 2, 1, 3, 1, 2,1]} 

df_a = pd.DataFrame(raw_data, columns = ['subject_id', 'name', 'nationality', 'alotdifferent','target','age_group']) 

今割合と測定速度を計算する:

def compute_prop(group): 
    return group.sum()/float(group.count()) 

def build_master(df): 
    master = df.copy() 
    fields = df.drop(['subject_id','target'],1).columns 

    for field in fields: 
     master = (pd.merge(master, df.groupby(field, as_index=False) 
            .agg({'target':compute_prop}) 
            .rename(columns={'target':'pre_{}'.format(field)}), 
          on=field) 
      ) 

    master.sort_values('subject_id') 
    return master 

%timeit master = build_master(df_a) 
10 loops, best of 3: 17.1 ms per loop 

出力:

subject_id name nationality alotdifferent target age_group pre_name \ 
0   1 A   DE    x  0   1 0.333333 
5   2 B   AUT    y  0   2 0.000000 
2   3 C   US    z  0   1 0.000000 
6   4 D   US    x  1   3 1.000000 
3   5 E   US    a  1   1 1.000000 
4   6 A   DE    x  0   2 0.333333 
1   7 A   DE    z  1   1 0.333333 

    pre_nationality pre_alotdifferent pre_age_group 
0   0.333333   0.333333   0.5 
5   0.000000   0.000000   0.0 
2   0.666667   0.500000   0.5 
6   0.666667   0.333333   1.0 
3   0.666667   1.000000   0.5 
4   0.333333   0.333333   0.0 
1   0.333333   0.500000   0.5 
+0

2つ目のケースを追加して/両方の集計を1回のパスで計算できますか? df =(grouped/grouped.groupby(level = 0).sum()) '' agg'に2番目の関数を渡すことは可能ですか? –

+0

しかし私は私の最初の解決策とは何が違うのか分かりません。そこでは、私はすでにすべてのフィールドをループし、データを集約しています。ステップを組み合わせるだけです。つまり、コードはすっきりしています。しかし、これによってパフォーマンスが向上する可能性はありますか?最終的には、ノートブックに記載されているように*重み*を格納するsklearnトランスフォーマーである必要があります。したがって、あなたが使用するマージとグループの組み合わせは、おそらく分離する必要があります。 –

関連する問題