web-dev-qa-db-ja.com

pandas複数の関数によるdplyr集計/集計と同等のものは何ですか?

Rからpandasに移行する際に問題があります。ここで、dplyrパッケージは簡単にグループ化して複数の要約を実行できます。

既存のPython pandas複数の集計のコード:

_import pandas as pd
data = pd.DataFrame(
    {'col1':[1,1,1,1,1,2,2,2,2,2],
    'col2':[1,2,3,4,5,6,7,8,9,0],
     'col3':[-1,-2,-3,-4,-5,-6,-7,-8,-9,0]
    }
)
result = []
for k,v in data.groupby('col1'):
    result.append([k, max(v['col2']), min(v['col3'])])
print pd.DataFrame(result, columns=['col1', 'col2_agg', 'col3_agg'])
_

問題点:

  • 冗長すぎる
  • おそらく最適化され効率的です。 (私は_for-loop groupby_実装を_groupby.agg_に書き直しましたが、パフォーマンスの向上は非常に大きかったです)。

Rでは、同等のコードは次のようになります。

_data %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))
_

更新:@ayhanが私の質問を解決しました。コメントとしてではなく、ここに投稿する追加の質問があります。

Q2)groupby().summarize(newcolumn=max(col2 * col3))に相当するもの、つまり関数が2+列の複合関数である集約/要約とは何ですか?

31
B.Mr.W.

と同等

df %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))

df.groupby('col1').agg({'col2': 'max', 'col3': 'min'})

返す

      col2  col3
col1            
1        5    -5
2        9    -9

返されるオブジェクトは、col1というインデックスと、col2およびcol3という名前の列を持つpandas.DataFrameです。デフォルトでは、データをグループ化するときにpandasはグループ化列をインデックスとして設定し、効率的なアクセスと変更を行います。ただし、それが望ましくない場合は、col1を設定する2つの選択肢があります列として。

  • as_index=Falseを渡す:

    df.groupby('col1', as_index=False).agg({'col2': 'max', 'col3': 'min'})
    
  • reset_indexを呼び出します。

    df.groupby('col1').agg({'col2': 'max', 'col3': 'min'}).reset_index()
    

両方の収量

col1  col2  col3           
   1     5    -5
   2     9    -9

groupby.aggに複数の関数を渡すこともできます。

agg_df = df.groupby('col1').agg({'col2': ['max', 'min', 'std'], 
                                 'col3': ['size', 'std', 'mean', 'max']})

これはDataFrameも返しますが、現在は列のMultiIndexを持っています。

     col2               col3                   
      max min       std size       std mean max
col1                                           
1       5   1  1.581139    5  1.581139   -3  -1
2       9   0  3.535534    5  3.535534   -6   0

MultiIndexは、選択とグループ化に非常に便利です。ここではいくつかの例を示します。

agg_df['col2']  # select the second column
      max  min       std
col1                    
1       5    1  1.581139
2       9    0  3.535534

agg_df[('col2', 'max')]  # select the maximum of the second column
Out: 
col1
1    5
2    9
Name: (col2, max), dtype: int64

agg_df.xs('max', axis=1, level=1)  # select the maximum of all columns
Out: 
      col2  col3
col1            
1        5    -1
2        9     0

以前( version 0.20. の前)agg呼び出しの列の名前を変更するために辞書を使用することが可能でした。例えば

df.groupby('col1')['col2'].agg({'max_col2': 'max'})

2番目の列の最大値をmax_col2として返します。

      max_col2
col1          
1            5
2            9

ただし、名前変更メソッドを支持して廃止されました。

df.groupby('col1')['col2'].agg(['max']).rename(columns={'max': 'col2_max'})

      col2_max
col1          
1            5
2            9

上記で定義したagg_dfのようなDataFrameの場合、冗長になります。その場合、名前変更機能を使用してこれらのレベルをフラット化できます。

agg_df.columns = ['_'.join(col) for col in agg_df.columns]

      col2_max  col2_min  col2_std  col3_size  col3_std  col3_mean  col3_max
col1                                                                        
1            5         1  1.581139          5  1.581139         -3        -1
2            9         0  3.535534          5  3.535534         -6         0

groupby().summarize(newcolumn=max(col2 * col3))などの操作の場合、assignを使用して新しい列を最初に追加することにより、aggを使用できます。

df.assign(new_col=df.eval('col2 * col3')).groupby('col1').agg('max') 

      col2  col3  new_col
col1                     
1        5    -1       -1
2        9     0        0

これは、古い列と新しい列の最大値を返しますが、いつものようにそれをスライスできます。

df.assign(new_col=df.eval('col2 * col3')).groupby('col1')['new_col'].agg('max')

col1
1   -1
2    0
Name: new_col, dtype: int64

groupby.applyを使用すると、これは短くなります。

df.groupby('col1').apply(lambda x: (x.col2 * x.col3).max())

col1
1   -1
2    0
dtype: int64

ただし、groupby.applyはこれをカスタム関数として扱うため、ベクトル化されません。これまで、aggに渡した関数( 'min'、 'max'、 'min'、 'size'など)はベクトル化され、これらは最適化された関数のエイリアスです。 df.groupby('col1').agg('min')df.groupby('col1').agg(min)df.groupby('col1').agg(np.min)、またはdf.groupby('col1').min()に置き換えることができ、それらはすべて同じ関数を実行します。カスタム関数を使用する場合、同じ効率は見られません。

最後に、バージョン0.20では、最初にグループ化することなく、aggをDataFrameで直接使用できます。例を参照してください here

48
ayhan

Pandas documentation here: http://pandas.pydata.org/pandas-docs/stable/comparison_with_r.html#grouping-and -要約

R's dplyr

gdf <- group_by(df, col1)
summarise(gdf, avg=mean(col1, na.rm=TRUE))  

Pandas

gdf = df.groupby('col1')
df.groupby('col1').agg({'col1': 'mean'})
1
Puriney