Pivot some rows to new columns in DataFrame
groupby

When iterating over the values in a column, it is bad practice to hardcode the values (for pivot in [1, 2, 3]). A better way would have been for pivot in df["dof"].unique(), but the best way is with DataFrame.groupby 

To see what happens in the groupby, I try it first with an iteration, and printing the groups

for pivot, data in df.groupby("dof"):
    print(pivot)
    print(data)


Then I get to work with one of the data to mold it the way I want. In this case, we don't need the column dof any more, since we have it in the pivot variable, and we rename the columns using rename

for pivot, data in df.groupby("dof"):
    print(pivot)
    print(
        data.drop(columns="dof").rename(
            mapper={
                column_name: f"{column_name}{pivot}"
                for column_name in data.columns
            },
            axis=1,
        )
    )


Then we can use pd.concat to stitch it together

pd.concat(
    [
        data.drop(columns="dof").rename(
            mapper={
                column_name: f"{column_name}{pivot}"
                for column_name in data.columns
            },
            axis=1,
        )
        for pivot, data in df.groupby("dof")
    ],
    axis=1,
)


unstack

An alternative is with unstack:

From you description, dof is part of the index, so add it there. Then you can use DataFrame.unstack to bring it to the columns.


df2 = df.set_index("dof", append=True).unstack("dof")



        foo foo foo bar bar bar qux qux qux
dof     1   2   3   1   2   3   1   2   3
idxA idxB                                   
100 101 10  11  12  30  31  32  50  51  52
100 102 13  14  15  33  34  35  53  54  55
200 101 16  17  18  36  37  38  56  57  58
200 102 19  20  21  39  40  41  59  60  61


If you are okay with a MultiIndex, which will be handier then the concatenated strings in most cases, you can leave it at that. If you want it in the form you have it, you can do df2.columns = df2.columns.map(lambda x: f"{x[0]}{x[1]}").