Group-based aggregation is central to data analysis, and Pandas implements the familiar split-apply-combine pattern through groupby. The expression df.groupby('category')['value'].mean() computes the mean of value for each unique category, and df.groupby('col').size() returns a Series with the number of rows in each group. Multiple summary statistics can be calculated at once with df.groupby('col').agg(['mean', 'sum', 'count']), which produces a DataFrame whose columns are the chosen aggregations. When you need a result that aligns with the original rows rather than a single row per group, transform is the right tool: df.groupby('group')['val'].transform(lambda x: (x - x.mean()) / x.std()) standardizes values within each group, useful for features that should be normalized relative to their own category. To run completely custom logic, df.groupby('col').apply(my_function) passes each group DataFrame to your function.
Combining data from multiple sources is another core capability. The function pd.merge(df1, df2, on='key') performs an inner join by default, keeping only rows whose key appears in both DataFrames. The how argument controls the join style: 'left' keeps all rows from the first DataFrame, 'right' keeps all rows from the second, and 'outer' keeps all rows from both, filling missing matches with NaN. When the key columns have different names, you can specify them separately with left_on and right_on, as in pd.merge(df1, df2, left_on='id', right_on='user_id'). For index-based joins, df1.join(df2, how='inner') aligns the two DataFrames on their index.
Stacking and reshaping cover cases where data needs to be reorganized rather than joined by key. pd.concat([df1, df2]) stacks DataFrames vertically by default, appending rows, while pd.concat([df1, df2], axis=1) joins them horizontally, aligning on the index. Pivot tables summarize data along two dimensions: df.pivot_table(values='sales', index='region', columns='quarter', aggfunc='sum') produces a matrix of total sales broken down by region and quarter. The inverse operation, df.melt(id_vars=['id'], value_vars=['col1', 'col2']), unpivots columns into rows, converting wide-format data into long format suitable for many plotting libraries and tidy-data workflows.