2016-10-05 11 views
0

私はpython 2.7を使用しています。次のように与えられたデータから:パンダ:与えられた列のユニークな行を取得しますが、他の列の条件によっては条件付きです。

data = pd.DataFrame({'id':['001','001','001','002','002','003','003','003','004','005'], 
        'status':['ground','unknown','air','ground','unknown','ground','unknown','unknown','unknown','ground'], 
        'value':[10,-5,12,20,-12,2,-4,-1,0,6]}) 

データは次のようになります。

id  status  value 
001 ground  10 
001 unknown  -5 
001 air   12 
002 ground  20 
002 unknown  -12 
003 ground  2 
003 unknown  -4 
003 unknown  -1 
004 unknown  0 
005 ground  6 

私は、次の基準に条件付きのユニークなIDを持っているデータフレームで出力を取得したいと思います:与えられたidには

'status': If 'air' does exist, pick 'air'. 
      If 'air' does not exist, pick 'ground'. 
      If both 'air' and 'ground' do not exist, pick 'unknown'. 

'value': Sum of values for each id 
'count': Count the number of rows for each id 

したがって、期待される出力は次のとおりです。

id  status  value  count 
001  air  17  3 
002 ground  8  2 
003 ground  -3  3 
004 unknown  0  1 
005 ground  6  1 

私はそれぞれの固有IDのループ行うことができますが、それは十分にエレガントではなく、計算がデータが大きくなる場合は特に、また高価です。私はより良いpythonicスタイルとより効率的な方法をこの出力を考え出すことを知ってもいいですか?前もって感謝します。

答えて

2

idにgroupbyを使用します。これは価値観や数には簡単ですが、ステータスにはやりにくいです。我々はpandas Seriesを取り、単一の属性を返す独自の関数を書く必要があります。

def group_status(x): 
    if (x=='air').any(): 
     y = 'air' 
    elif (x=='ground').any(): 
     y = 'ground' 
    else: 
     y = 'unknown' 
    return y 

data = data.groupby(by='id').agg({'value': ['sum', 'count'], 'status': [group_status]}) 
data.columns = ['status', 'value', 'count'] 

print(data) 

    status value count 
id   
001 air  17  3 
002 ground 8  2 
003 ground -3  3 
004 unknown 0  1 
005 ground 6  1 

は、ここでは、アイハンの非常にエレガントな答えで述べたように、空気、大地、未知の順序は、カテゴリに列の型を変更することなく維持されることを保証しています。

group_status()機能は、より高度なgroupby機能を組み込む必要がある場合は、基礎を成しています。

+1

カテゴリの列はアルファベット順に並べ替えられませんが、順序は '.astype'に渡されます。だから、それを「地面」、「空気」、「不明」に変更すると、地面が存在すれば最初の値になります。 – ayhan

+1

私はそれを知らなかった。確かに知っておくと便利です。私はあなたの例が注文されたように読んで、コードの最初の行を見落としました。私は私の答えを若干編集します。 – josh

2

一つのオプションカテゴリーにステータス列の種類を変更し、groupby.aggでそれに基づいてソートされます:

ここ
df['status'] = df['status'].astype('category', categories=['air', 'ground', 'unknown'], ordered=True) 

df.sort_values('status').groupby('id').agg({'status': 'first', 'value': ['sum', 'count']}) 
Out: 
     status value  
     first sum count 
id      
001  air 17  3 
002 ground  8  2 
003 ground -3  3 
004 unknown  0  1 
005 ground  6  1 

、値が'air''ground''unknown'順にソートされているので、'first'リターン正しい値。型を変更したくない場合は、air/ground/unknownを返す独自の関数を定義し、'first'の代わりにその関数を渡すことができます。

関連する問題