Вы можете stack
перед вами pivot
, с некоторыми манипуляциями с данными:
s = df.set_index('letter').stack().reset_index(name='vals')
counter = s.groupby(['letter', 'level_1']).cumcount().add(1).astype(str)
(s.assign(flag=s.level_1 + '_' + counter)
.pivot_table(index='letter', values='vals', columns='flag', aggfunc='first'))
tmp color_1 color_2 color_3 number_1 number_2 number_3
letter
a green blue NaN 2 3 NaN
b red blue yellow 3 4 1
c red blue NaN 9 5 NaN