2017-03-20 2 views
2

私は列のペアに基づいてデータを並べ替える方法を見つけようとしています。私の現在のコードは非常に近いですが、最終的にJoeをトップに移動したいと考えています - と彼の合計が最大であるので、すべての行を一緒ににしてください。パンダ:個々の行の代わりに行のグループを並べ替える

アップデート1:'Total'は常に最大ではありません - それは'Yes'指定を使用する必要がある - (ドル金額の一部が負になることができます)。

アップデート2:私のコードと所望の出力は、'Total'行が(これは負ドルに)グループ内の別'Dollar'未満とすることができる場所を示すように更新されているが、それはまだその最初の行であるべきである'Dude'グループ。

私のコードではグループ化は正しく行われますが、最終的には'Dude'グループはソートされません。

import pandas as pd 

headers = ['Date','Dude','Dollar', 'Total'] 
df = pd.DataFrame({ 
    'Dude':['Bob','Bob','Sam','Bob','Joe','Joe','Joe','Bob','Sam','Sam','Joe','Sam'], 
    'Dollar':[4,1,-2,1,5,12,3,2,7,1,4,8], 
    'Total':['Yes','No','No','No','No','Yes','No','No','Yes','No','No','No'], 
    'Date':['1/1/2016','1/1/2016','1/1/2016','3/1/2016','3/1/2016','1/1/2016','1/1/2016','5/1/2016','1/1/2016','3/1/2016','5/1/2016','5/1/2016'] 
    }, columns = headers) 

df['Date'] = pd.to_datetime(df['Date']) 

df.sort_values(by = ['Dude','Total','Date'], ascending = [True, False, True], inplace = True) 

出力:

  Date Dude Dollar Total 
0 2016-01-01 Bob  4 Yes 
1 2016-01-01 Bob  1 No 
3 2016-03-01 Bob  1 No 
7 2016-05-01 Bob  2 No 
5 2016-01-01 Joe  12 Yes 
6 2016-01-01 Joe  3 No 
4 2016-03-01 Joe  5 No 
10 2016-05-01 Joe  4 No 
8 2016-01-01 Sam  7 Yes 
2 2016-01-01 Sam  -2 No 
9 2016-03-01 Sam  1 No 
11 2016-05-01 Sam  8 No 

所望の出力:

  Date Dude Dollar Total 
5 2016-01-01 Joe  12 Yes 
6 2016-01-01 Joe  3 No 
4 2016-03-01 Joe  5 No 
10 2016-05-01 Joe  4 No 
8 2016-01-01 Sam  7 Yes 
2 2016-01-01 Sam  -2 No 
9 2016-03-01 Sam  1 No 
11 2016-05-01 Sam  8 No 
0 2016-01-01 Bob  4 Yes 
1 2016-01-01 Bob  1 No 
3 2016-03-01 Bob  1 No 
7 2016-05-01 Bob  2 No 

答えて

2

私のソリューションは...それはまず、すべて「はい」行を検索し、元のデータフレームにそれらをマージして、それらの上で最初にソートします。

import pandas as pd 

headers = ['Date','Dude','Dollar', 'Total'] 
df = pd.DataFrame({ 
    'Dude':['Bob','Bob','Sam','Bob','Joe','Joe','Joe','Bob','Sam','Sam','Joe','Sam'], 
    'Dollar':[4,1,-2,1,5,12,3,2,7,1,4,8], 
    'Total':['Yes','No','No','No','No','Yes','No','No','Yes','No','No','No'], 
    'Date':['1/1/2016','1/1/2016','1/1/2016','3/1/2016','3/1/2016','1/1/2016','1/1/2016','5/1/2016','1/1/2016','3/1/2016','5/1/2016','5/1/2016'] 
    }, columns = headers) 

df['Date'] = pd.to_datetime(df['Date']) 

# Just the Total = Yes row for each dude, with dollar renamed to total_dollar 
totals = df.loc[df['Total'] == 'Yes', ['Dude', 'Dollar']] 
totals.columns = ['Dude', 'Total_Dollar'] 

# Merge back on dude, sort by total dollars before sorting by everything else 
df = df.merge(totals, on='Dude').sort_values(by = ['Total_Dollar', 'Dude', 'Total', 'Date'], ascending = [False, True, False, True]) 
del df['Total_Dollar'] 

出力:

  Date Dude Dollar Total 
9 2016-01-01 Joe  12 Yes 
10 2016-01-01 Joe  3 No 
8 2016-03-01 Joe  5 No 
11 2016-05-01 Joe  4 No 
5 2016-01-01 Sam  7 Yes 
4 2016-01-01 Sam  -2 No 
6 2016-03-01 Sam  1 No 
7 2016-05-01 Sam  8 No 
0 2016-01-01 Bob  4 Yes 
1 2016-01-01 Bob  1 No 
2 2016-03-01 Bob  1 No 
3 2016-05-01 Bob  2 No 
+0

こんにちはIgor - ありがとう、しかし、私はデータのいずれかを変更したくない、単純にそれを並べ替える。 – pshep123

+0

元のデータに戻しました...例を説明のために変更しました。それとも、それは悪いことですか? – Igor

+0

私はあなたのアイデアが 'merge' +1を使用するのが好きです。 df.merge(totals).sort_values(['Total_Dollar'、 'Dude'、 'Total'、 'Date']、昇順= [0,1,0,1])。drop( 'Total_Dollar '、1) ' – MaxU

2

UPDATE:

In [162]: m = df.loc[df.Total=='Yes'].set_index('Dude')['Dollar'] 

In [163]: m 
Out[163]: 
Dude 
Bob  4 
Joe 12 
Sam  7 
Name: Dollar, dtype: int64 

In [164]: df.assign(x=df.Dude.map(m)) \ 
    ...: .sort_values(['x','Dude','Total','Date'], ascending=[0,1,0,1]) \ 
    ...: .drop('x', 1) 
Out[164]: 
     Date Dude Dollar Total 
5 2016-01-01 Joe  12 Yes 
6 2016-01-01 Joe  3 No 
4 2016-03-01 Joe  5 No 
10 2016-05-01 Joe  4 No 
8 2016-01-01 Sam  7 Yes 
2 2016-01-01 Sam  -2 No 
9 2016-03-01 Sam  1 No 
11 2016-05-01 Sam  8 No 
0 2016-01-01 Bob  4 Yes 
1 2016-01-01 Bob  1 No 
3 2016-03-01 Bob  1 No 
7 2016-05-01 Bob  2 No 

旧答え:

In [96]: df.assign(x=df.groupby('Dude').Dollar.transform('max')) \ 
    ...: .sort_values(['x','Dude','Dollar','Date'], ascending=[0,1,0,1]) \ 
    ...: .drop('x',1) 
Out[96]: 
     Date Dude Dollar Total 
5 2016-01-01 Joe  12 Yes 
4 2016-03-01 Joe  5 No 
10 2016-05-01 Joe  4 No 
6 2016-01-01 Joe  3 No 
8 2016-01-01 Sam  8 Yes 
11 2016-05-01 Sam  5 No 
2 2016-01-01 Sam  2 No 
9 2016-03-01 Sam  1 No 
0 2016-01-01 Bob  4 Yes 
7 2016-05-01 Bob  2 No 
1 2016-01-01 Bob  1 No 
3 2016-03-01 Bob  1 No 
+0

限りMaxUましたか?私はこのすべてを消化しようとしています... – pshep123

+0

@ pshep123、どういう意味ですか? – MaxU

+0

申し訳ありませんが、それは冗談でした。あなたはいつも素早く引き分けます - それは大変感謝しています!しかし私はそれを消化しようと冗談を言っていません。それを一歩一歩進んでください。 – pshep123

3

その後、ソートあなたが前に行ったように、ご希望の順序とカテゴリのデータタイプとして「おい」列を設定することができます。これにより、「Dude」列をカテゴリにすることの他の利点も得られます。

# Get the ordering of Dudes based on max dollar. 
dude_order = df[df['Total'] == 'Yes'].sort_values(by='Dollar', ascending=False) 

# Set dude as categorical with the previously determined ordering. 
df['Dude'] = df['Dude'].astype('category', categories=dude_order['Dude'], ordered=True) 

# Sort the dataframe. 
df = df.sort_values(by=['Dude', 'Total', 'Date'], ascending=[True, False, True]) 

結果の出力:

  Date Dude Dollar Total 
5 2016-01-01 Joe  12 Yes 
6 2016-01-01 Joe  3 No 
4 2016-03-01 Joe  5 No 
10 2016-05-01 Joe  4 No 
8 2016-01-01 Sam  7 Yes 
2 2016-01-01 Sam  -2 No 
9 2016-03-01 Sam  1 No 
11 2016-05-01 Sam  8 No 
0 2016-01-01 Bob  4 Yes 
1 2016-01-01 Bob  1 No 
3 2016-03-01 Bob  1 No 
7 2016-05-01 Bob  2 No 
+0

これはスマートです! – MaxU

+1

最後の2つ+1つ...私は裸であると感じる – piRSquared

+0

「Total」は常に最大になるわけではないので、「Yes」の指定を使用する必要があります。 – pshep123

関連する問題