---
title: "ValueError: could not convert string to float — fix your data, not your code"
description: "This error means one cell in your data is not a number. Learn how to find the exact bad row in pandas and clean commas, currency symbols, percent signs and blanks for good."
url: https://articles.sythra.ai/articles/could-not-convert-string-to-float-fix
slug: could-not-convert-string-to-float-fix
author: "vaibhavkothari"
author_url: https://articles.sythra.ai/writers/vaibhavkothari
date_published: 2026-08-26T08:26:25.097Z
date_modified: 2026-08-29T10:22:15.966Z
topics: ["Python", "Pandas", "Machine Learning", "Errors"]
reading_time_minutes: 6
publisher: "Sythra"
publisher_url: https://sythra.ai
access: free
language: en
---

# ValueError: could not convert string to float — fix your data, not your code

> This error means one cell in your data is not a number. Learn how to find the exact bad row in pandas and clean commas, currency symbols, percent signs and blanks for good.

Source: https://articles.sythra.ai/articles/could-not-convert-string-to-float-fix · Author: vaibhavkothari · Published: 2026-08-26 · Reading time: 6 min · Topics: Python, Pandas, Machine Learning, Errors

`ValueError: could not convert string to float: '1,250'`

Python is telling you exactly what it choked on — look at the text in quotes at the end of the message. That is a real value from your data. In this case a thousands separator: `1,250` is a number to a human, and a string to Python.

This error is almost never a coding mistake. It is a **data** mistake, and the fastest fix is to find the bad rows first and clean them deliberately.

## Step 1 — Read the message properly

The value after the colon is your entire clue:

| Message ends with | What is in your data |
|---|---|
| `: '1,250'` | Thousands separator |
| `: '$45.00'` | Currency symbol |
| `: '12%'` | Percent sign |
| `: ''` | Empty cell |
| `: 'N/A'` or `: '-'` | Placeholder for missing |
| `: '12.5 kg'` | Unit stuck to the number |
| `: '1.234,56'` | European decimal format |

If the message ends with `: ''`, the cell is blank — the most common case of all when a CSV was exported from a spreadsheet.

## Step 2 — Find the guilty rows

Do not scroll through the file. Ask pandas which values fail to convert:

```python
import pandas as pd

df = pd.read_csv("sales.csv")

# to_numeric with errors="coerce" turns anything unconvertible into NaN
converted = pd.to_numeric(df["price"], errors="coerce")
bad_rows = df[converted.isna() & df["price"].notna()]

print(bad_rows[["price"]].head(20))
print("Bad values:", bad_rows["price"].unique()[:20])
```

That last line is the useful one. It prints the distinct offenders — usually three or four patterns, not three thousand unique problems. Now you know exactly what to clean.

## Step 3 — Clean the column

Strip the junk, then convert. Chain the replacements so the intent stays readable:

```python
df["price"] = (
    df["price"]
    .astype(str)
    .str.strip()                       # stray spaces
    .str.replace(",", "", regex=False)  # thousands separator
    .str.replace("$", "", regex=False)  # currency
    .str.replace("%", "", regex=False)  # percent
)

df["price"] = pd.to_numeric(df["price"], errors="coerce")
```

A more general version strips every character that is not a digit, dot, or minus sign:

```python
df["price"] = (
    df["price"].astype(str).str.replace(r"[^0-9.\-]", "", regex=True)
)
df["price"] = pd.to_numeric(df["price"], errors="coerce")
```

Careful with percentages: after removing `%`, the value `12` means `0.12`. Divide explicitly so nobody has to guess later:

```python
df["rate"] = pd.to_numeric(df["rate"].str.rstrip("%"), errors="coerce") / 100
```

## Step 4 — Decide what to do with the blanks

`errors="coerce"` converts the unfixable into NaN. You now have a decision to make, and it matters more than the cleaning itself:

```python
missing = df["price"].isna().sum()
print(f"{missing} missing out of {len(df)} rows")

# Option A — drop rows with no price
df = df.dropna(subset=["price"])

# Option B — fill with the median (robust to outliers)
df["price"] = df["price"].fillna(df["price"].median())

# Option C — keep them and flag it, so a model can learn from "missing"
df["price_missing"] = df["price"].isna().astype(int)
df["price"] = df["price"].fillna(df["price"].median())
```

Option C is usually the strongest for machine learning: missing data is often informative. A blank income field may say more than any imputed number would.

Never silently fill with `0`. A price of zero is a real, meaningful value, and pretending a missing price is free will quietly poison every model you train afterwards.

## Step 5 — Fix the same error in scikit-learn

If the traceback mentions `fit`, `transform`, or `StandardScaler`, the error comes from a text column that slipped into your feature matrix:

```python
print(df.dtypes)
print(df.select_dtypes(include="object").columns.tolist())
```

Any `object` column is text as far as scikit-learn is concerned. Categories must be encoded, not converted:

```python
X = pd.get_dummies(df[["price", "city", "category"]], drop_first=True)
```

One-hot encoding via `get_dummies` gives the model numbers it can use without inventing a fake order. Never map `{"low": 1, "medium": 2, "high": 3}` unless the order is genuinely real.

## Step 6 — Stop it happening on the next file

Tell pandas about your data's quirks while reading it, and the cleaning disappears:

```python
df = pd.read_csv(
    "sales.csv",
    thousands=",",                       # handles 1,250
    na_values=["", "N/A", "-", "NA", "null", "missing"],
    dtype={"zip_code": str},             # keep IDs as text, preserve leading zeros
)
```

That `dtype` line prevents the opposite bug: pandas reading a zip code of `07030` as the number `7030`.

For European files where `.` groups and `,` decimals:

```python
df = pd.read_csv("sales.csv", thousands=".", decimal=",")
```

## The checklist

1. Read the quoted value in the error — it names the problem
2. `pd.to_numeric(col, errors="coerce")` to find every bad row at once
3. Print `.unique()` on the bad values to see the real patterns
4. Strip symbols, then convert
5. Choose deliberately how to handle NaN — drop, fill, or flag
6. Add `thousands=` and `na_values=` to `read_csv` so the next load is clean

```remember
# Remember this
The quoted value in the error -> is the actual problem, read it first
`pd.to_numeric(col, errors="coerce")` -> finds every bad row at once
`col[converted.isna()].unique()` -> shows the real patterns behind them
---
Fix the data, not the code. Then add `thousands=` and `na_values=` to
`read_csv` so the next load is already clean.
```


## FAQ

### What causes ValueError: could not convert string to float?

A value in your data is text that Python cannot parse as a number — typically a comma separator, a currency symbol, a percent sign, a unit, or an empty cell. The offending value is printed at the end of the error message.

### How do I find which row causes the error in pandas?

Run `pd.to_numeric(df["col"], errors="coerce")`, then select rows where the result is NaN but the original was not null. Printing `.unique()` on those values shows the handful of patterns you actually need to clean.

### How do I convert a column with commas to float?

Use `df["col"].str.replace(",", "", regex=False)` and then `pd.to_numeric`, or pass `thousands=","` to `read_csv` so pandas handles it while loading.

### Should I fill missing numbers with zero?

No. Zero is a real value and will distort averages and model training. Use the median, or keep the NaN and add a separate 0/1 column marking that the value was missing.

### Why does scikit-learn raise this error during fit?

A text column is still in your feature matrix. Check `df.dtypes` for `object` columns and encode them with `pd.get_dummies` before training.

## Next reading on Sythra Articles

- [Clean a messy CSV with pandas](https://articles.sythra.ai/articles/clean-messy-csv-pandas)
- [Train your first machine learning model in 20 lines](https://articles.sythra.ai/articles/first-machine-learning-model-scikit-learn)
- [Stop memorizing Python syntax](https://articles.sythra.ai/articles/seven-python-patterns-for-ml-notebooks)

## Glossary (terms defined in this article)
- **NaN** (basic) — "Not a Number" — pandas' marker for a missing value
- **One-hot encoding** (medium) — Turning each category into its own 0/1 column
