Используйте numpy.argsort
для позиций по отсортированным значениям в строках с именами столбцов широковещания и фильтрации только 3 значений в строках:
df = df.set_index('user_id')
arr = df.columns.values[np.argsort(-df.values)[:, -3:]].tolist()
df1 = pd.DataFrame({'user_id': df.index, 'top_3_categories':arr})
print (df1)
user_id top_3_categories
0 1 [cat_3, cat_4, cat_1]
1 2 [cat_5, cat_3, cat_6]
2 3 [cat_4, cat_1, cat_2]
3 4 [cat_1, cat_3, cat_2]
4 5 [cat_6, cat_4, cat_5]
Или:
arr = df.columns.values[np.argsort(-df.values)[:, :3]].tolist()
df1 = pd.DataFrame({'user_id': df.index, 'top_3_categories':arr})
print (df1)
user_id top_3_categories
0 1 [cat_5, cat_6, cat_2]
1 2 [cat_1, cat_2, cat_4]
2 3 [cat_3, cat_6, cat_5]
3 4 [cat_5, cat_4, cat_6]
4 5 [cat_1, cat_2, cat_3]