2016-07-09 16 views
2

Ich versuche eine Methode zu finden, um den n-ten Wert zu finden und den Spaltennamen zurückzugeben. So zum Beispiel eines Datenrahmen gegeben:Ermitteln der n-ten Spalten-IDs pro Zeile eines Datenrahmens - Python/Pandas

df = pd.DataFrame(np.random.randn(5, 4), columns = list('ABCD')) 

# Return column name of "MAX" value, compared to other columns in any particular row. 

df['MAX1_NAMES'] = df.idxmax(axis=1) 

print df 

      A   B   C   D MAX1_NAMES 
0 -0.728424 -0.764682 -1.506795 0.722246   D 
1 1.305500 -1.191558 0.068829 -1.244659   A 
2 -0.175834 -0.140273 1.117114 0.817358   C 
3 -0.255825 -1.534035 -0.591206 -0.352594   A 
4 -2.408806 -1.925055 -1.797020 2.381936   D 

Dies würde den höchsten Wert in den Zeilen finden und die Spaltennamen zurück, wo sie sich ereignen. Aber ich brauche den Fall, dass ich den besonderen Rang des gewünschten Wertes wählen kann, und hoffentlich einen Datenrahmen wie folgt erhalten:

  A   B   C   D MAX1_NAMES MAX2_NAMES 
0 -0.728424 -0.764682 -1.506795 0.722246   D   A 
1 1.305500 -1.191558 0.068829 -1.244659   A   C 
2 -0.175834 -0.140273 1.117114 0.817358   C   D 
3 -0.255825 -1.534035 -0.591206 -0.352594   A   D 
4 -2.408806 -1.925055 -1.797020 2.381936   D   C 

Wo MAX2_NAMES ist der zweitgrößte Wert in der Zeile.

Danke.

Antwort

3

Sie suchen das Ranking für einen bestimmten Rang n nur auszuführen, so möchte ich um np.argpartition vorzuschlagen, die Indizes nur für die höchsten n-eingestuften Einträge in jeder Reihe sortieren würde, anstatt alle Elemente zu sortieren. Dies zielt auf eine verbesserte Leistung ab. Die Leistungsvorteile werden in Antworten auf A fast way to find the largest N elements in an numpy array ausführlich besprochen und hoffentlich werden wir auch hier von den Vorteilen profitieren.

So wird in einem Funktionsformat, hätten wir -

def rank_df(df,rank): 
    coln = 'MAX' + str(rank) + '_NAMES' 
    sortID = np.argpartition(-df[['A','B','C','D']].values,rank,axis=1)[:,rank-1] 
    df[coln] = df.columns[sortID] 

Probelauf -

In [84]: df 
Out[84]: 
      A   B   C   D 
0 -0.124851 0.152432 1.436602 -0.391178 
1 0.371932 1.732399 0.340876 -1.340609 
2 -1.218608 0.444246 0.169968 -1.437259 
3 -0.828132 0.821613 -0.556643 -0.407703 
4 -0.390477 0.048824 -2.087323 1.597030 

In [85]: rank_df(df,1) 

In [86]: rank_df(df,2) 

In [87]: df 
Out[87]: 
      A   B   C   D MAX1_NAMES MAX2_NAMES 
0 -0.124851 0.152432 1.436602 -0.391178   C   B 
1 0.371932 1.732399 0.340876 -1.340609   B   A 
2 -1.218608 0.444246 0.169968 -1.437259   B   C 
3 -0.828132 0.821613 -0.556643 -0.407703   B   D 
4 -0.390477 0.048824 -2.087323 1.597030   D   B 

Runtime Test

Ich Timing np.argpartition basierten Ansatz, wie oben aufgeführt in Dieser Beitrag und np.argsort basiert wie in der anderen Lösung von @Psidom auf einem anständigen Datenrahmen aufgeführt.

In [92]: df = pd.DataFrame(np.random.randn(10000, 4), columns = list('ABCD')) 

In [93]: %timeit rank_df(df,2) 
100 loops, best of 3: 2.36 ms per loop 

In [94]: df = pd.DataFrame(np.random.randn(10000, 4), columns = list('ABCD')) 

In [95]: %timeit df['MAX2_NAMES'] = df.iloc[:,:4].apply(lambda r: r.index[r.argsort()[::-1][1]], axis = 1) 
1 loops, best of 3: 3.32 s per loop 
+0

Sehr schön, ich war mehr bestrebt, jede Lösung unabhängig von der Geschwindigkeit zu bekommen, aber die numpige Sortierleistung Tipp wird sich als nützlich erweisen. – ajsp

4

Sie können eine argsort() pro Zeile in umgekehrter Reihenfolge Index übernehmen und das eine an der zweiten Position abholen:

df['MAX2_NAMES'] = df.iloc[:,:4].apply(lambda r: r.index[r.argsort()[::-1][1]], axis = 1) 

df 
#   A   B   C   D MAX1_NAMES MAX2_NAMES 
#0 -0.728424 -0.764682 -1.506795 0.722246    D   A 
#1 1.305500 -1.191558 0.068829 -1.244659   A   C 
#2 -0.175834 -0.140273 1.117114 0.817358    C   D 
#3 -0.255825 -1.534035 -0.591206 -0.352594   A   D 
#4 -2.408806 -1.925055 -1.797020 2.381936    D   C 
+0

Ausgezeichnet, Prost. – ajsp

Verwandte Themen