2017-03-08 7 views
1

Stumped。複数の商品カテゴリ「タグ」を含む列を持つデータフレームを想像してみましょう。PANDAS単一の列内のリスト内の複数のグループを使用する厄介なグループ

import pandas as pd 

raw = { 
    'Products' : ['Rock On Leather Journal', 
        'Beats Earbuds In Ear Timer', 
        'Garmin 25mm Wristwatch' 
       ], 
    'Product Cost': [55,163,200], 
    'Product Category' : [['Music','Journals','Paper'], 
          ['Headphones','Music', 'Clocks'], 
          ['Watches','Clocks']] 
} 

data = pd.DataFrame(raw) 

各カテゴリ内でどのように多くの製品のカウントを取得するために、各カテゴリのコストを平均化するための最良の方法は何ですか?たとえば、

音楽:Count-?、Avg Price-?

通常、これはマップまたはグループバイを使用する簡単なプロセスです。しかし、カテゴリの列にリストが存在すると、厄介なものになります。

答えて

2

出典DF:いくつかの説明

In [25]: x.groupby('Product Category')['Product Cost'].agg(['size', 'mean']).reset_index() 
Out[25]: 
    Product Category size mean 
0   Clocks  2 181.5 
1  Headphones  1 163.0 
2   Journals  1 55.0 
3   Music  2 109.0 
4   Paper  1 55.0 
5   Watches  1 200.0 

In [22]: lst_col = 'Product Category' 
    ...: 
    ...: x = pd.DataFrame({ 
    ...:  col:np.repeat(data[col].values, data[lst_col].str.len()) 
    ...:  for col in data.columns.difference([lst_col]) 
    ...: }).assign(**{lst_col:np.concatenate(data[lst_col].values)})[data.columns.tolist()] 
    ...: 

In [23]: x 
Out[23]: 
    Product Category Product Cost     Products 
0   Music   55  Rock On Leather Journal 
1   Journals   55  Rock On Leather Journal 
2   Paper   55  Rock On Leather Journal 
3  Headphones   163 Beats Earbuds In Ear Timer 
4   Music   163 Beats Earbuds In Ear Timer 
5   Clocks   163 Beats Earbuds In Ear Timer 
6   Watches   200  Garmin 25mm Wristwatch 
7   Clocks   200  Garmin 25mm Wristwatch 

今、私たちがすることができ、容易"count of how many Products within each Category, and to average the costs for each category"

In [21]: data 
Out[21]: 
       Product Category Product Cost     Products 
0  [Music, Journals, Paper]   55  Rock On Leather Journal 
1 [Headphones, Music, Clocks]   163 Beats Earbuds In Ear Timer 
2   [Watches, Clocks]   200  Garmin 25mm Wristwatch 

まず、以下のDFに(平ら)に変換することができます:

各行のリスト要素の

数:

次のように我々は、すべての非リストの列を複製することができ、この情報を使用して
In [7]: data[lst_col].str.len() 
Out[7]: 
0 3 
1 3 
2 2 
Name: Product Category, dtype: int64 

In [3]: x = pd.DataFrame({ 
    ...:  col:np.repeat(data[col].values, data[lst_col].str.len()) 
    ...:  for col in data.columns.difference([lst_col]) 
    ...: }) 

In [4]: x 
Out[4]: 
    Product Cost     Products 
0   55  Rock On Leather Journal 
1   55  Rock On Leather Journal 
2   55  Rock On Leather Journal 
3   163 Beats Earbuds In Ear Timer 
4   163 Beats Earbuds In Ear Timer 
5   163 Beats Earbuds In Ear Timer 
6   200  Garmin 25mm Wristwatch 
7   200  Garmin 25mm Wristwatch 

今私たちが追加することができますがlist columnを平坦化:

In [8]: np.concatenate(data[lst_col].values) 
Out[8]: 
array(['Music', 'Journals', 'Paper', 'Headphones', 'Music', 'Clocks', 'Watches', 'Clocks'], 
     dtype='<U10') 

In [5]: x.assign(**{lst_col:np.concatenate(data[lst_col].values)}) 
Out[5]: 
    Product Cost     Products Product Category 
0   55  Rock On Leather Journal   Music 
1   55  Rock On Leather Journal   Journals 
2   55  Rock On Leather Journal   Paper 
3   163 Beats Earbuds In Ear Timer  Headphones 
4   163 Beats Earbuds In Ear Timer   Music 
5   163 Beats Earbuds In Ear Timer   Clocks 
6   200  Garmin 25mm Wristwatch   Watches 
7   200  Garmin 25mm Wristwatch   Clocks 

最後に、元の順序で列を選択するだけです。

In [6]: x.assign(**{lst_col:np.concatenate(data[lst_col].values)})[data.columns.tolist()] 
Out[6]: 
    Product Category Product Cost     Products 
0   Music   55  Rock On Leather Journal 
1   Journals   55  Rock On Leather Journal 
2   Paper   55  Rock On Leather Journal 
3  Headphones   163 Beats Earbuds In Ear Timer 
4   Music   163 Beats Earbuds In Ear Timer 
5   Clocks   163 Beats Earbuds In Ear Timer 
6   Watches   200  Garmin 25mm Wristwatch 
7   Clocks   200  Garmin 25mm Wristwatch 
+0

この作品は!しかし、私はまだあなたの.assign()を通して "for" colセクションから起こっていることを正確に理解しようとしています。それぞれのカテゴリに1つのカテゴリがあるように、行データを新しい行にコピーしています。次に、.assign()を使用して、他のすべての列を追加します。しかし、多分私は間違っています。これは私がこれまでに見たことのどれよりも複雑です(幻想的ではありますが)。この記事を見ている他の誰かのために少し説明してください。 – Adestin

+0

@Adestin、いくつかの説明を追加しました - 確認してください – MaxU

0

これはあなたのケースによって異なります。このサイズの場合は、要素ごとにブール値の列を作成することができます。あなたが製品の大きなプールを持っている場合

unique_products = set(chain(*data['Product Category'])) 
for product in unique_products: 
    data['product_{}.format(product) = data.Products.apply(lambda x: product in x) 

代わりに、先に行くと、必要に応じてdata.Product.apply(lamba x: product in x)を使用しています。 data.Product.isin([product_one, product_two])を使用して同様のチェックを実行することもできます。

合成カラムを作成したら、それをマージに使用できます。

関連する問題