Python
Pandas
DataFrame
value_counts
Data Analysis

Python Pandas Convert .value_counts output to dataframe

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

value_counts() returns a Series, which is often exactly what you want for quick inspection. But once the counts need to be merged, sorted with other columns, exported, or renamed cleanly, converting that result into a DataFrame is more practical. The main trick is knowing whether you want the counted values to become an index column or stay as an index.

Start with What value_counts() Actually Returns

Given a simple series:

python
1import pandas as pd
2
3s = pd.Series(["apple", "banana", "apple", "orange", "banana", "apple"])
4counts = s.value_counts()
5
6print(counts)
7print(type(counts))

The result is a Series where:

  • the unique values become the index
  • the counts become the series values

That structure is convenient for inspection, but it is less convenient when you want named columns.

Convert with reset_index

The most common conversion pattern is:

python
1import pandas as pd
2
3s = pd.Series(["apple", "banana", "apple", "orange", "banana", "apple"])
4
5df = s.value_counts().reset_index()
6df.columns = ["fruit", "count"]
7
8print(df)

This works because reset_index() turns the old index into a normal column. It is a good default when you want a clean table for later joins or exports.

A slightly cleaner version uses rename_axis and reset_index(name=...):

python
1df = (
2    s.value_counts()
3     .rename_axis("fruit")
4     .reset_index(name="count")
5)
6
7print(df)

This is often the nicest idiomatic form because the column names are assigned directly in the transformation.

Convert with to_frame When You Want to Keep the Index

Sometimes you want a DataFrame but still like the counted values as the index. In that case, use to_frame:

python
df = s.value_counts().to_frame(name="count")
print(df)

This gives you a one-column DataFrame named count, with the unique values still living in the index.

That is useful when you plan to preserve index semantics or join on the index later.

Work with Value Counts from a DataFrame Column

The same techniques apply when the counted data comes from a DataFrame column:

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "city": ["Paris", "Berlin", "Paris", "Rome", "Berlin", "Paris"]
5})
6
7counts_df = (
8    df["city"]
9    .value_counts()
10    .rename_axis("city")
11    .reset_index(name="count")
12)
13
14print(counts_df)

Once the counts are in a DataFrame, you can merge them back into other tables, write them to CSV, or add computed percentages.

Add Percentages and Other Derived Columns

Converting to a DataFrame becomes especially helpful when you need more than one output column.

python
1counts_df = (
2    df["city"]
3    .value_counts()
4    .rename_axis("city")
5    .reset_index(name="count")
6)
7
8total = counts_df["count"].sum()
9counts_df["percent"] = counts_df["count"] / total * 100
10
11print(counts_df)

That kind of extension is one reason to convert early when the counts are headed into reporting logic.

Count Missing Values Intentionally

By default, value_counts() excludes missing values. If you want them included, pass dropna=False before converting.

python
1import pandas as pd
2
3s = pd.Series(["apple", None, "apple", "banana", None])
4
5df = (
6    s.value_counts(dropna=False)
7     .rename_axis("fruit")
8     .reset_index(name="count")
9)
10
11print(df)

This matters in diagnostics and data-quality reporting because missing values can be analytically important.

Common Pitfalls

  • Forgetting that value_counts() returns a Series, not a two-column DataFrame.
  • Calling reset_index() and leaving generic column names such as index and 0.
  • Using to_frame() when the downstream step actually needs the counted values as normal columns.
  • Forgetting dropna=False when missing values should be counted explicitly.
  • Overcomplicating the conversion when rename_axis(...).reset_index(name=...) already gives a clean result.

Summary

  • 'value_counts() returns a Series with unique values in the index.'
  • Use reset_index when you want a normal two-column DataFrame.
  • Use to_frame when you want a one-column DataFrame while keeping the index.
  • Name the columns explicitly so the result is ready for joins and exports.
  • Include missing values deliberately with dropna=False when data quality matters.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.