A groupby on two columns gives a Series with a two-level index (region, then channel). unstack() moves the last level into the columns, so you get a grid:
df.groupby(["region", "channel"])["revenue"].sum().unstack()
unstack(level=0) moves the first level instead (regions across the top).
- Combinations that never happened become
NaN; unstack(fill_value=0) fills them.
stack() does the reverse: it moves the columns back into the index and returns a long Series. Follow it with reset_index(name="revenue") to get a flat table.
groupby plus unstack gives the same grid as pivot_table; use whichever reads better in your code.