Skip to content

TypeError: Cannot perform reduction 'mean' with string dtype

Have you ever asked Pandas for the average of a data frame and been told it can't be done?

weather = pd.DataFrame({'country': ['Norway', 'Norway', 'Peru'],
                        'city': ['Oslo', 'Bergen', 'Lima'],
                        'temp': [5.0, 8.0, 18.0]})

weather.mean()
TypeError: Cannot perform reduction 'mean' with string dtype

The short answer is that the data frame includes text columns, and there's no such thing as the mean of "Oslo" and "Bergen." Tell Pandas to skip them:

weather.mean(numeric_only=True)
temp    10.333333
dtype: float64

The same message, with 'median' or 'std' in place of 'mean', has the same cause and the same fix.

The groupby version says it differently

If you hit this while grouping, you'll see a different message:

weather.groupby('country').mean()
TypeError: dtype 'str' does not support operation 'mean'

It's the same problem, since groupby tries to average every column except the one you grouped by, and that includes city. resample and pivot_table go through the same machinery and produce the same wording.

numeric_only=True works here too, but in a groupby, I'd rather name the column I want:

weather.groupby('country')['temp'].mean()
country
Norway     6.5
Peru      18.0
Name: temp, dtype: float64

This is not just a workaround. Selecting the column says what question you're asking, it doesn't break when someone adds a column to the source data next month, and it doesn't waste time computing results you'll throw away. If you want different summaries for different columns, agg with named aggregations says all of it in one place:

weather.groupby('country').agg(temp=('temp', 'mean'),
                               cities=('city', 'count'))
         temp  cities
country              
Norway    6.5       2
Peru     18.0       1

Why sum works when mean does not

You might reasonably wonder why this fails when sum does not:

weather.sum()
country    NorwayNorwayPeru
city         OsloBergenLima
temp                   31.0
dtype: object

Adding strings in Python concatenates them, so a "sum" of text is defined, even if it's rarely useful. min and max work too, and give you alphabetical order. A mean requires dividing by a count, and a string can't be divided, so Pandas stops.

This also explains the older error messages you may find in search results. Pandas 2 attempted the sum first, and then failed trying to convert the glued-together text into a number, with a message like Could not convert ['NorwayNorwayPeru' 'OsloBergenLima'] to numeric. That's the text of both string columns, glued together. Pandas 3 knows the column is text before it starts, and says so.

When the numbers are text

The frustrating version of this error is on a column that obviously contains numbers:

sales = pd.read_csv(io.StringIO('region,revenue\nNorth,"$1,200"\nSouth,$850\n'))
sales['revenue'].mean()
TypeError: Cannot perform reduction 'mean' with string dtype

Check the dtypes:

sales.dtypes
region     str
revenue    str
dtype: object

The dollar signs and thousands separators made read_csv treat revenue as text. numeric_only=True would silently skip the column you care about, so here the fix is to clean the text and convert it:

sales['revenue'].str.replace(r'[$,]', '', regex=True).astype(float).mean()
np.float64(1025.0)

When a column you expected to be numeric shows up as str, look for currency symbols, commas, percent signs, footnote markers, and placeholders like "n/a". Real-world data sources are full of them. For thousands separators alone, read_csv(..., thousands=',') handles it at load time.

Practice

See mean in Pandas and groupby in Pandas for averages on real data, and to_numeric in Pandas for cleaning numbers stored as text. Then try the groupby exercise.