Решения со стеком / unstack или pivot имеют предварительное условие, что все возможные точки должны существовать в столбцах «A» и «B». если в этих двух столбцах отсутствует точка, результат будет неверным. Например, удалив Index = 3 (V22) в исходных данных, получится результат:
In []: df.set_index(['A','B']).unstack().stack(dropna=False).reset_index()
Out[]:
A B Value
0 1 1 V11
1 1 3 V13
2 2 1 V21
3 2 3 V23
4 3 1 V31
5 3 3 V33
Более надежным решением является использование reindex () для принудительного получения результирующих строк с заранее определенными точками и порядком, поэтому не беспокойтесь о возможных пропущенных точках. i.e.:
In []: midx = pd.MultiIndex.from_product([[1,2,3],[1,2,3]],names=list('AB'))
In []: df.set_index(['A','B']).reindex(midx).reset_index()
Out[]:
A B Value
0 1 1 V11
1 1 2 NaN
2 1 3 V13
3 2 1 V21
4 2 2 NaN
5 2 3 V23
6 3 1 V31
7 3 2 NaN
8 3 3 V33