Grouping and Aggregation with pandas

Learn to split a pandas DataFrame into groups and summarize each one. Group by columns, derived keys and index levels; compute built-in, multiple and custom aggregations; add group statistics to every row with transform; rank, filter and sample within groups; and use apply for everything else. Then bin numbers with cut and qcut for quantile analysis, and build pivot tables and cross-tabulations with totals and percentages.

IntermediateLesson 5 of 8 in Data Analysis with Python Course

What you will learn

  1. Explain the split-apply-combine pattern, create GroupBy objects from different kinds of keys, and control how the grouped result is labeled, ordered and completed.
    • Explain split-apply-combine and the GroupBy object
      Describe what happens when pandas groups a DataFrame, inspect the groups it forms, and select the columns to summarize.
    • Group by columns, arrays, mappings, functions and index levels
      Choose and combine grouping keys, from one or several columns to derived keys, mappings, functions and index levels.
    • Control group keys, order and missing keys in results
      Shape grouped results for further work: keys as index or columns, sorted output, missing keys and unused categories, and clear names.
  2. Reduce every group to summary values with built-in aggregations, several aggregations in one call, and custom functions, and interpret the results correctly.
    • Use built-in aggregation methods correctly
      Compute counts, totals, averages, spreads and other summaries per group, and know how they treat missing values and text columns.
    • Apply several aggregations at once with agg
      Use agg with lists, dictionaries and named aggregation to build summary tables with clear column names.
    • Write custom aggregation functions
      Write your own functions that reduce a group to one value, name their results, and know when a built-in or a ratio of sums is the better choice.
  3. Add group results to every row, compute running and relative values within groups, keep or sample groups and rows, and use apply for operations the other methods cannot express.
    • Add group statistics to every row with transform
      Use transform to broadcast group results back to the original rows for shares, deviations, standardized values and group-based filling of missing data.
    • Compute running totals, ranks and changes within groups
      Use cumulative, ranking and shifting methods that restart in every group, and keep the rows in the intended order.
    • Keep, drop or sample rows group by group
      Filter whole groups by a condition, take the first, last or top rows of each group, and draw random samples within groups.
    • Run general group operations with apply
      Use apply for group operations that need several columns or return tables, predict the shape of its result, and prefer faster methods when they fit.
  4. Turn numeric values into interval categories with cut and qcut, compute quantiles, and use the bins as grouping keys for bucket and quantile analysis.
    • Bin values into intervals with cut
      Use cut with explicit edges or a number of equal-width bins, read interval notation, and control edges, labels and values outside the bins.
    • Make equal-count bins with quantiles and qcut
      Compute quantiles, create quantile-based bins with qcut, compare them with equal-width bins, and handle ties.
    • Compare groups defined by bins and quantiles
      Use the output of cut and qcut as grouping keys for bucket and quantile analysis, keep empty bins when needed, and interpret the results with care.
  5. Build two-way summary tables with pivot_table and crosstab, add totals, convert counts to proportions, and choose the table that answers the question.
    • Build pivot tables with pivot_table
      Summarize values by row and column keys with pivot_table, choose the aggregation function, and add fill values and totals.
    • Count and compare categories with crosstab
      Build frequency tables of two categorical variables with crosstab, add totals, convert counts to row, column or overall proportions, and choose the proportion that answers the question.

Grouping and Aggregation with pandas study guide

5 chapters

1

Split data into groups with groupby

Grouped analysis starts with a question such as “How many units did each region sell?” You choose the keys that define a group, select the values to analyze, and decide what shape the answer should have. The same rows can support regional totals, product comparisons, or combinations of both. Understanding keys, indexes, and missing categories makes those results easier to inspect and use in a report.

1.1 Explain split-apply-combine and the GroupBy object

A group contains rows with the same key value. If the key is region, every North order belongs to one group even when those orders are scattered through the table. Split-apply-combine means identifying these groups, doing the same operation inside each one, and assembling the results.

Start with the order data

The examples use pandas 3 with import pandas as pd and NumPy as np. Create the drink-order table:

sales = pd.DataFrame({
    "region": ["North", "South", "North", "East", "South", "East", "North", "South"],
    "product": ["tea", "tea", "coffee", "coffee", "coffee", "tea", "tea", "coffee"],
    "units": [10, 4, 7, 5, 9, 3, 6, 8],
    "revenue": [30, 12, 28, 20, 36, 9, 18, 32]
})

Revenue has no currency unit here. Tea has revenue 3 per unit and coffee 4 per unit. The default row labels are 0 through 7.

From a GroupBy object to an answer

sales.groupby("region") returns a GroupBy object, which holds the grouping information. It is not a summary table. Choose a column and call a method to calculate a result:

g = sales.groupby("region")
totals = g["units"].sum()

East contains rows 3 and 5, so its total is 5 + 3 = 8. North contains rows 0, 2, and 6, giving 10 + 7 + 6 = 23. South contains rows 1, 4, and 7, giving 4 + 9 + 8 = 21. pandas combines these into a Series named units, with the region names as its index. The totals add to 52, the original column total.

The default output order is East, North, South because group keys are sorted. sales.groupby("region", sort=False) uses first-appearance order: North, South, East. Neither choice sorts the observations inside a group or changes sales.

Inspect and select

g.ngroups is 3. g.size() reports 2, 3, and 3 rows for East, North, and South. g.groups maps keys to row labels, and g.get_group("North") returns the three North rows. You can inspect one group at a time:

for name, group in g:
    print(name, group["units"].tolist())

Iteration helps when inspecting or exporting groups. For a statistic, a built-in grouped method avoids writing a Python loop and collecting the results yourself.

Selecting g["units"] produces a SeriesGroupBy; its sum is a Series. Selecting g[["units"]] produces a DataFrameGroupBy; its sum is a one-column DataFrame. Select g[["units", "revenue"]] when both numeric columns are needed.

Choose the output shape

An aggregation such as sum gives one summary value per group and column. A transformation gives a value for every input row, such as each order’s share of its region’s total. A filtration keeps selected rows or groups. The general apply method handles less regular group results.

Filtering sales[sales["region"] == "North"] retrieves one region’s rows. Grouping lets you process every region with the same operation.

Key Takeaways

  • Group keys decide which rows belong together.
  • A GroupBy object needs an operation before it produces a result.
  • Choose aggregation, transformation, or filtration by the output you need.
  • Grouping preserves the original table and the row order within each group.

1.2 Group by columns, arrays, mappings, functions and index levels

Keys can come from columns, calculations, or the row index. The important question is what value each row receives as its key. Rows with the same combination of keys are processed together.

Use several columns

Pass a list of column names to group by combinations:

pair_totals = sales.groupby(["region", "product"])["units"].sum()

The result has a two-level MultiIndex. Its entries are East–coffee 5, East–tea 3, North–coffee 7, North–tea 16, South–coffee 17, and South–tea 4. North–tea combines the two tea orders, with 10 and 6 units. Grouping by region alone would also include North’s coffee order.

pair_totals.unstack() moves the inner product level into columns. The rows are regions, and the columns are coffee and tea. An absent combination becomes NaN; unstack(fill_value=0) can represent it as zero when that absence means no units.

Use a list for multiple column names. groupby(("region", "product")) treats the tuple as a single column label and looks for a column with that tuple as its name.

Derive a key from values

A Boolean Series can divide orders by size without adding a column:

sales.groupby(sales["units"] >= 7)["revenue"].sum()

The True group contains units 10, 7, 9, and 8; its revenue is 126. The False group contains the other four orders and has revenue 59. The test creates group labels; it does not remove the smaller orders.

A mapping can combine regions into zones:

zones = {"North": "Zone 1", "East": "Zone 1", "South": "Zone 2"}
zone_key = sales["region"].map(zones)
sales.groupby(zone_key)["units"].sum()

Zone 1 receives North’s 23 and East’s 8 units, totaling 31. Zone 2 receives South’s 21. Map the column first: a dictionary passed directly to groupby maps index labels, not region values.

Group using the index

A function passed as a key also receives index labels. For stock indexed by product codes, the first letter can identify the product family:

stock = pd.Series([12, 8, 5, 9, 4],
                  index=["T01", "T02", "C01", "C02", "C03"])
stock.groupby(lambda code: code[0]).sum()

The C total is 18 and the T total is 20. For an existing MultiIndex, pair_totals.groupby(level="product").sum() regroups by the named index level, producing coffee 29 and tea 23.

Check alignment before grouping

A NumPy array key supplies labels by position and must have one element per row. A Series key is aligned by index label. If its labels cover only rows 0 and 1, the other rows receive missing keys and are dropped by the default grouping behavior. A reordered Series can still group correctly when its labels match; replacing it with its values changes the operation to positional matching.

Key Takeaways

  • Use a list of column names to group by combinations.
  • A key Series aligns by index label; an array supplies values by position.
  • Map column values before grouping when a dictionary describes those values.
  • Functions passed as keys receive index labels.
  • Use level for index levels and unstack to move an index level into columns.
  • A Boolean key separates rows into condition-based groups without removing either group.

1.3 Control group keys, order and missing keys in results

A grouped calculation has two parts to inspect: the values and the labels around them. pandas lets you choose where keys appear, how groups are ordered, and whether missing or unused keys appear in the report.

Keep keys in the index or in columns

By default, keys become the result’s index:

sales.groupby("region")["revenue"].sum()

This Series has East 29, North 76, and South 80. For a flat report, use:

report = sales.groupby("region", as_index=False)["revenue"].sum()

report has ordinary region and revenue columns and a new integer index. Calling .reset_index() on the original Series produces the same layout. With several keys, it converts each MultiIndex level into a column. unstack() has a different purpose: it moves an index level across into columns of a grid.

A Series result keeps the selected column’s name. Use .rename("total_revenue") for a clearer Series name or .to_frame("total_revenue") for a one-column DataFrame. Named aggregation can supply descriptive column names during the calculation.

Sort keys or rank values

sort=True sorts the keys, so alphabetical region order remains East, North, South even though South has the largest revenue. To rank totals, sort the result:

sales.groupby("region")["revenue"].sum().sort_values(ascending=False)

The output is South 80, North 76, East 29. Use sort=False to keep first-appearance key order and avoid unnecessary key sorting on a large dataset. It does not sort rows within groups.

Account for missing keys

The default dropna=True excludes rows with a missing group key. Add an order with 5 units but no region: the full units column now totals 57, while the grouped totals still add to 52. The omitted row has no named region.

sales.groupby("region", dropna=False)["units"].sum()

On the enlarged table, this adds a missing-key group totaling 5. Missing keys determine whether a row enters a group; missing values determine what an aggregation counts or calculates within a group. They are separate decisions.

Show unused categories when needed

A categorical region column can list East, North, South, and West even when there are no West orders. Since pandas 3.0, observed=True is the default and shows only categories present in the data. With observed=False, West appears too: its sum and count are 0, while its mean is NaN.

Choose this setting explicitly when a report must show the same categories every time. An unused category and a missing key are different: observed handles declared categorical values; dropna handles absent key values.

as_index and sort shape aggregation results. Transformations and filtrations such as head, nth, and filter retain input-row indexes. For a sum report, comparing the sum of group totals with the original column total can expose excluded keys or an earlier filter.

Key Takeaways

  • as_index=False places aggregation keys in ordinary columns.
  • sort orders keys; sort_values ranks calculated values.
  • dropna=False retains a group for missing keys.
  • observed=False includes unused categorical values.
2

Summarize each group with aggregations

A summary table turns many observations into a few useful measurements. Counts, totals, averages, and measures of spread answer different questions, even when they use the same groups. You will choose suitable built-in functions, collect several results in one call, and write a custom function when needed. Missing values and unequal group sizes matter: a neat table can still answer the wrong question.

2.1 Use built-in aggregation methods correctly

An aggregation reduces each group to a summary value for each selected column. Choose the measurement from the question: a row count, a total, an average, or a measure of variation describes a different feature of the data.

Select the statistic

Common methods include sum, prod, mean, median, min, max, count, size, nunique, std, var, first, last, and quantile. A direct call such as .mean() and .agg("mean") both request a pandas group mean. nunique() counts distinct non-missing values by default.

sales.groupby("product")["revenue"].agg(["mean", "median"])

Coffee revenues are 28, 20, 36, and 32. Their mean is 29; sorting them gives middle values 28 and 32, so their median is 30. Tea revenues are 30, 12, 9, and 18. Their mean is 17.25 and median 15. The large tea order of 30 pulls the mean above the median.

Count rows or recorded values

size() counts rows. count() counts non-missing values in each selected column. If units are missing for North row 2 and East row 5, sizes remain East 2, North 3, South 3, but units counts are 1, 2, and 3. Different columns can therefore have different counts inside the same group.

Most numeric reductions skip missing values. North’s remaining units 10 and 6 have mean 8, using two recorded values. Dividing their sum by all three rows would give the wrong mean. An all-missing group has sum 0 by default but mean NaN. Since pandas 3.0, reductions such as sum and mean accept skipna=False to return a missing result when a group contains a missing value.

Interpret spread and combined summaries

std() and var() use sample statistics, with ddof=1: the divisor is one less than the number of recorded observations. Values 1 and 3 have sample standard deviation about 1.414. A group with only the value 5 has sample standard deviation NaN.

describe() bundles count, mean, standard deviation, minimum, quartiles, and maximum. For South revenues 12, 36, and 32, the mean is about 26.67 and the median is 32. The 50% column is the median.

Control columns and row order

Selecting numeric columns avoids trying to average text:

sales.groupby("region")[["units", "revenue"]].mean()

A whole-table .mean() fails on the text product column; numeric_only=True is another solution. A whole-table .sum() can concatenate text, producing East’s "coffeetea", which is no useful product summary.

first() and last() choose the first and last non-missing value per column in current row order. They can take values from different rows. Use nth(0) to retrieve the actual first row, including its missing values; sort first when “first” means earliest.

Unequal group sizes also affect interpretation. The regional revenue means average to about 22.17, but the overall mean is 185 divided by 8, or 23.125. Giving every regional mean equal weight gives the two-row East group as much influence as each three-row group.

Key Takeaways

  • size counts rows; count counts recorded values.
  • Most reductions skip missing values; an all-missing sum defaults to zero.
  • std and var use the sample divisor by default.
  • Select relevant numeric columns before aggregating.
  • first can skip missing values; nth(0) selects an actual row.
  • Unequal groups need appropriate weights when combining their means.

2.2 Apply several aggregations at once with agg

A useful report often needs several measurements from the same groups. agg, short for aggregate, lets you request those measurements together and control how their output columns are named.

Give one column several functions
sales.groupby("region")["revenue"].agg(["sum", "mean", "max"])

East gives 29, 14.5, and 20; North gives 76, about 25.33, and 30; South gives 80, about 26.67, and 36. Each row represents one region, while the function names become column names.

A list applied to several value columns produces hierarchical columns:

result = sales.groupby("region")[["units", "revenue"]].agg(["sum", "mean"])

The four column labels are the pairs ("units", "sum"), ("units", "mean"), ("revenue", "sum"), and ("revenue", "mean"). The first level identifies the input column; the second identifies the calculation. These are column levels, separate from any grouping levels in the row index.

Assign functions to specific columns

A dictionary selects the input columns and their functions:

sales.groupby("region").agg({
    "units": "sum",
    "revenue": ["mean", "max"]
})

This requests total units but average and maximum revenue. Columns absent from the dictionary do not appear. Different functions can make sense for different measures; summing a quantity and averaging a rate are not interchangeable choices.

Name the outputs directly

Named aggregation gives each result an explicit name:

report = sales.groupby("region").agg(
    total_units=("units", "sum"),
    avg_revenue=("revenue", "mean")
)

Every keyword names an output column. Its tuple contains the source column and the function. total_units is 8, 23, and 21; avg_revenue is 14.5, about 25.33, and about 26.67. pd.NamedAgg(column="units", aggfunc="sum") is an alternative helper for specifying the source and function.

After selecting a single Series, use function keywords without source-column tuples:

sales.groupby("region")["units"].agg(total="sum", most="max")

The totals are 8, 23, and 21, and maxima 5, 10, and 9. A dictionary such as {"total": "sum"} on this selected Series raises a SpecificationError; it is not the dictionary form used on a DataFrame.

A list of named pairs also works on a selected column: .agg([("average", "mean"), ("spread", "std")]). If you already have MultiIndex columns made from string labels, result.columns = ["_".join(col) for col in result.columns] flattens them, producing names such as units_sum.

Choose the function deliberately

String names use pandas’ built-in group calculations. Since pandas 3.0, a NumPy or Python function passed to agg is called as supplied. For East revenues 20 and 9, "std" uses the sample divisor and gives about 7.78, while np.std uses the population divisor and gives 5.5.

Key Takeaways

  • A list applies several functions to the selected columns.
  • A dictionary assigns functions to particular input columns.
  • Named aggregation uses output names with (column, function) pairs.
  • String function names and NumPy callables can use different statistical defaults.

2.3 Write custom aggregation functions

A custom aggregation expresses a summary that a built-in name does not provide. Its function receives one group’s values as a Series and should reduce them to one useful result.

Write and pass the function
def value_range(s):
    return s.max() - s.min()

sales.groupby("region")["revenue"].agg(value_range)

East’s range is 20 minus 9, or 11. North’s is 30 minus 18, or 12. South’s is 36 minus 12, or 24. Pass value_range itself; value_range() would call it immediately without the group Series it needs.

A lambda suits a short calculation:

sales.groupby("region")["revenue"].agg(
    share_20=lambda s: (s >= 20).mean()
)

Boolean values act as 1 for True and 0 for False, so their mean is the share passing the condition. East has one qualifying order out of two, or 0.5. North and South each have two out of three, or about 0.667. Naming the result makes its meaning clearer than an automatic lambda label. Lists with several functions label lambdas <lambda_0>, <lambda_1>, and so on; a lone lambda in a list is labeled <lambda>.

Prepare columns to use fast reductions

A Python function runs once for each group. When there are many groups, built-in reductions are usually faster. The share calculation can be rewritten by making its Boolean column first:

sales.assign(big=sales["revenue"] >= 20).groupby("region")["big"].mean()

The comparison runs on the full column, leaving pandas to calculate the group means.

Combine two columns through their totals

An agg function handles one column at a time. For average revenue per unit, first summarize both columns:

totals = sales.groupby("region")[["units", "revenue"]].sum()
avg_price = totals["revenue"] / totals["units"]

The results are East 29/8 = 3.625, North 76/23 ≈ 3.304, and South 80/21 ≈ 3.810. Every unit receives equal weight. Averaging the order prices instead gives East 3.5, North about 3.333, and South about 3.667, because each order receives equal weight regardless of its size. Decide whether the question concerns a typical unit or a typical order before choosing the formula.

Keep the return value and missing data clear

A function returning the two smallest values does not create two ordinary summary rows through agg; in pandas 3.1, lambda s: s.nsmallest(2) stores a list-like object in each cell. Use apply when a group needs to return several values or rows.

The input Series still contains missing values. s.mean() skips them, while len(s) counts their rows. If units are missing at rows 2 and 5, .agg(len) gives group sizes 2, 3, and 3, not non-missing counts 1, 2, and 3.

Extra arguments can follow the function: .agg("quantile", 0.9) gives each group’s 90th percentile. East revenues 9 and 20 give 18.9 by linear interpolation. The direct .quantile(0.9) call is easier to read for this single operation.

Key Takeaways

  • Pass a function to agg without calling it first.
  • A custom aggregation receives one group’s Series and should return one summary value.
  • Boolean means give proportions.
  • A ratio of totals weights units differently from a mean of row-level ratios.
  • Prefer built-in reductions when they express the calculation.
  • Custom functions must handle missing values intentionally.
3

Transform, filter and apply functions group by group

A group can provide context for each original row, not just a separate summary. An order can receive its region’s total, its rank, or the change from that region’s previous order. Other tasks keep selected groups or return a table from each group. Choosing a method by its output shape makes this work clearer and avoids index alignment errors when you add a result back to the original data.

3.1 Add group statistics to every row with transform

A summary has one row per group, but sometimes each original row needs its group’s statistic. transform returns a result with the original length and index, making it suitable for a new column.

Broadcast a total to the right rows
g = sales.groupby("region")["revenue"]
regional_total = g.transform("sum")
sales["share"] = sales["revenue"] / regional_total

The total Series contains 76, 80, 76, 29, 80, 29, 76, and 80 in original row order. North’s total 76 is repeated only on North rows. Row 0 receives a share of 30/76 ≈ 0.395; East row 3 receives 20/29 ≈ 0.690. Within each region, these revenue shares sum to 1.

Assigning g.sum() directly would fail to match the rows. Its index contains region names, while sales has row labels 0 through 7. pandas aligns by index label, so the assigned column becomes missing. Either use transform or explicitly merge a summary onto region.

Compare a row with its group

Subtracting the group mean gives a within-group deviation:

x = sales["revenue"]
deviation = x - g.transform("mean")

North row 0 is about 4.67 above its group mean of about 25.33. South row 1 is about 14.67 below its group mean of about 26.67. Each comparison uses the row’s own region, not the whole table’s average.

A z-score divides that deviation by the group’s standard deviation:

z = (x - g.transform("mean")) / g.transform("std")

For North row 0, the sample standard deviation is about 6.43 and the z-score about 0.73. East row 3 has a z-score about 0.71, so it is above its region’s average even though its revenue of 20 is below the overall average of 23.125. A zero standard deviation or too few recorded values leaves a standardized score undefined.

Fill a missing value from its group

Suppose units at rows 2 and 5 are missing. North’s recorded units are 10 and 6, with mean 8; East’s only recorded units value is 5.

with_missing = sales.copy()
with_missing.loc[[2, 5], "units"] = np.nan
means = with_missing.groupby("region")["units"].transform("mean")
filled_units = with_missing["units"].fillna(means)

On that modified table, row 2 receives 8 and row 5 receives 5. Existing values remain unchanged. When groups have different typical values, their own means can provide more realistic replacements than one overall mean. A group with no recorded values still has no mean to supply.

Understand a custom transform

A function given to transform can return a scalar, which pandas repeats within the group, or a Series indexed to the group’s rows. For example, g.transform(lambda s: s - s.mean()) computes the same deviations as the built-in mean followed by subtraction, but invokes Python for each group.

A shorter returned Series is matched by label. g.transform(lambda s: s.head(1)) supplies only the first row’s value in each group; the other rows receive NaN. Keep row-level calculations in the original index when the result will be assigned back to the table.

Key Takeaways

  • transform returns results aligned with the input rows.
  • Divide each value by its transformed group total for within-group shares.
  • Use group means and standard deviations for within-group comparisons.
  • Group-based filling uses the statistic of the missing row’s own group.

3.2 Compute running totals, ranks and changes within groups

Running calculations and comparisons with previous observations need both a group and a row order. Grouping prevents a calculation from crossing into another group; sorting determines what “previous” or “so far” means.

Accumulate within each group

Assume the order rows are already in time order:

sales["running_units"] = sales.groupby("region")["units"].cumsum()

North’s units 10, 7, and 6 produce running totals 10, 17, and 23. South’s 4, 9, and 8 produce 4, 13, and 21. East’s 5 and 3 produce 5 and 8. These values remain attached to their original row labels, so the full output in row order is 10, 4, 17, 5, 13, 8, 23, and 21.

Without groupby, sales["units"].cumsum() would give one total across all orders: 10, 14, 21, 26, 35, 38, 44, and 52. The grouped calculation restarts for each region. Related methods include cumprod, cummax, and cummin for running products, maxima, and minima.

cumcount() counts positions within groups from zero. Here it gives 0, 0, 1, 0, 1, 1, 2, and 2. Add 1 for the first, second, and third order numbers within each region.

Rank values without rearranging rows
sales.groupby("region")["revenue"].rank(ascending=False)

The largest revenue receives rank 1 in its own region: North row 0, South row 4, and East row 3. The output keeps the input index; ranking does not move the largest rows to the top of the table.

By default, ties receive their average rank. If two values tie for first place, both get 1.5 and the next gets 3. method="min" gives the tied values 1 and still gives the next 3. method="dense" gives the tied values 1 and the next 2. Choose a tie rule that fits how the ranks will be interpreted.

Compare consecutive values
g = sales.groupby("region")["units"]
previous = g.shift(1)
change = g.diff()
relative_change = g.pct_change()

North’s previous values are missing, 10, and 7. Its differences are missing, −3, and −1. Its relative changes are missing, −0.3, and about −0.143: the difference is divided by the previous value. pct_change() returns a fraction, so −0.3 means a 30% decrease, not a 0.3% decrease.

The first observation of each group has no previous observation and receives NaN. A plain column shift() would use the previous row of the whole table, which could belong to another region.

Before these ordered calculations, sort the rows by the column that defines the sequence, such as a date or event number. groupby(sort=True) sorts group keys only; it cannot put observations into chronological order. Ranking compares values and handles ties independently of chronology, while cumulative and lagged calculations depend on the chosen sequence.

Key Takeaways

  • Sort observations before calculations that depend on their sequence.
  • Grouped cumulative methods restart inside every group.
  • cumcount starts at zero; add 1 for ordinary sequence numbers.
  • Choose the rank direction and tie method explicitly when needed.
  • shift, diff, and pct_change compare observations within the same group.
  • pct_change returns a fraction that can be multiplied by 100 for a percentage.

3.3 Keep, drop or sample rows group by group

Keeping a group and summarizing it are different operations. A group filter uses a group-wide condition to decide which original rows remain; row-selection methods choose particular observations from each group.

Keep whole groups
sales.groupby("region").filter(lambda g: len(g) >= 3)

North and South each have three orders, while East has two. The result contains rows 0, 1, 2, 4, 6, and 7, in original order with their original labels. It does not return two regional summary rows.

The condition must produce one Boolean for each group. lambda g: g["units"] > 5 produces a Boolean Series and is invalid for filter. Reduce that condition with all() or any():

sales.groupby("region").filter(lambda g: (g["units"] > 5).all())

Only North passes, because all its units values, 10, 7, and 6, exceed 5. Using any() also keeps South because at least one of its orders exceeds 5.

A transformed group size provides a faster row-aligned mask for the first task:

sizes = sales.groupby("region")["units"].transform("size")
sales[sizes >= 3]

This mask can be combined with other row conditions using & and |. Filtering sales.groupby("region")["revenue"].sum() instead would retain summary entries, not the original orders.

Take rows by position

head(n) takes the first n rows per group, tail(n) the last n, and nth(k) the row at zero-based position k. sales.groupby("region").head(1) returns rows 0, 1, and 3: the first observed order from each region. Missing values do not make head(1) search for a later non-missing row.

To select the largest order per region, first sort by revenue:

sales.sort_values("revenue", ascending=False).groupby("region").head(1)

The selected rows are South row 4 with revenue 36, North row 0 with 30, and East row 3 with 20. Sorting controls which observation is first; the group operation then takes that first row. With unique row labels, sales.loc[sales.groupby("region")["revenue"].idxmax()] retrieves the same maxima by their labels.

Sample within every group
sales.groupby("region").sample(n=1, random_state=0)

This draws one order from each region. Setting random_state makes repeated runs on the same data repeatable. A sample from the entire DataFrame could miss a region, even if it has three rows in total.

Use frac=0.5 to draw about half the rows in each group. The per-group sample size is rounded: with frac=0.2, East’s two rows yield 0.4 rows, rounded to zero. Use an explicit n=1 when every nonempty group must contribute one observation. The requested sample size must be feasible for the groups under the chosen sampling settings.

Key Takeaways

  • filter returns original rows from groups whose single Boolean condition passes.
  • head, tail, and nth select rows in current order.
  • Sort before head when selecting top values.
  • Grouped sampling with n=1 represents each nonempty group; a small fraction can omit small groups.

3.4 Run general group operations with apply

apply lets a function examine a whole group and return a scalar, a Series, or a DataFrame. That flexibility is useful when columns must interact or the result contains several rows. It also makes the result shape less predictable than agg or transform.

Use several columns together
def price_per_unit(g):
    return g["revenue"].sum() / g["units"].sum()

sales.groupby("region").apply(price_per_unit)

The function receives one region’s rows. It returns one value, so pandas combines the outputs into a Series indexed by region: East 3.625, North about 3.304, and South about 3.810. A ratio of built-in grouped sums produces the same result with less Python overhead. np.average(g["revenue"] / g["units"], weights=g["units"]) expresses the equivalent weighted mean.

For a statistic involving two columns, such as the correlation between study hours and score within each class group, apply can pass the two Series from each group to .corr().

Predict how outputs combine

A function returning a Series with the same labels for every group creates one table row per group:

sales.groupby("region").apply(
    lambda g: pd.Series({
        "orders": len(g),
        "avg_price": g["revenue"].sum() / g["units"].sum()
    })
)

The columns are orders and avg_price. The counts appear as 2.0, 3.0, and 3.0 because the returned Series also holds a floating-point price. If the returned Series use different labels, pandas stacks them into a longer Series, adding group keys as an outer index level.

A DataFrame per group is stacked into a larger DataFrame:

def top(g, n=2, col="revenue"):
    return g.sort_values(col, ascending=False).head(n)

sales.groupby("region").apply(top)

The rows are East 3 and 5, North 0 and 2, and South 4 and 7. Each group is sorted independently. Extra arguments follow the function: .apply(top, n=1, col="units") changes the selection to the largest units order.

Control keys and alignment

For these returned rows, the default group_keys=True adds the region as an outer index level. sales.groupby("region", group_keys=False).apply(top) keeps just the original row labels. It still assembles results group by group; it does not promise the input table’s row order.

Since pandas 3.0, the DataFrame passed to a grouped apply excludes the grouping columns. In this example it has product, units, and revenue, but not region. Read the current group key from g.name when the function needs it.

Use the narrower method when it fits

apply runs Python code for each group and infers how to assemble the output. Use agg for per-column summary values, transform for results aligned to every input row, and filter for group-wide keep-or-drop decisions.

For example, subtracting each region’s mean through a selected-Series apply returns differences under a region-and-row MultiIndex. transform returns the differences with the original index and is ready for assignment as a column.

Key Takeaways

  • apply can use several columns and return flexible result shapes.
  • A scalar result gives a Series; matching Series labels give a table.
  • DataFrame results are stacked, usually with group keys in the index.
  • Since pandas 3.0, grouped apply excludes grouping columns from each input group.
  • Prefer agg, transform, or filter when their result contract fits.
  • Use group_keys to control outer group labels, not to restore original row order.
4

Bin numeric data and analyze groups by bins and quantiles

Numeric values can become useful group labels when you divide them into intervals. Fixed boundaries let you compare the same ranges across reports; quantiles let you compare lower and upper parts of a sample. You will create both kinds of bins, inspect boundaries and ties, and summarize another variable within them. Counts beside the summaries help you see how much data supports each comparison.

4.1 Bin values into intervals with cut

Binning, also called discretization, replaces numeric values with interval categories. Use it when a report needs meaningful ranges, such as score bands, instead of a separate group for every number.

Set explicit boundaries
scores = pd.Series([42, 50, 55, 64, 68, 70, 73, 81, 85, 88, 97, 100])
bands = pd.cut(scores, [0, 50, 70, 85, 100])
bands.value_counts(sort=False)

Five edges define four bins: (0, 50], (50, 70], (70, 85], and (85, 100]. They contain 2, 4, 3, and 3 scores. Explicit edges can have unequal widths because they describe meaningful boundaries.

A parenthesis excludes an endpoint and a square bracket includes it. With the default right=True, 50 belongs in the first bin, 70 in the second, 85 in the third, and 100 in the fourth. Read (50, 70] as “greater than 50 and at most 70.”

Handle the outer edges

With these explicit edges, 0 is excluded from the first interval, and 101 lies beyond the last interval. Both receive NaN. Use include_lowest=True to include a value equal to the lowest edge. Values below the lowest edge or above the highest still receive no bin.

For left-closed intervals, use right=False. The same edges then define [0, 50), [50, 70), [70, 85), and [85, 100). Now 50 moves into the second bin and 100 is excluded. The example counts become 1, 4, 3, and 3, with one missing bin assignment. A top edge of 101 would include the score 100 in the last left-closed bin.

Changing the closure changes membership at a boundary. Check a minimum, an internal boundary, and a maximum before using the bands in a report.

Add readable labels
bands = pd.cut(
    scores, [0, 50, 70, 85, 100],
    labels=["fail", "pass", "merit", "distinction"]
)

Provide one label for each interval: four labels for five edges. The output is an ordered categorical, so its order is fail, pass, merit, distinction, not alphabetical order. labels=False instead returns zero-based bin codes 0 through 3 for assigned values.

value_counts() normally sorts by frequency. Use sort=False or sort the resulting index to retain the interval sequence. Otherwise the most frequent band may appear first and make the distribution harder to read.

Ask pandas for equal widths

Passing an integer requests that many equal-width bins:

bands, edges = pd.cut(scores, 4, retbins=True)

The range from 42 to 100 spans 58, giving widths of 14.5. The internal edges are 56.5, 71.0, and 85.5. pandas extends the lower end slightly for these right-closed bins, giving a first edge of 41.942 so the minimum is included. Each bin happens to contain three scores here; equal widths do not generally produce equal counts.

retbins=True returns the actual edges as well as assignments. Explicit edges must be in increasing order: [0, 70, 50, 100] cannot define the intended sequence of intervals.

Key Takeaways

  • cut turns numeric values into interval categories.
  • By default, bins exclude the left edge and include the right edge.
  • Explicit edges leave out-of-range values unassigned.
  • include_lowest=True includes the lowest explicit edge.
  • An integer bin count requests equal widths, not equal counts.
  • Labels and counts need to retain the intended interval order.
  • right=False changes which endpoint belongs to each interval; check the maximum after changing closure.

4.2 Make equal-count bins with quantiles and qcut

A quantile describes a position in sorted data. The median is the 0.5 quantile; quartiles divide the distribution into quarters, deciles into tenths, and percentiles into hundredths. qcut uses sample quantiles as bin boundaries.

Compute a quantile

For the scores 42, 50, 55, 64, 68, 70, 73, 81, 85, 88, 97, and 100:

scores.quantile([0.25, 0.5, 0.75])

The results are 61.75, 71.5, and 85.75. pandas uses linear interpolation by default. For the 0.25 quantile, the zero-based position is:

0.25(12−1)=2.75

Position 2 holds 55 and position 3 holds 64. Move three quarters of the distance between them:

55+0.75(64−55)=61.75

A sample quantile can therefore fall between observed values. It need not equal a score that someone actually received.

Create quantile groups
quartile = pd.qcut(scores, 4, labels=["Q1", "Q2", "Q3", "Q4"])

This sample gives three scores per quartile group. The internal boundaries are the three computed quartiles. The first interval includes the minimum; the interval display adjusts its lower label slightly below 42. Use labels=False for codes 0 through 3, or retbins=True to retrieve the numeric boundaries.

A list of proportions controls the quantile ranges. pd.qcut(x, [0, 0.1, 0.5, 0.9, 1]) separates the bottom 10%, two middle portions split at the median, and the top 10%.

Choose widths or counts
MethodWhat sets the boundaries?What is kept comparable?
cut(x, n)Equal intervals across the observed rangeNumeric width
cut(x, edges)Explicit supplied edgesThe chosen ranges
qcut(x, n)Quantiles of this sampleApproximate observation counts

Delivery times of 5, 6, 7, 7, 8, 9, 10, 12, 15, 20, 35, and 60 minutes show the difference. Three equal-width bins contain 10, 1, and 1 observations. Three quantile bins contain 4 each, with internal edges about 7.67 and 13 minutes. Long delays spread out the equal-width range, leaving most observations in its first bin.

Use fixed edges when the same time ranges must be compared across datasets. Quantile boundaries change when the sample changes.

Keep ties visible

For values 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, and 12, quartile edges are 3.75, 6, and 8.25. Both values of 6 belong together, so bin counts are 3, 4, 2, and 3. Equal-count binning is approximate when values tie.

With many ties, quantile edges can coincide. For 1, 1, 1, 1, 1, 1, 2, and 3, requesting quartiles gives repeated edges. duplicates="drop" removes duplicate edges and leaves only two bins, with counts 6 and 2. Ranking first with rank(method="first") can force four equal-sized groups, but it splits equal values according to row order. That changes the meaning from value intervals to groups based on tie-broken ranks.

Key Takeaways

  • Quantiles can lie between observations because pandas interpolates.
  • qcut uses sample quantiles to create approximately equal-count groups.
  • Use fixed cut edges for ranges that must stay comparable across datasets.
  • Ties can make quantile bin counts unequal or produce duplicate edges.
  • Dropping duplicate edges reduces the number of bins; ranking first splits ties.

4.3 Compare groups defined by bins and quantiles

A bin label can serve as a group key. This lets you ask how one variable changes across ranges of another, such as average exam score across study-hour bands. The summary describes the observations in each band.

Build a bucket summary

Create the student data:

students = pd.DataFrame({
    "group": ["day", "evening", "day", "evening", "day", "evening", "day", "evening", "day", "day", "evening", "day"],
    "hours": [2, 3, 3, 5, 4, 6, 6, 8, 7, 9, 10, 12],
    "score": [42, 50, 55, 64, 68, 70, 73, 81, 85, 88, 97, 100]
})
hour_band = pd.cut(students["hours"], [0, 3, 6, 9, 12])
students.groupby(hour_band)["score"].agg(["count", "mean"])

The four bands contain 3, 4, 3, and 2 students. Their mean scores are 49, 68.75, about 84.67, and 98.5. In the first band, the scores are 42, 50, and 55; their mean is 147/3 = 49. The count shows how many recorded scores support each mean.

The band Series has one entry per student and the same index, so its assignments match the rows during grouping. The numeric hours column stays available for other calculations.

Keep empty bins when a report needs them

Since pandas 3.0, observed=True is the grouping default for categorical keys. Add an edge of 15 and the unused (12, 15] band will be omitted. observed=False keeps it with count 0 and mean NaN. Zero students is a count; a zero mean would wrongly suggest observed scores averaging zero.

Bins are ordered categories, so the normal grouped output follows low-to-high interval order. Named labels retain the order assigned to their intervals.

Analyze quantile groups and combinations
quartile = pd.qcut(students["hours"], 4,
                   labels=["Q1", "Q2", "Q3", "Q4"])
students.groupby(quartile)["score"].agg(["count", "min", "max", "mean"])

Counts are 3, 4, 2, and 3, with mean scores 49, 68.75, 83, and 95. The tied values of 6 explain the unequal counts. To compare day and evening students inside each quartile, group by [quartile, "group"] and call .mean().unstack(). Q1 means are day 48.5 and evening 50; Q4 means are day 94 and evening 97.

The direction of the analysis matters. Grouping study hours by score bands answers a different question: the mean hours for fail, pass, merit, and distinction bands are 2.5, 4.5, 7, and about 10.33.

Decide which population defines a quantile

An overall median split of scores uses 71.5. A split within each class uses its own median: day 73 and evening 70.

within_class = students.groupby("group")["score"].transform(
    lambda s: pd.qcut(s, 2, labels=["lower", "upper"])
)

The day student scoring 73 is above the overall median but belongs to the lower half within the day group. Both labels are correct because they answer different comparison questions.

A rising mean across hour bands is an association. Students in different bands may differ in other ways, so the table alone cannot establish that extra study time caused the score difference. Small counts also make a mean more sensitive to a single observation.

Key Takeaways

  • Use a bin Series as a group key to summarize another variable.
  • Report counts beside means so the amount of supporting data is visible.
  • observed=False keeps empty bins with zero counts and missing means.
  • Overall and within-group quantiles use different reference populations.
  • Patterns across bins describe association and can be sensitive to small samples.
5

Summarize data in pivot tables and cross-tabulations

A two-way table makes combinations of categories easy to compare. A pivot table summarizes a numeric value at each row-and-column intersection, while a cross-tabulation usually counts observations. Totals and proportions add context, but their meaning depends on the aggregation and denominator. You will build both tables and read each cell as an answer to a precise question.

5.1 Build pivot tables with pivot_table

A pivot table summarizes values for combinations of row and column keys. Each cell collects the observations at one intersection and applies a function, such as a sum or mean.

Assign the roles explicitly
sales.pivot_table(
    index="region", columns="product",
    values="revenue", aggfunc="sum"
)

index supplies the row keys, columns the column keys, values the measured variable, and aggfunc the calculation. The table is:

Regioncoffeetea
East209
North2848
South6812

North–tea combines revenues 30 and 18, so its sum is 48. South–coffee combines 36 and 32, giving 68. The same data can be summarized with sales.groupby(["region", "product"])["revenue"].sum().unstack().

The default aggfunc is "mean". Omitting it would give North–tea 24 and South–coffee 34. State aggfunc="sum" when the question asks for totals; a table’s layout does not tell you which statistic it contains.

Fill absent combinations carefully

Combinations without observations appear as NaN. Remove East’s tea order and that cell becomes missing. fill_value=0 can represent no orders in a sum or count report. For a mean, replacing an empty cell with 0 suggests an observed average that was never measured. Keep its missing status when no average exists.

Categorical keys follow the observed choice; since pandas 3.0, the default shows observed categories. Set it explicitly when a report must retain unused categories.

Add margins using the same function
sales.pivot_table(
    index="region", columns="product", values="revenue",
    aggfunc="sum", margins=True, margins_name="Total"
)

Row totals are East 29, North 76, and South 80. Column totals are coffee 116 and tea 69; the grand total is 185. margins_name replaces the default label All.

Margins are recomputed from underlying rows using the aggregation function. For a mean pivot, the corner is 23.125, the mean of all eight orders. Averaging the six displayed cell means would give about 21.17 because the cells contain different numbers of observations. A margin is not a general instruction to add or average whatever numbers happen to be displayed.

Extend or count the table

aggfunc=["sum", "mean"] makes a block of columns for each statistic. With units, North–tea has sum 16 and mean 8. A function dictionary such as {"units": "sum", "revenue": "max"} assigns functions to separate value columns. Multiple keys can also create hierarchical rows or columns, and binned values work as categorical keys.

aggfunc="size" counts rows per cell, while "count" counts non-missing values in the chosen value column. North has one coffee order and two tea orders.

pivot does no aggregation and requires unique row-and-column combinations. The sales table has repeated North–tea and South–coffee combinations, so pivot raises a duplicate-entry error. Use pivot_table when several observations must be combined into one cell.

Key Takeaways

  • index, columns, values, and aggfunc define the meaning of each pivot cell.
  • The default aggregation is a mean; request sums explicitly.
  • Fill absent counts or totals with zero only when zero expresses the absence correctly.
  • Margins apply the same function to the underlying observations.
  • Multiple functions or values can produce hierarchical columns.
  • Use pivot_table for repeated key combinations and pivot for unique combinations.

5.2 Count and compare categories with crosstab

A cross-tabulation, or contingency table, counts observations for combinations of categorical variables. Proportions then let you compare groups that contain different numbers of observations.

Count combinations

The survey data has six basic-plan users: four use phones and two use laptops. Its four premium users include one phone user and three laptop users.

survey = pd.DataFrame({
    "plan": ["basic"] * 6 + ["premium"] * 4,
    "device": ["phone", "phone", "phone", "laptop", "phone", "laptop",
               "laptop", "laptop", "phone", "laptop"],
    "minutes": [20, 35, 15, 40, 25, 50, 60, 45, 30, 55]
})
counts = pd.crosstab(survey["plan"], survey["device"], margins=True)

Pass the actual Series, not the strings "plan" and "device". The first variable supplies rows and the second supplies columns. The basic row contains laptop 2 and phone 4; the premium row contains laptop 3 and phone 1. Row totals are 6 and 4, column totals are 5 and 5, and the grand total is 10.

For raw counts, an absent combination is shown as zero. Equivalent counts can be obtained with survey.groupby(["plan", "device"]).size().unstack(fill_value=0) or a pivot table using aggfunc="size". survey.value_counts(["plan", "device"]) gives a long frequency list sorted by count.

Choose the denominator from the question
SettingDenominatorMeaning of basic–phone
normalize="all"All observations4/10 = 0.4
normalize="index"Basic row total4/6 ≈ 0.667
normalize="columns"Phone column total4/5 = 0.8

“What share of premium users use a laptop?” starts with the premium users, so the denominator is 4. Use row normalization; the answer is 3/4 = 0.75. “What share of phone users have the basic plan?” starts with phone users, so the denominator is 5. Use column normalization; the answer is 4/5 = 0.8.

A count of three premium laptop users exceeds the basic count of two, but the within-plan comparison is 75% against about 33.3%. Identify the population being compared before turning a count into a share. Multiply normalized values by 100 for percentages.

With margins=True, normalized margins also have meanings. Row normalization adds an All row showing the overall device shares, 0.5 and 0.5. Column normalization adds an All column showing the overall plan shares, 0.6 and 0.4.

Summarize a third variable

Supply values and aggfunc to replace frequencies with a numeric statistic:

pd.crosstab(survey["plan"], survey["device"],
            values=survey["minutes"], aggfunc="mean")

Basic laptop sessions of 40 and 50 minutes average 45. Basic phone sessions of 20, 35, 15, and 25 minutes average 23.75. Premium laptop sessions of 60, 45, and 55 minutes average about 53.33, while the single premium phone session lasts 30 minutes. These cells describe session length, not user counts.

A list of Series can provide multiple row or column levels. Binned scores also work as categories: crossing fail, pass, merit, and distinction with class group gives day counts 1, 2, 2, 2 and evening counts 1, 2, 1, 1. Every cell’s meaning still follows from its row key, column key, and chosen statistic.

Key Takeaways

  • crosstab counts combinations of supplied Series or arrays.
  • Choose row, column, or overall normalization from the question’s denominator population.
  • Adding values and aggfunc changes cells from frequencies to a numeric summary.

Grouping and Aggregation with pandas examples

5 Walkthroughs

1

Turn rows into useful groups

12 steps
Build and inspect a grouping, choose keys, and account for every row in the result.
  1. 1
    IntroductionStart with a grouped question

    A collection of orders can answer “How many units were sold?” or “How many units did each region sell?” The second question needs a grouping key.

    We will split orders by region, select a value column, and combine per-group results. Then we will change the keys and output layout while keeping track of which rows the calculation includes.

  2. 2
    ExampleSet up four orders

    Use a small table so you can follow every row:

    orders = pd.DataFrame({
        "region": ["West", "East", "West", "East"],
        "product": ["tea", "tea", "coffee", "tea"],
        "units": [6, 3, 8, 5]
    })
    

    The two West rows are separated by an East row. They still belong together when the key is region; matching keys matter more than neighboring positions.

  3. 3
    ExplanationSplit, add, combine
    orders.groupby("region")["units"].sum()
    

    East receives units 3 and 5, giving 8. West receives 6 and 8, giving 14. pandas combines the two totals into a Series indexed by region.

    Calling only groupby("region") creates the GroupBy object. The selection and sum() specify what to calculate from that grouping.

  4. 4
    TipInspect before calculating

    Store g = orders.groupby("region") when several inspections are useful. g.ngroups reports 2, g.size() reports two rows per region, and g.get_group("West") shows the West observations.

    Selecting g["units"] yields a SeriesGroupBy. Selecting g[["units"]] keeps DataFrame form, even though only one value column is selected.

  5. 5
    ChallengePredict a changed total

    A new West order with 4 units is appended to the table. What are the regional totals, and does grouping remove the original order rows?

    ---reveal---

    East stays at 8. West becomes 18 because the new order joins its existing 14 units. The original rows remain in the input table; the grouped sum is a new summary object with one entry per region.

  6. 6
    ExampleAdd a second key
    orders.groupby(["region", "product"])["units"].sum()
    

    Using the original four orders, East–tea totals 8, West–coffee totals 8, and West–tea totals 6. The Series has a two-level index.

    unstack() moves product into columns. East has no coffee row, so its coffee cell is missing; filling it with zero suits this units-total report.

  7. 7
    ConnectionA key can be calculated
    orders.groupby(orders["units"] >= 5)["units"].sum()
    

    The Boolean key creates a False group totaling 3 and a True group totaling 19. It labels every row instead of filtering out small orders.

    A mapped Series also works as a key. Series keys align by row label, while an array supplies one label per position and must match the row count.

  8. 8
    ChallengeRead a key from the index

    A stock Series is indexed M1, N1, M2, with values 4, 9, 7. What does stock.groupby(lambda label: label[0]).sum() return?

    ---reveal---

    M totals 11 and N totals 9. The function receives each index label and returns its first letter. It does not inspect the stock value. A dictionary passed directly as a key likewise maps index labels; map a column first when its values define the groups.

  9. 9
    ExplanationChoose labels and order

    orders.groupby("region", as_index=False)["units"].sum() returns a table with region and units columns. reset_index() converts an indexed summary into the same flat layout.

    Default key sorting lists East before West. To rank totals, sort the calculated values instead: .sum().sort_values(ascending=False). Key order and value order answer different needs.

  10. 10
    Key InsightMissing and unused keys differ

    Suppose region is categorical and also declares North, with no North orders. Since pandas 3.0, default observed=True omits that unused category; observed=False shows it.

    A row with no region is a separate issue. Default dropna=True excludes it from groups. dropna=False retains a missing-key group. One option cannot replace the other.

  11. 11
    ChallengeReconcile the report

    The original four orders total 22 units. A fifth order has 7 units and no region. A categorical region column also declares an unused North. How can a report total 29 and show North?

    ---reveal---

    Group with dropna=False, observed=False. The missing-key group retains the extra 7; North appears as an unused category with sum 0. Use as_index=False too if the report needs ordinary key columns.

  12. 12
    RecapCheck keys, values, and shape

    Choose the key that expresses which rows belong together, then choose the operation and selected value columns. Inspect groups when membership is unclear.

    After calculating a total, check whether missing keys caused rows to be excluded. For presentation, decide between an indexed result and ordinary key columns, and distinguish sorting group names from ranking the calculated values.

2

Choose and name group summaries

13 steps
Compute a multi-column report and distinguish row counts, recorded values, and weighted averages.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionA summary must answer a question
  2. 2
    ExampleFollow a batch with a missing value
  3. 3
    ExplanationRead the reduction defaults
  4. 4
    ChallengeCount the available readings
  5. 5
    ExampleName each output
  6. 6
    ExplanationUnderstand multi-function columns
  7. 7
    ChallengeRepair the report names
  8. 8
    ExampleAdd a custom range
  9. 9
    TipPrepare a Boolean column
  10. 10
    ExampleWeight the measured quantity
  11. 11
    ChallengeFind the price per unit
  12. 12
    ChallengeCombine unequal group means
  13. 13
    RecapKeep meaning attached to each statistic
3

Keep group context on the correct rows

16 steps
Build shares, ordered calculations, group filters, and flexible outputs without losing row alignment.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionDecide which rows the answer needs
  2. 2
    ExampleBroadcast a total
  3. 3
    ExampleTurn totals into shares
  4. 4
    ChallengeChoose the right fill value
  5. 5
    ExplanationEstablish the sequence first
  6. 6
    ExampleCompare with the previous observation
  7. 7
    TipChoose the tie rule
  8. 8
    ChallengeTrack interleaved groups
  9. 9
    ExampleKeep all rows from a qualifying group
  10. 10
    TipSelect or sample within groups
  11. 11
    ChallengeApply a whole-group condition
  12. 12
    ExplanationPredict apply’s shape
  13. 13
    ExampleReturn several rows per group
  14. 14
    ChallengeRepair a row assignment
  15. 15
    ChallengeCombine a group total with a row decision
  16. 16
    RecapMatch the method to the result
4

Build and compare numeric bands

14 steps
Choose fixed or quantile boundaries and use the resulting categories for grouped analysis.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionChoose what a band should mean
  2. 2
    ExampleCreate fixed intervals
  3. 3
    ExplanationCover the outer values
  4. 4
    TipKeep labels in interval order
  5. 5
    ChallengePlace boundary values
  6. 6
    ExplanationFind a sample quantile
  7. 7
    ExampleDivide by count or width
  8. 8
    Key InsightTies can change the bin count
  9. 9
    ChallengeChoose stable boundaries
  10. 10
    ExampleSummarize another variable
  11. 11
    TipDisplay empty groups honestly
  12. 12
    ChallengeChange the reference population
  13. 13
    ChallengeRead the final comparison
  14. 14
    RecapRead ranges before comparing results
5

Read two-way totals and proportions

11 steps
Build a pivot table and choose cross-tabulation denominators from the question being asked.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionGive every cell a meaning
  2. 2
    ExampleBuild a small pivot
  3. 3
    ExplanationState the aggregation
  4. 4
    Key InsightMargins use underlying observations
  5. 5
    ChallengeReport absence and totals
  6. 6
    ExampleCount category combinations
  7. 7
    ExplanationStart with the denominator
  8. 8
    ChallengeCompare unequal groups
  9. 9
    ConnectionA crosstab can summarize values
  10. 10
    ChallengeChoose the table for a report
  11. 11
    RecapRead function and population together

Grouping and Aggregation with pandas practice questions

50 Practice Questions in 5 sets

Set 1: Use row context and compare distributions10 Practice Questions

Question 1 of 10

A custom aggregation receives readings 3, 7, and 14. What does lambda s: s.max() - s.min() return?
  1. 7
  2. 8
  3. 24
  4. 11
Show answerHide answer
Answer: D
The maximum is 14 and the minimum is 3, so the returned range is 11. The function reduces the group’s Series to one value. A result of 8 would subtract the last two sorted values and omit the group minimum, so it would not measure the full range.

Question 2 of 10

A grouping g has already been created. Which expression reports how many groups it contains?
  1. g.count()
  2. g.ngroups
  3. g.size()
  4. len(g.groups.keys()) + 1
Show answerHide answer
Answer: B
ngroups is the number of groups in a GroupBy object. size() instead returns a separate row count for each group. count() also returns per-group results, but counts recorded values in each selected column rather than reporting one group count.

Question 3 of 10

A Series has row labels 10 and 20 with values 5 and 8. Its key Series is indexed 20 and 10 with values "outer" and "inner", respectively. What are the group sums?
  1. Outer 5; inner 8
  2. Outer 13; inner 13
  3. Outer 8; inner 5
  4. Outer 0; inner 13
Show answerHide answer
Answer: C
Series keys align to the data by index label. Label 20 therefore receives the key "outer" and contributes 8, while label 10 receives "inner" and contributes 5. Pairing the two Series by their displayed positions would swap the groups and ignore pandas’ label alignment.

Question 4 of 10

One group has 2 recorded values with mean 10; another has 6 recorded values with mean 20. What is the mean across all 8 values?
  1. 17.5
  2. 15.0
  3. 20.0
  4. 30.0
Show answerHide answer
Answer: A
The first group contributes a total of 20 and the second a total of 120. Their combined total of 140 divided by eight observations gives 17.5. Averaging 10 and 20 directly gives 15 because it assigns equal weight to groups that contain different numbers of observations.

Question 5 of 10

A DataFrame has integer row labels. Why can assigning its region-indexed sum Series directly as a new column create missing values?
  1. The sum changes integer labels into region names.
  2. Assignment matches row labels to the summary’s index.
  3. A sum Series stores only text instead of numeric values.
  4. Grouping overwrites the row index before assignment.
Show answerHide answer
Answer: B
Assignment aligns the incoming Series by index label. Region names in a summary do not match the original integer row labels, leaving those rows without a matching value. Grouping did not overwrite the DataFrame’s index; a transform or a merge by region supplies the needed alignment.

Question 6 of 10

A group filter should retain a workshop only if every recorded delay is below 4. What predicate gives one decision per group?
  1. lambda g: g["delay"] < 4
  2. lambda g: (g["delay"] < 4).any()
  3. lambda g: (g["delay"] < 4).all()
  4. lambda g: g["delay"].count() < 4
Show answerHide answer
Answer: C
all() combines the row comparisons into one Boolean and requires every comparison to pass. any() would retain a workshop even if just one delay were below 4. Returning the comparison Series itself does not give the single group decision required by filter.

Question 7 of 10

A grouped apply function returns a Series indexed low and high for every group. What structure does pandas build?
  1. A Series with only the first group’s two values
  2. A DataFrame with the original input row count
  3. A DataFrame with groups as columns and original rows
  4. A DataFrame with one row per group and two columns
Show answerHide answer
Answer: D
Matching Series labels become result columns, with one row for each group. Here those columns are low and high. A result with the original input row count would require a row-aligned operation; this function supplies two summary entries per group instead of one value for each input row.

Question 8 of 10

Monthly delivery times need four groups with approximately equal numbers of observations. Which operation fits?
  1. pd.qcut(times, 4)
  2. pd.cut(times, 4)
  3. times.quantile(0.4)
  4. times.groupby(times).size()
Show answerHide answer
Answer: A
qcut uses sample quantiles to form approximately equal-count groups. Ties can keep the counts from being exactly equal. cut(times, 4) instead makes equal-width intervals, which can have very different observation counts when the delivery-time distribution is uneven.

Question 9 of 10

Eight temperatures are 10, 11, 12, 13, 30, 31, 32, 33 °C. Site A has the first four; site B has the last four. What happens to 13 °C under an overall median split versus a split within site A?
  1. Upper overall; lower within A
  2. Lower overall; lower within A
  3. Lower overall; upper within A
  4. Upper overall; upper within A
Show answerHide answer
Answer: C
The overall median is 21.5 °C, so 13 °C belongs to the lower half of all observations. Site A’s median is 11.5 °C, so 13 °C belongs to its upper half. Calling it lower in both cases overlooks that the reference population changes from all sites to site A alone.

Question 10 of 10

A frequency table has rows X and Y and columns P and Q: X has 2 and 6; Y has 3 and 1. With row normalization and margins, what does the All row show for P and Q?
  1. 0.5 and 0.5
  2. 5/12 and 7/12
  3. 0.4 and 0.6
  4. 0.25 and 0.75
Show answerHide answer
Answer: B
The All row summarizes the whole sample’s column distribution. There are five P observations and seven Q observations out of twelve, so it shows 5/12 and 7/12. Averaging the two row proportions would give 0.5 and 0.5, incorrectly weighting the eight-row and four-row groups equally.
Set 2: Read groups and choose useful summaries10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A table has team labels Delta, Echo, Delta and item counts 6, 5, 9. What does grouping by team and summing item counts return?
  1. Delta 15; Echo 5
  2. Delta 6; Echo 14
  3. Delta 20; Echo 20
  4. Delta 7.5; Echo 5
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A DataFrame has columns site and material. How do you group by each combination of these two columns?
  1. df.groupby(("site", "material"))
  2. df.groupby("site")["material"]
  3. df.groupby(["site", "material"])
  4. df.groupby("site").get_group("material")
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A grouped total is needed as a DataFrame with site and mass_kg as ordinary columns. Which call produces that layout?
  1. df.groupby("site", sort=False)["mass_kg"].sum()
  2. df.groupby("site", as_index=False)["mass_kg"].sum()
  3. df.groupby("site", dropna=False)["mass_kg"].sum()
  4. df.groupby("site", observed=False)["mass_kg"].sum()
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

One batch has readings 8, missing, 12, missing. What are its size() and reading count()?
  1. Size 2; count 4
  2. Size 4; count 4
  3. Size 2; count 2
  4. Size 4; count 2
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

You need one row per machine with columns peak and average from load. What named aggregation fits?
  1. .agg(peak=("load", "max"), average=("load", "mean"))
  2. .agg(load=("peak", "max"), average=("load", "mean"))
  3. .agg(peak=("load", "mean"), average=("load", "max"))
  4. .agg(peak=("max", "load"), average=("mean", "load"))
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Three records in one lab have energy readings 4, 6, and 10 kWh. What value should the 6 kWh row receive when each reading is divided by its transformed lab sum?
  1. 0.60
  2. 0.20
  3. 0.30
  4. 0.50
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Rows are in event order: group A has value 7, group B has 3, then group A has 5. What is the grouped cumulative-sum output in that row order?
  1. 7, 10, 15
  2. 7, 3, 12
  3. 12, 3, 12
  4. 0, 0, 1
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Where does the value 40 fall in pd.cut(x, [0, 20, 40, 60]) with default closure?
  1. (0, 20]
  2. (40, 60]
  3. No bin
  4. (20, 40]
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A cell has two delivery durations, 12 and 18 minutes. What does a pivot_table cell contain if aggfunc is omitted?
  1. 15 minutes
  2. 30 minutes
  3. 2 deliveries
  4. 18 minutes
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A survey has 9 remote workers, 6 of whom cycle, and 3 onsite workers, 2 of whom cycle. A crosstab has workplace in rows and travel mode in columns. Which normalized result answers “What fraction of cyclists are remote workers?”
  1. normalize="index"; 6/9
  2. normalize="all"; 6/12
  3. normalize="index"; 2/3
  4. normalize="columns"; 6/8
Show answerHide answer

Save this lesson to see this answer.

Set 3: Check result shapes and boundary decisions10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A categorical key lists A, B, and C, but the data contains only A and B. In pandas 3, which setting includes C in a grouped summary?
  1. dropna=False
  2. as_index=False
  3. sort=False
  4. observed=False
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

Two value columns are aggregated with ["sum", "mean"]. What labels do the result columns have?
  1. Pairs of input-column name and function name
  2. Only the two original input-column names
  3. Pairs of group-key value and input-row label
  4. Only the two selected aggregation function names
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A supplier ships 2 kg at a unit price of 9 and 8 kg at a unit price of 4. What is the average price per kilogram across the shipment?
  1. 6.5
  2. 4.0
  3. 5.0
  4. 5.5
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A group’s values in sequence are 12, 9, and 15. What does grouped pct_change() return?
  1. Missing, −3, 6
  2. Missing, −0.25, about 0.667
  3. 0, −0.25, 0.5
  4. Missing, −0.333, 0.4
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A table is unsorted. You need the two largest mass_kg rows from each batch. Which procedure fits?
  1. Group by batch, then take tail(2).
  2. Sort batch names, then take head(2).
  3. Group by batch, then filter groups of size 2.
  4. Sort mass descending, then grouped head(2).
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A function f sorts each group by quality and returns two rows. With df.groupby("batch", group_keys=False).apply(f), what should you expect before assigning the result back?
  1. Original labels, with rows selected and ordered by group
  2. Original row order, with every input row retained
  3. A batch-indexed scalar Series with one value per group
  4. A fresh integer index with every input row retained
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A report uses pd.cut(x, [0, 10, 20], right=False). Which of the values 0, 10, and 20 receive bins?
  1. Only 10 and 20
  2. Only 0 and 20
  3. Only 0 and 10
  4. All three values
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Values are 2, 2, 2, 2, 2, 2, 6, 10. Quartile edges repeat. What is the consequence of qcut(..., 4, duplicates="drop") compared with ranking first using method="first"?
  1. Dropping edges preserves four bins and breaks ties.
  2. Dropping edges reduces bins; ranking can split ties.
  3. Dropping edges removes tied rows; ranking keeps them.
  4. Dropping edges uses fixed widths; ranking uses quartiles.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A fixed score-band report must show an empty band as well as occupied bands. What setting and result express this correctly for counts and means?
  1. observed=True; count 0, mean 0
  2. dropna=False; count 1, mean missing
  3. observed=False; count 0, mean missing
  4. as_index=False; count missing, mean 0
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Several observations share the same row-and-column keys. You need one total per cell. Which operation fits?
  1. pivot with the value column
  2. unstack on the unchanged rows
  3. crosstab without a value column
  4. pivot_table with aggfunc="sum"
Show answerHide answer

Save this lesson to see this answer.

Set 4: Build reliable grouped reports10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A notebook stores g = df.groupby("team")[["items"]]. What object does g.sum() return?
  1. A Series with one total per team
  2. A DataFrame with an items column
  3. A DataFrame with every original row
  4. A Series with every original row
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A DataFrame has index labels a, b, c and amounts 5, 8, 12. A key Series has labels c and a with values "R" and "S". With dropna=False, what grouped sums result?
  1. R 5; S 8; missing 12
  2. R 12; S 13; no missing group
  3. R 12; S 5; missing 8
  4. R 17; S 8; no missing group
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A single group contains one recorded value, 11. What does its default grouped std() return?
  1. 0.0
  2. 11.0
  3. 1.0
  4. NaN
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Two inspections record defect flags True, False for plant A and True, True, False, False, False, False for plant B. What fraction of all inspected items is defective?
  1. 3/8
  2. 1/2
  3. 5/12
  4. 1/3
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

Which implementation returns the fraction of readings at least 16 in each group without a Python function per group?
  1. df.groupby("batch")["reading"].mean() >= 16
  2. df.assign(hit=df["reading"] >= 16).groupby("batch")["hit"].sum()
  3. df.assign(hit=df["reading"] >= 16).groupby("batch")["hit"].mean()
  4. df.groupby("batch")["reading"].count() / len(df)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Rows are A:4, B:9, A:12, B:3 for group and amount. A new column must show each row’s share of its own group’s total. What values appear in row order?
  1. 0.25, 0.25, 0.75, 0.75
  2. 1/7, 9/28, 3/7, 3/28
  3. 0.5, 0.5, 0.5, 0.5
  4. 0.25, 0.75, 0.75, 0.25
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Unsorted events are U at step 2 with value 15, V at step 1 with 8, and U at step 1 with 10. After sorting by step, what grouped difference belongs to U’s step-2 row, and why?
  1. −5; use the next U value
  2. 5; subtract U’s step-1 value
  3. 7; subtract the preceding V value
  4. 15; restart at each event
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Fixed bands must include 0 and 100 and place 50 in the lower of two bands. What call fits?
  1. pd.cut(x, [0, 50, 100], right=False)
  2. pd.cut(x, [0, 50, 100], include_lowest=True)
  3. pd.cut(x, [0, 50, 100])
  4. pd.cut(x, [0, 50, 101], right=False)
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Sorted values are 4, 8, 12, 24, 40. What is the 0.6 quantile with pandas’ default interpolation?
  1. 16.8
  2. 24.0
  3. 19.2
  4. 12.0
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A mean pivot table has two occupied cells in a row: one averages 10 from 1 observation; the other averages 30 from 3 observations. All values and keys are recorded. What is that row’s mean margin?
  1. 20
  2. 40
  3. 25
  4. 30
Show answerHide answer

Save this lesson to see this answer.

Set 5: Diagnose grouped analyses and comparisons10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

Amounts are 7 and 11 under keys A and B, plus 6 with a missing key. The key is categorical with an unused C category. Which settings preserve the total 24 and also show C?
  1. dropna=True, observed=False
  2. dropna=False, observed=True
  3. dropna=True, observed=True
  4. dropna=False, observed=False
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

In pandas 3, a group has values 2 and 6. Why can .agg("std") and .agg(np.std) give different results?
  1. The string call uses a sample divisor; NumPy uses a population divisor.
  2. The string call uses a population divisor; NumPy uses a sample divisor.
  3. The string call rounds input values; NumPy preserves input values.
  4. The string call calculates variance; NumPy calculates standard deviation.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

One station has readings 2 and 14, and another has 9, 9, and 9. You need all original rows from stations whose mean exceeds 8. What should remain?
  1. Only the 14 row from the first station
  2. All five rows from both stations
  3. All three rows from the second station
  4. One summary row for the second station
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Since pandas 3.0, where can a function passed to DataFrame grouped apply read its current group key?
  1. g.columns
  2. g.name
  3. g.index.name
  4. g.shape
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A report bins study hours and shows mean scores 60 and 85 with counts 20 and 2. What conclusion is supported by these results?
  1. Extra study caused a 25-point rise for each student.
  2. The upper band is more reliable because its mean is higher.
  3. All students in the upper band scored above all others.
  4. Means differ; the upper mean rests on only two scores.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A crosstab has departments in rows and outcomes in columns. Department J has pass 18, fail 6; K has pass 12, fail 4. What is J’s share among failures, and what is its within-department failure rate?
  1. 60% and 25%
  2. 25% and 60%
  3. 75% and 60%
  4. 60% and 75%
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A team uses apply(lambda s: s - s.mean()) on a grouped numeric Series, then resets the result’s index and assigns its values by position to the original unsorted table. Why can the new column be wrong?
  1. The calculation uses an overall mean instead of group means.
  2. Resetting the index changes all deviations to group totals.
  3. Groupwise assembly can attach values to the wrong input rows.
  4. An apply result always drops the first observation from every group.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A custom aggregation uses len(s) on values 5, missing, 7. What does it return, and what does that number measure?
  1. 2; recorded values
  2. 3; recorded values
  3. 2; rows in the group
  4. 3; rows in the group
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Group A has values 2, missing, 8; group B has 20, missing, 40. After filling from each group’s transformed mean, what is the mean of the six completed values?
  1. 17.5
  2. About 11.667
  3. 20.0
  4. 15.0
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A mean pivot cell has no observations. Why can fill_value=0 mislead a reader?
  1. It counts the empty cell as one new input row.
  2. It represents an unobserved average as a measured zero.
  3. It removes the entire category from the table.
  4. It changes all nonempty means into totals.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

68 Key Terms, each with its definition

A

Aggregation
An aggregation reduces a group of observations to a summary value per selected column, such as a sum, count, or mean.
An aggregation of order quantities by warehouse gives one total quantity for each warehouse.
Aggregation dictionary
An aggregation dictionary maps DataFrame input columns to functions, allowing different summaries for different measures.
An aggregation dictionary can request a sum for units and both a mean and a maximum for duration.
Aggregation function
An aggregation function determines how a pivot cell combines its observations, such as through a mean, sum, or count.
The aggregation function changes a repeated-key cell from average revenue to total revenue when set to sum.
Apply
Grouped apply runs a function on each group and combines scalar, Series, or DataFrame outputs into one result.
Apply can calculate a correlation from two measured columns inside each class group’s observations.
Association
An association is an observed relationship between variables, such as changing group means across bins, without establishing a cause.
An association between study-hour bands and mean scores can also reflect other differences between students.

B

Bin edge
A bin edge is a boundary between or around intervals; neighboring edges define the possible ranges for bin assignments.
A bin edge at 50 separates two score ranges, with membership at 50 decided by the closure rule.
Binning
Binning converts numeric observations into interval categories, allowing ranges of values to act as grouping labels.
Binning delivery durations into fixed time ranges makes a monthly frequency report easier to compare.
Boolean mean
A Boolean mean is the average of True and False values interpreted as 1 and 0, giving the proportion that are True.
A Boolean mean of defect flags gives each batch’s defective-item fraction instead of its defect count.
Broadcasting
Broadcasting repeats a scalar group result across the group’s rows, making it available for row-level calculations.
Broadcasting a group total through transform gives every row the denominator for its own share.
Bucket analysis
Bucket analysis summarizes one variable within numeric bands of another, often reporting counts and means for each band.
Bucket analysis compares average exam scores among students in different fixed study-hour ranges.

C

Callable
A callable is a function or similar object that pandas can invoke on grouped values, using that object’s own calculation rules.
A callable such as np.std can use a different default divisor from the pandas string function "std".
Column proportion
A column proportion divides a cell count by its column total, describing the cell’s row category within that column population.
A column proportion in a plan-by-device table gives the basic-plan share among all phone users.
Cross-tabulation
A cross-tabulation is a table of frequencies for combinations of categorical variables, also called a contingency table.
A cross-tabulation of plan by device counts how many users belong to each plan-and-device combination.
Cumulative sum
A grouped cumulative sum is a running total that follows the current row order and starts again for each group.
The cumulative sum of units sold restarts when tracking a different region’s sequence of orders.
Custom aggregation
A custom aggregation is a user-written function that receives one group’s Series and returns a useful summary value.
A custom aggregation can report a group’s largest value minus its smallest value as a range.

D

Degrees of freedom
The degrees of freedom are the independent pieces of information available for estimating spread; sample variance uses one fewer than the recorded count.
With three recorded readings, the degrees of freedom for the default sample variance are two.
Dense rank
A dense rank assigns equal values the same rank and gives the next distinct value the next integer, without a gap.
With descending dense rank, two equal top readings receive rank 1 and the next lower reading receives rank 2.
Distinct count
A distinct count measures how many different values occur in a group; pandas nunique() excludes missing values by default.
A distinct count of products per region shows how many product types each region has sold.
Duplicate key combination
A duplicate key combination occurs when several rows share the row and column keys that would identify one cell in a pivot.
A duplicate key combination needs aggregation through pivot_table before it can occupy one numeric cell.

E

Equal-width bins
Equal-width bins divide a numeric range into intervals of the same width, without requiring equal observation counts.
Equal-width bins can place most deliveries in the first interval when a few delays are extremely long.

F

Fill value
A fill value replaces missing result cells with a chosen display value, which should express the meaning of the absence correctly.
A fill value of zero can describe no orders in a count table but misrepresent an unobserved average.
Filtration
A filtration retains selected original rows or groups, preserving their row labels instead of replacing them with summaries.
A filtration can keep every order from regions that have at least three orders in the dataset.
Flat summary table
A flat summary table keeps grouping keys as ordinary columns, with one row for each summarized key combination.
A flat summary table with site and total mass columns is convenient for a later merge on site.

G

Group filter
A group filter keeps or drops a whole group using a single Boolean decision, returning original rows for groups that pass.
A group filter retains all records from stations whose average measurement exceeds a reporting threshold.
Group function
A group function receives a group’s data and computes its result; grouped apply can give it multiple columns together.
A group function can sort all columns of each batch and return its two highest-quality records.
Group keys
Group keys identify returned pieces in a grouped result and can be added as an outer index level by apply.
Group keys above original row labels make it clear which region supplied each selected order.
GroupBy object
A GroupBy object holds grouping information and provides operations that compute results from the rows in each group.
A GroupBy object created for teams can later produce both item totals and average delivery times.
Grouped sample
A grouped sample draws observations separately within each group, using a specified row count or fraction for every group.
A grouped sample with n=1 includes one record from each nonempty region instead of risking omitted regions.
Grouping key
A grouping key assigns each row to a group; several keys assign rows according to their shared combination of values.
A grouping key based on material type places all aluminum records in the same analysis group.

H

Hierarchical columns
Hierarchical columns have multiple label levels, often pairing each measured variable with its aggregation function.
Hierarchical columns distinguish a units mean from a revenue mean when both statistics appear together.

I

Index alignment
Index alignment matches pandas objects by their index labels when combining or assigning values, including Series grouping keys.
Index alignment attaches a key labeled row 8 to data row 8, even if the key Series is displayed in another order.

L

Lagged value
A lagged value is an earlier observation shifted to a later row within the chosen sequence, separately for each group.
A lagged value lets each order compare its units with the previous order from that same region.
Lambda expression
A lambda expression defines a short anonymous Python function, often used for a compact custom group calculation.
A lambda expression can return the fraction of readings that meet a specified temperature threshold.
Linear interpolation
Linear interpolation estimates a value between neighboring observations by taking the corresponding fraction of their difference.
Linear interpolation can place a sample percentile between two scores even when neither score equals it.

M

Mapping
A mapping associates input labels or values with output keys, allowing several original categories to share a broader group.
A mapping from regions to zones can combine several regional quantities into one zone total.
Margin
A margin is a summary row or column computed from underlying observations using the pivot table’s aggregation function.
A mean margin weights occupied cells by their observation counts because it averages the underlying rows.
Median
The median is the middle of sorted recorded values, averaging the two middle values when the recorded count is even.
The median of grouped order amounts can be less affected by a single large order than their mean.
Missing key
A missing key is an absent grouping value that excludes a row by default or forms a separate group when dropna=False.
A missing key in the region column can explain why regional sums omit an otherwise recorded order.
MultiIndex
A MultiIndex is an index with several levels, allowing one row or column label to represent a combination of key values.
A region-and-product MultiIndex identifies a total by both where an order occurred and what it contained.

N

Named aggregation
Named aggregation specifies output names together with input columns and summary functions, producing clearly labeled results.
Named aggregation creates total_mass from a sum and max_temperature from a maximum in one report.
Non-missing count
A non-missing count measures how many recorded values a selected column has within a group, excluding its missing entries.
The non-missing count is three when a five-row batch contains only three recorded temperatures.
Normalization
Normalization converts frequency counts to proportions by dividing them by a chosen row, column, or grand total.
Normalization by columns compares plan membership separately among phone users and among laptop users.

O

Observed categories
Observed categories are categorical values actually present in the data, as opposed to declared categories without rows.
Observed categories alone appear by default when a categorical key is grouped in pandas 3.
Ordered categorical
An ordered categorical is a set of category values with an explicit sequence, such as the low-to-high order of numeric bins.
An ordered categorical keeps score labels fail, pass, merit, distinction in their meaningful sequence.
Overall proportion
An overall proportion divides a cell count by the grand total, describing that combination’s share of all observations.
An overall proportion of 0.2 means that the cell’s category combination accounts for 20% of the full table.

P

Pivot table
A pivot table aggregates value columns for combinations of row and column keys, displaying the results in a two-way grid.
A pivot table can display total units sold for every region-and-product combination in one report.
Predicate
A predicate is a function that returns a Boolean decision; a GroupBy filter predicate must give one decision per group.
A predicate using all() can require every reading in a group to meet the same quality condition.

Q

Quantile
A quantile locates a specified fractional position in sorted data; pandas can interpolate when that position falls between values.
The 0.5 quantile is a group’s median, while the 0.9 quantile marks a higher relative position.
Quantile analysis
Quantile analysis compares a measure across groups defined by quantile bins, such as lower and upper portions of a sample.
Quantile analysis can summarize session duration for customers in each quarter of purchase amounts.
Quantile bin
A quantile bin is an interval bounded by sample quantiles, intended to hold a chosen share of the sample’s observations.
A quantile bin for the upper quarter of customers can change its numeric limits in a later sample.
Quartile
A quartile is one of the quarter-position cut points of a distribution, commonly at probabilities 0.25, 0.5, and 0.75.
Sample quartile boundaries let qcut divide observations into four approximately equal-count groups.

R

Reference population
A reference population is the set of observations used for a comparison, such as all rows or the rows of one subgroup.
A reference population of one class can give a score a different relative label from the full student dataset.
Relative change
A relative change is a difference from the previous value divided by that previous value, expressed as a fraction.
A relative change of 0.15 means a 15% increase from the preceding observation in the same group.
Right-closed interval
A right-closed interval includes its upper endpoint; the default cut intervals exclude the left endpoint and include the right.
The right-closed interval (20, 40] contains a value of 40 but excludes a value of 20.
Row count
A row count measures the number of observations in a group, including observations with missing values in measured columns.
The row count stays at five even when two of a batch’s five temperature readings are missing.
Row proportion
A row proportion divides a cell count by its row total, describing the cell’s column category within that row population.
A row proportion in a plan-by-device table gives the phone share among users on the basic plan.

S

Sample standard deviation
The sample standard deviation measures spread around a mean using a divisor of one less than the recorded observation count.
A group with one recorded reading has missing sample standard deviation under the pandas default.
Scalar result
A scalar result is one value returned for a group, which grouped apply combines into a Series indexed by group keys.
A scalar result from each region’s price calculation gives a single regional price per unit.
Split-apply-combine
Split-apply-combine is a pattern that groups matching rows, processes each group separately, and assembles their results.
Split-apply-combine turns a table of individual orders into one total quantity for each region.

T

Tie
A tie occurs when observations have equal values; keeping ties together can make quantile-bin counts unequal.
A tie at a sample quartile can move several equal observations into one interval and leave unequal counts.
Top-n selection
A top-n selection keeps a chosen number of the highest-valued rows per group after ordering by the measured variable.
A top-n selection of two orders per region can use a descending revenue sort followed by grouped head(2).
Transformation
A grouped transformation produces results with the input length and index, allowing group information to accompany each row.
A transformation repeats a region’s total on its order rows so each order can receive a regional share.

U

Unstack
Unstack is an operation that moves an index level into columns, turning indexed combinations into a wider table.
Unstack changes product labels in a grouped index into columns beside each region’s totals.
Unused category
An unused category is a declared categorical value that has no observations in the current dataset but can appear in a summary.
An unused category for a warehouse keeps its place in a report when observed=False is chosen.

W

Weighted mean
A weighted mean gives observations different influence according to specified weights, such as the units in each order.
A weighted mean of order prices using unit counts equals total revenue divided by total units.
Within-group deviation
A within-group deviation is a value minus its own group’s mean, showing how far it lies above or below that average.
A positive within-group deviation marks an order with revenue above the average for its region.
Within-group rank
A within-group rank describes a value’s position relative to other values in its own group, using a chosen tie rule.
A descending within-group rank gives each region’s largest order rank 1 without moving any rows.
Within-group z-score
A within-group z-score expresses a value’s deviation from its group mean in units of that group’s standard deviation.
A within-group z-score can show a relatively high reading in one lab even when its absolute value is modest.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started