Split a table of rows into groups by a category column, then compute the mean of a value column within each group. Groupby-mean is one of the most common one-liner operations in data analysis.

By hand

Maintain two dicts: totals accumulates the sum per category, counts accumulates the row count. After the loop, divide to get the mean for each category. Sort the keys before printing so the output is deterministic.

naive.py
Replay: real traced execution (multi-file project)
cats = ['a', 'b', 'a', 'b', 'a', 'b']
vals = [10, 20, 30, 40, 50, 60]
totals = {}
counts = {}
for cat, val in zip(cats, vals):
    totals[cat] = totals.get(cat, 0) + val
    counts[cat] = counts.get(cat, 0) + 1
means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
print('RESULT:', means)
  1. cats ← ['a', 'b', 'a', 'b', 'a', 'b']

    1cats = ['a', 'b', 'a', 'b', 'a', 'b']2vals = [10, 20, 30, 40, 50, 60]
    values this step['a', 'b', 'a', 'b', 'a', 'b']cats
  2. vals ← [10, 20, 30, 40, 50, 60]

    1cats = ['a', 'b', 'a', 'b', 'a', 'b']2vals = [10, 20, 30, 40, 50, 60]3totals = {}
    values this step[10, 20, 30, 40, 50, 60]vals
  3. totals ← {}

    2vals = [10, 20, 30, 40, 50, 60]3totals = {}4counts = {}
    values this step{}totals
  4. counts ← {}

    3totals = {}4counts = {}5for cat, val in zip(cats, vals):
    values this step{}counts
  5. cat ← 'a', val ← 10

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'a'cat10val
  6. totals ← {'a': 10}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{} {'a': 10}totals
  7. counts ← {'a': 1}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{} {'a': 1}counts
  8. cat ← 'b', val ← 20

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'a' 'b'cat10 20val
  9. totals ← {'a': 10, 'b': 20}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{'a': 10} {'a': 10, 'b': 20}totals
  10. counts ← {'a': 1, 'b': 1}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{'a': 1} {'a': 1, 'b': 1}counts
  11. cat ← 'a', val ← 30

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'b' 'a'cat20 30val
  12. totals ← {'a': 40, 'b': 20}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{'a': 10, 'b': 20} {'a': 40, 'b': 20}totals
  13. counts ← {'a': 2, 'b': 1}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{'a': 1, 'b': 1} {'a': 2, 'b': 1}counts
  14. cat ← 'b', val ← 40

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'a' 'b'cat30 40val
  15. totals ← {'a': 40, 'b': 60}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{'a': 40, 'b': 20} {'a': 40, 'b': 60}totals
  16. counts ← {'a': 2, 'b': 2}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{'a': 2, 'b': 1} {'a': 2, 'b': 2}counts
  17. cat ← 'a', val ← 50

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'b' 'a'cat40 50val
  18. totals ← {'a': 90, 'b': 60}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{'a': 40, 'b': 60} {'a': 90, 'b': 60}totals
  19. counts ← {'a': 3, 'b': 2}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{'a': 2, 'b': 2} {'a': 3, 'b': 2}counts
  20. cat ← 'b', val ← 60

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
    values this step'a' 'b'cat50 60val
  21. totals ← {'a': 90, 'b': 120}

    5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 1
    values this step{'a': 90, 'b': 60} {'a': 90, 'b': 120}totals
  22. counts ← {'a': 3, 'b': 3}

    6    totals[cat] = totals.get(cat, 0) + val7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}
    values this step{'a': 3, 'b': 2} {'a': 3, 'b': 3}counts
  23. for cat, val in zip(cats, vals):

    4counts = {}5for cat, val in zip(cats, vals):6    totals[cat] = totals.get(cat, 0) + val
  24. means ← {'a': 30.0, 'b': 40.0}

    7    counts[cat] = counts.get(cat, 0) + 18means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}9print('RESULT:', means)
    values this step{'a': 30.0, 'b': 40.0}means
  25. stdout ← RESULT: {'a': 30.0, 'b': 40.0}

    8means = {cat: totals[cat] / counts[cat] for cat in sorted(totals)}9print('RESULT:', means)
    values this stepRESULT: {'a': 30.0, 'b': 40.0}stdout

With Pandas

pd.DataFrame loads the list of dicts into a typed table. groupby('cat') partitions the rows, ['val'] selects the column, and .mean() reduces each partition to its mean — all in one chain. The result is a Series indexed by category.

library.py
import pandas as pd
from dalib.display import set_display
set_display()

data = pd.DataFrame({
    'cat': ['a', 'b', 'a', 'b', 'a', 'b'],
    'val': [10, 20, 30, 40, 50, 60],
})
means = data.groupby('cat')['val'].mean()
result = {k: float(means[k]) for k in sorted(means.index)}
print('index:', sorted(means.index.tolist()))
print('values:', [float(means[k]) for k in sorted(means.index)])
print('dtype:', means.dtype)
print('RESULT:', result)
index: ['a', 'b']
values: [30.0, 40.0]
dtype: float64
RESULT: {'a': 30.0, 'b': 40.0}