You can use very fast numpy.argsort for change columns names by sorted values per row:
print (np.argsort(-df.values, axis=1))
[[4 3 2 1 0]
[4 3 1 2 0]
[3 0 1 2 4]
[3 4 1 2 0]
[1 2 4 3 0]
[0 2 1 3 4]
[0 3 2 1 4]
[1 3 0 4 2]
[1 4 0 3 2]
[0 2 4 3 1]]
print (df.columns[np.argsort(-df.values, axis=1)])
Index([['TWTR', 'TSLA', 'ATVI', 'GOOG', 'DB'],
['TWTR', 'TSLA', 'GOOG', 'ATVI', 'DB'],
['TSLA', 'DB', 'GOOG', 'ATVI', 'TWTR'],
['TSLA', 'TWTR', 'GOOG', 'ATVI', 'DB'],
['GOOG', 'ATVI', 'TWTR', 'TSLA', 'DB'],
['DB', 'ATVI', 'GOOG', 'TSLA', 'TWTR'],
['DB', 'TSLA', 'ATVI', 'GOOG', 'TWTR'],
['GOOG', 'TSLA', 'DB', 'TWTR', 'ATVI'],
['GOOG', 'TWTR', 'DB', 'TSLA', 'ATVI'],
['DB', 'ATVI', 'TWTR', 'TSLA', 'GOOG']],
dtype='object')
df = pd.DataFrame(df.columns[np.argsort(-df.values, axis=1)][:,[0,1,-1]], index=df.index)
df.columns = ['largest','second largest','smallest']
print (df)
largest second largest smallest
1.0 TWTR TSLA DB
2.0 TWTR TSLA DB
3.0 TSLA DB TWTR
4.0 TSLA TWTR DB
5.0 GOOG ATVI DB
6.0 DB ATVI TWTR
7.0 DB TSLA TWTR
8.0 GOOG TSLA ATVI
9.0 GOOG TWTR ATVI
10.0 DB ATVI GOOG
Another solutions (slowier) with apply and custom function where sort each row and get indexes:
def f(x):
x = x.sort_values()
return pd.Series([x.index[-1], x.index[-2], x.index[0]],
index=['largest','second largest','smallest'])
df = df.apply(f ,axis=1)
print (df)
largest second largest smallest
1.0 TWTR TSLA DB
2.0 TWTR TSLA DB
3.0 TSLA DB TWTR
4.0 TSLA TWTR DB
5.0 GOOG ATVI DB
6.0 DB ATVI TWTR
7.0 DB TSLA TWTR
8.0 GOOG TSLA ATVI
9.0 GOOG TWTR ATVI
10.0 DB ATVI GOOG
df = df.apply(lambda x: x.sort_values().index ,axis=1)
df = df.iloc[:, [-1,-2,0]]
df.columns = ['largest','second largest','smallest']
print (df)
largest second largest smallest
1.0 TWTR TSLA DB
2.0 TWTR TSLA DB
3.0 TSLA DB TWTR
4.0 TSLA TWTR DB
5.0 GOOG ATVI DB
6.0 DB ATVI TWTR
7.0 DB TSLA TWTR
8.0 GOOG TSLA ATVI
9.0 GOOG TWTR ATVI
10.0 DB ATVI GOOG
Timings:
#[10000 rows x 5 columns]
df = pd.concat([df]*1000).reset_index(drop=True)
In [357]: %timeit pd.DataFrame(df.columns[np.argsort(-df.values, axis=1)][:,[0,1,-1]], index=df.index, columns=['largest','second largest','smallest'])
1000 loops, best of 3: 974 µs per loop
In [358]: %timeit df.apply(f ,axis=1)
1 loop, best of 3: 3.91 s per loop
In [361]: %timeit df.apply(lambda x: x.sort_values().index ,axis=1).iloc[:, [-1,-2,0]]
1 loop, best of 3: 1.88 s per loop
In [362]: %timeit df.apply(lambda x: x.sort_values().index.to_series().iloc[0], axis=1)
1 loop, best of 3: 2.47 s per loop
In [363]: %timeit df.apply(lambda x: x.sort_values(ascending=False).index.to_series().iloc[0], axis=1)
1 loop, best of 3: 2.51 s per loop
In [364]: %timeit df.apply(lambda x: x.sort_values(ascending=False).index.to_series().iloc[1], axis=1)
1 loop, best of 3: 2.52 s per loop
In [365]: %timeit [df.T.sort_values(by=k).T.keys()[-1] for k in df.T.keys()]
1 loop, best of 3: 6.42 s per loop