Track both count and running sum per category in a single loop, then derive the mean from those two accumulators. With pandas, .agg(['count', 'mean']) applies both aggregations at once and returns a DataFrame with one column per aggregation — avoiding the need to loop twice or store two separate dicts.

By hand

One loop over zip(cats, vals) fills both counts and totals. A second loop over sorted keys builds result as a {cat: (count, mean)} dict.

naive.py
cats = ['a', 'b', 'a', 'c', 'b', 'a']
vals = [10, 20, 30, 40, 50, 60]
counts = {}
totals = {}
for cat, val in zip(cats, vals):
    counts[cat] = counts.get(cat, 0) + 1
    totals[cat] = totals.get(cat, 0) + val
result = {}
for k in sorted(counts):
    result[k] = (counts[k], round(totals[k] / counts[k], 2))
print('RESULT:', result)

With pandas

df.groupby('cat')['val'].agg(['count', 'mean']) returns a DataFrame indexed by category with count and mean columns. The snapshot shows the columns, index, and each aggregation's values before the final result dict.

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

cats = ['a', 'b', 'a', 'c', 'b', 'a']
vals = [10, 20, 30, 40, 50, 60]
df = pd.DataFrame({'cat': cats, 'val': vals})
agg = df.groupby('cat')['val'].agg(['count', 'mean'])
result = {
    k: (int(agg.loc[k, 'count']), round(float(agg.loc[k, 'mean']), 2))
    for k in sorted(agg.index)
}
print('columns:', agg.columns.tolist())
print('index:', sorted(agg.index.tolist()))
print('count:', [int(agg.loc[k, 'count']) for k in sorted(agg.index)])
print('mean:', [round(float(agg.loc[k, 'mean']), 2) for k in sorted(agg.index)])
print('RESULT:', result)
columns: ['count', 'mean']
index: ['a', 'b', 'c']
count: [3, 2, 1]
mean: [33.33, 35.0, 40.0]
RESULT: {'a': (3, 33.33), 'b': (2, 35.0), 'c': (1, 40.0)}

Implementation notes

  • .agg(['count', 'mean']) returns a DataFrame (not a Series), because there is more than one aggregation result per group. The columns are the aggregation names; the index is the group keys.
  • Passing a dict to .agg allows renaming and mixing aggregations per column: df.groupby('cat').agg({'val': ['sum', 'mean'], 'score': 'max'}).
  • int() and float() convert numpy scalars to Python natives for stable repr. agg.loc[k, 'count'] is np.int64; agg.loc[k, 'mean'] is np.float64 — both need conversion for a clean RESULT.
  • Cross-reference: group-mean (python-data-basics) for the pure-Python mean-from-accumulators version; groupby-mean (this chapter) for the single-aggregation pandas version.