2016-07-07 2 views
3

Ich versuche einen Weg zu finden, eine kumulative Summe zu erstellen, die Verbindungen in Pandas berücksichtigt.Kumulatives Ranking von Werten in Pandas mit Bindungen

Lassen Sie uns hypothetische Daten von einem Track treffen, wo ich Leute, Rennen, Heats und Zeit habe.

Platzierung Jeder Person wird entsprechend den folgenden:

Für eine gegebene Rasse/Wärme Kombination:

  • Die Person Person mit der niedrigsten Zeit
  • Die Person mit der zweitniedrigsten Zeit zuerst platziert zweiter wurde

und so weiter ...

Dies wäre ziemlich einfach Code, aber für eine Sache ..

Wenn zwei Menschen die gleiche Zeit haben, erhalten sie beide den gleichen Ort und dann das nächste Mal größer als ihre Zeit wird diesen Wert +1 als Platzierung haben .

In der Tabelle unten für 100 Meter-Lauf, Wärme 1, Runner1 zuerst abgeschlossen, RUNNER2/RUNNER3 fertig zweiten und RUNNER3 Dritter (nächstes Mal nach RUNNER2/RUNNER3)

Also im Grunde ist die Logik wie folgt:

Wenn Rennen <> race.shift() oder Wärme <> heat.shift(), dann = 1 setzen

Wenn race = race.shift() und Wärme = heat.shift() und Zeit> time.shift dann place = place.shift() + 1

Wenn race = race.shift() und Wärme = heat.shift() und time> time.shift dann place = place.shift()

Der Teil, der mich verwirrt, ist, wie man mit den Bindungen umgeht. Sonst könnte ich etwas wie

df['Place']=np.where(
       (df['race']==df['race'].shift()) 
       & 
       (df['heat']==df['heat'].shift()), 
       df['Place'].shift()+1, 
       1) 

Vielen Dank!

Beispieldaten folgt:

Person,Race,Heat,Time 
RUNNER1,100 Yard Dash,1,9.87 
RUNNER2,100 Yard Dash,1,9.92 
RUNNER3,100 Yard Dash,1,9.92 
RUNNER4,100 Yard Dash,1,9.96 
RUNNER5,100 Yard Dash,1,9.97 
RUNNER6,100 Yard Dash,1,10.01 
RUNNER7,100 Yard Dash,2,9.88 
RUNNER8,100 Yard Dash,2,9.93 
RUNNER9,100 Yard Dash,2,9.93 
RUNNER10,100 Yard Dash,2,10.03 
RUNNER11,100 Yard Dash,2,10.26 
RUNNER7,200 Yard Dash,1,19.63 
RUNNER8,200 Yard Dash,1,19.67 
RUNNER9,200 Yard Dash,1,19.72 
RUNNER10,200 Yard Dash,1,19.72 
RUNNER11,200 Yard Dash,1,19.86 
RUNNER12,200 Yard Dash,1,19.92 

, was ich am Ende wollen, ist

Person,Race,Heat,Time,Place 
RUNNER1,100 Yard Dash,1,9.87,1 
RUNNER2,100 Yard Dash,1,9.92,2 
RUNNER3,100 Yard Dash,1,9.92,2 
RUNNER4,100 Yard Dash,1,9.96,3 
RUNNER5,100 Yard Dash,1,9.97,4 
RUNNER6,100 Yard Dash,1,10.01,5 
RUNNER7,100 Yard Dash,2,9.88,1 
RUNNER8,100 Yard Dash,2,9.93,2 
RUNNER9,100 Yard Dash,2,9.93,2 
RUNNER10,100 Yard Dash,2,10.03,3 
RUNNER11,100 Yard Dash,2,10.26,4 
RUNNER7,200 Yard Dash,1,19.63,1 
RUNNER8,200 Yard Dash,1,19.67,2 
RUNNER9,200 Yard Dash,1,19.72,3 
RUNNER10,200 Yard Dash,1,19.72,3 
RUNNER11,200 Yard Dash,1,19.86,4 
RUNNER12,200 Yard Dash,1,19.92,4 

[Bearbeiten] Nun noch einen Schritt weiter ..

vermuten lässt, dass Sobald ich einen Satz eindeutiger Werte belasse, werden die Werte beim nächsten Aufrufen des Sets auf 1 zurückgesetzt.

Also, zum Beispiel, - Beachten Sie, dass es geht auf "Wärme 1" und dann "Wärme 2" und zurück zu "Wärme 1" - Ich möchte nicht, dass die Rankings von der vorherigen "Wärme 1" fortsetzen, Ich möchte, dass sie zurückgesetzt werden.

Person,Race,Heat,Time,Place 
RUNNER1,100 Yard Dash,1,9.87,1 
RUNNER2,100 Yard Dash,1,9.92,2 
RUNNER3,100 Yard Dash,1,9.92,2 
RUNNER4,100 Yard Dash,2,9.96,1 
RUNNER5,100 Yard Dash,2,9.97,2 
RUNNER6,100 Yard Dash,2,10.01,3 
RUNNER7,100 Yard Dash,1,9.88,1 
RUNNER8,100 Yard Dash,1,9.93,2 
RUNNER9,100 Yard Dash,1,9.93,2 
+0

speichern Sie einfach die letzte Läuferzeit im Speicher (wie ein Puffer) und überprüfen Sie die aktuelle gegen ihn (wie Sie zwei Schwimmer mit etwas Genauigkeit e vergleichen würden). Wenn die Differenz unter e liegt, erhöhen Sie die Position nicht. –

+0

Wie würde ich das tun? Danke –

Antwort

7

könnten Sie verwenden:

grouped = df.groupby(['Race','Heat']) 
df['Place'] = grouped['Time'].transform(lambda x: pd.factorize(x, sort=True)[0]+1) 

import pandas as pd 
df = pd.DataFrame({'Heat': [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1], 'Person': ['RUNNER1', 'RUNNER2', 'RUNNER3', 'RUNNER4', 'RUNNER5', 'RUNNER6', 'RUNNER7', 'RUNNER8', 'RUNNER9', 'RUNNER10', 'RUNNER11', 'RUNNER7', 'RUNNER8', 'RUNNER9', 'RUNNER10', 'RUNNER11', 'RUNNER12'], 'Race': ['100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '200 Yard Dash', '200 Yard Dash', '200 Yard Dash', '200 Yard Dash', '200 Yard Dash', '200 Yard Dash'], 'Time': [9.8699999999999992, 9.9199999999999999, 9.9199999999999999, 9.9600000000000009, 9.9700000000000006, 10.01, 9.8800000000000008, 9.9299999999999997, 9.9299999999999997, 10.029999999999999, 10.26, 19.629999999999999, 19.670000000000002, 19.719999999999999, 19.719999999999999, 19.859999999999999, 19.920000000000002]}) 

grouped = df.groupby(['Race','Heat']) 
df['Place'] = grouped['Time'].transform(lambda x: pd.factorize(x, sort=True)[0]+1) 
df['Rank'] = grouped['Time'].rank(method='min') 
print(df) 

Ausbeuten

Heat Person   Race Time Place Rank 
0  1 RUNNER1 100 Yard Dash 9.87 1.0 1.0 
1  1 RUNNER2 100 Yard Dash 9.92 2.0 2.0 
2  1 RUNNER3 100 Yard Dash 9.92 2.0 2.0 
3  1 RUNNER4 100 Yard Dash 9.96 3.0 4.0 
4  1 RUNNER5 100 Yard Dash 9.97 4.0 5.0 
5  1 RUNNER6 100 Yard Dash 10.01 5.0 6.0 
6  2 RUNNER7 100 Yard Dash 9.88 1.0 1.0 
7  2 RUNNER8 100 Yard Dash 9.93 2.0 2.0 
8  2 RUNNER9 100 Yard Dash 9.93 2.0 2.0 
9  2 RUNNER10 100 Yard Dash 10.03 3.0 4.0 
10  2 RUNNER11 100 Yard Dash 10.26 4.0 5.0 
11  1 RUNNER7 200 Yard Dash 19.63 1.0 1.0 
12  1 RUNNER8 200 Yard Dash 19.67 2.0 2.0 
13  1 RUNNER9 200 Yard Dash 19.72 3.0 3.0 
14  1 RUNNER10 200 Yard Dash 19.72 3.0 3.0 
15  1 RUNNER11 200 Yard Dash 19.86 4.0 5.0 
16  1 RUNNER12 200 Yard Dash 19.92 5.0 6.0 

Beachten Sie, dass Pandas eine Groupby.rank hat getroffen hod, die viele gängige Rangformen berechnen kann - aber nicht die, die du beschrieben hast. Beachten Sie, wie zum Beispiel in Zeile 3 die Rank 4 nach einer Verbindung zwischen den zweiten und dritten Kufen, während die Place ist 3.


Bezüglich der Änderung: Verwenden

(df['Heat'] != df['Heat'].shift()).cumsum() 

um die Wärmen disambiguieren :

import pandas as pd 
df = pd.DataFrame({'Heat': [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1], 'Person': ['RUNNER1', 'RUNNER2', 'RUNNER3', 'RUNNER4', 'RUNNER5', 'RUNNER6', 'RUNNER7', 'RUNNER8', 'RUNNER9', 'RUNNER10', 'RUNNER11', 'RUNNER7', 'RUNNER8', 'RUNNER9', 'RUNNER10', 'RUNNER11', 'RUNNER12'], 'Race': ['100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash', '100 Yard Dash'], 'Time': [9.8699999999999992, 9.9199999999999999, 9.9199999999999999, 9.9600000000000009, 9.9700000000000006, 10.01, 9.8800000000000008, 9.9299999999999997, 9.9299999999999997, 10.029999999999999, 10.26, 19.629999999999999, 19.670000000000002, 19.719999999999999, 19.719999999999999, 19.859999999999999, 19.920000000000002]}) 

df['HeatGroup'] = (df['Heat'] != df['Heat'].shift()).cumsum() 
grouped = df.groupby(['Race','HeatGroup']) 
df['Place'] = grouped['Time'].transform(lambda x: pd.factorize(x, sort=True)[0]+1) 
df['Rank'] = grouped['Time'].rank(method='min') 
print(df) 

ergibt

Heat Person   Race Time HeatGroup Place Rank 
0  1 RUNNER1 100 Yard Dash 9.87   1 1.0 1.0 
1  1 RUNNER2 100 Yard Dash 9.92   1 2.0 2.0 
2  1 RUNNER3 100 Yard Dash 9.92   1 2.0 2.0 
3  1 RUNNER4 100 Yard Dash 9.96   1 3.0 4.0 
4  1 RUNNER5 100 Yard Dash 9.97   1 4.0 5.0 
5  1 RUNNER6 100 Yard Dash 10.01   1 5.0 6.0 
6  2 RUNNER7 100 Yard Dash 9.88   2 1.0 1.0 
7  2 RUNNER8 100 Yard Dash 9.93   2 2.0 2.0 
8  2 RUNNER9 100 Yard Dash 9.93   2 2.0 2.0 
9  2 RUNNER10 100 Yard Dash 10.03   2 3.0 4.0 
10  2 RUNNER11 100 Yard Dash 10.26   2 4.0 5.0 
11  1 RUNNER7 100 Yard Dash 19.63   3 1.0 1.0 
12  1 RUNNER8 100 Yard Dash 19.67   3 2.0 2.0 
13  1 RUNNER9 100 Yard Dash 19.72   3 3.0 3.0 
14  1 RUNNER10 100 Yard Dash 19.72   3 3.0 3.0 
15  1 RUNNER11 100 Yard Dash 19.86   3 4.0 5.0 
16  1 RUNNER12 100 Yard Dash 19.92   3 5.0 6.0 
+0

Große Antwort. Ich stelle mir vor, dass die Kontrolle der Genauigkeit der Vergleiche etwas expliziteres erfordern würde, wie das Ändern der Zahlen selbst durch math.ceil() oder was auch immer. –

+0

@ Ev.Kounis: Ja, man könnte etwas wie 'df [' Time '] = df [' Time ']. Round (2) 'verwenden, um alle Zeiten auf 2 Dezimalstellen zu runden, bevor' groupby/transform' oder 'groupby/rank'. – unutbu

+0

Danke! Ich fügte am Ende eine kleine Wendung hinzu ... es ist ein wenig verwirrend zu erklären, warum ich das tun muss, aber irgendwelche Ideen, wie ich dieses Ziel auch erreichen kann? –

Verwandte Themen