Fix Python ValueError: could not convert string to float '1,234' — Định dạng số theo ngôn ngữ

beginner🐍 Python2026-06-20| Python 3.x, pandas 1.x / 2.x, mọi hệ điều hành (Windows, Linux, macOS)

Error Message

ValueError: could not convert string to float: '1,234'
#python#float#string#pandas#xử-lý-dữ-liệu#locale

Lỗi Gặp Phải

ValueError: could not convert string to float: '1,234'

Bạn đang cố chuyển đổi một chuỗi số sang kiểu float — nhưng giá trị lại chứa dấu phẩy bên trong. Hàm float() của Python chỉ xử lý được các chuỗi thuần như '1234' hoặc '1234.56'. Bất kỳ chuỗi nào có dấu phân cách hàng nghìn đều gây ra lỗi ngay lập tức.

Lỗi này xảy ra khi bạn tải dữ liệu từ file CSV, Excel, kết xuất cơ sở dữ liệu, hoặc API — những nơi số được định dạng cho con người đọc: '1,234', '$1,234.56', hoặc '1.234,56' nếu nguồn dữ liệu dùng định dạng châu Âu.

Nguyên Nhân

Dấu phẩy trong '1,234' là dấu phân cách hàng nghìn, không phải dấu thập phân. Các vùng miền khác nhau định dạng số theo cách khác nhau:

  • Mỹ/Anh: 1,234.56 — dấu phẩy = hàng nghìn, dấu chấm = thập phân
  • Châu Âu (Đức/Pháp/...): 1.234,56 — dấu chấm = hàng nghìn, dấu phẩy = thập phân

Hàm float() của Python không biết dữ liệu của bạn dùng quy ước nào. Nó chỉ đơn giản là báo lỗi. Khi dữ liệu đến từ bảng tính, file xuất theo locale, hoặc đầu vào người dùng, những ký tự thừa này sẽ làm hỏng quá trình chuyển đổi mỗi lần.

Cách Sửa Từng Bước

Cách 1: Xóa dấu phẩy thủ công (đơn giản nhất)

Nguồn dữ liệu của bạn dùng định dạng Mỹ — dấu phẩy là phân cách hàng nghìn, dấu chấm là thập phân. Chỉ cần xóa nó đi:

value = '1,234'
result = float(value.replace(',', ''))
print(result)  # 1234.0

Có ký hiệu tiền tệ hoặc khoảng trắng thừa? Dùng nối tiếp các lệnh replace:

value = '$1,234.56'
result = float(value.replace(',', '').replace('$', '').strip())
print(result)  # 1234.56

Cách 2: Làm sạch cột pandas bằng str.replace + pd.to_numeric

Tình huống phổ biến nhất: một cột DataFrame được load với kiểu object thay vì float64. Làm sạch chỉ trong một dòng:

import pandas as pd

df = pd.DataFrame({'price': ['1,234', '5,678', '9,012']})

df['price'] = pd.to_numeric(df['price'].str.replace(',', '', regex=False))
print(df['price'])
# 0    1234.0
# 1    5678.0
# 2    9012.0
print(df.dtypes)
# price    float64

Cách 3: Truyền tham số thousands khi đọc CSV

Tốt hơn nữa — xử lý ngay lúc tải dữ liệu. Tham số thousands cho pandas biết dấu phân cách ngay từ đầu, để các cột số tự động ra kiểu float64:

import pandas as pd

df = pd.read_csv('data.csv', thousands=',')
print(df.dtypes)  # các cột số sẽ đã là float64

File định dạng châu Âu — nơi dấu phẩy là dấu thập phân — cần cả hai tham số:

df = pd.read_csv('data.csv', decimal=',', thousands='.')

Cách 4: Xử lý dữ liệu lộn xộn hoặc hỗn hợp với errors='coerce'

Dữ liệu thực tế thường rất lộn xộn. Một cột có thể chứa số hợp lệ, chuỗi rỗng, và nhãn như 'N/A' — tất cả cùng lúc. Thay vì bị crash ở những dòng lỗi, errors='coerce' chuyển đổi những gì có thể và biến phần còn lại thành NaN:

import pandas as pd

df = pd.DataFrame({'amount': ['1,234', 'N/A', '5,678', '', '9,012']})

df['amount'] = pd.to_numeric(
    df['amount'].str.replace(',', '', regex=False),
    errors='coerce'
)

print(df['amount'])
# 0    1234.0
# 1       NaN
# 2    5678.0
# 3       NaN
# 4    9012.0

Cách 5: Dùng module locale để phân tích theo locale chuẩn

Khi locale của nguồn dữ liệu đã biết và nhất quán, locale.atof() tự động xử lý các quy tắc dấu phân cách — không cần thao tác chuỗi thủ công:

import locale

# Định dạng Mỹ: '1,234' → 1234.0
locale.setlocale(locale.LC_NUMERIC, 'en_US.UTF-8')
result = locale.atof('1,234')
print(result)  # 1234.0

# Định dạng Đức: '1.234,56' → 1234.56
locale.setlocale(locale.LC_NUMERIC, 'de_DE.UTF-8')
result = locale.atof('1.234,56')
print(result)  # 1234.56

Lưu ý quan trọng: locale.setlocale() thay đổi cài đặt trên toàn bộ process và không an toàn khi dùng đa luồng. Trong ứng dụng web hoặc code bất đồng bộ, hãy dùng cách str.replace() tường minh thay thế.

Kiểm Tra Sau Khi Sửa

Kiểm tra nhanh cho một giá trị đơn lẻ:

value = '1,234'
result = float(value.replace(',', ''))
assert result == 1234.0, f"Kết quả không mong đợi: {result}"
print("OK:", result)  # OK: 1234.0

Với DataFrame, xác nhận kiểu dữ liệu đã chuyển sang numeric và đếm các giá trị NaN không mong muốn:

print(df['price'].dtype)          # float64
print(df['price'].isna().sum())   # 0  (hoặc số lượng dự kiến với các dòng thực sự thiếu)
print(df['price'].describe())     # kiểm tra nhanh min/max/mean

Mẹo Thêm

  • Kiểm tra dữ liệu thô trước: chạy df['col'].head(20) hoặc df['col'].unique()[:20] trước khi viết bất kỳ code làm sạch nào. Bạn cần biết chính xác những ký tự nào đang có — dấu phẩy, khoảng trắng, ký hiệu tiền tệ, dấu gạch ngang.
  • Dấu thập phân châu Âu: nếu '1,5' có nghĩa là 1.5 trong dữ liệu của bạn, dùng value.replace(',', '.'). Nhưng chỉ khi không có dấu phân cách hàng nghìn trong cùng cột — nếu không bạn sẽ âm thầm làm hỏng các giá trị như '1.234,56'.
  • File Excel: các số trong file .xlsx thường đã là float đúng kiểu. Khi không phải vậy, cùng quy trình str.replace() + pd.to_numeric() cũng hoạt động với kết quả từ pd.read_excel().
  • Sau khi làm sạch, xử lý NaN: nếu bạn dùng errors='coerce', hãy quyết định xem nên xóa các dòng đó (df.dropna(subset=['amount'])) hay điền giá trị thay thế (df['amount'].fillna(0)) trước khi xử lý tiếp.

Related Error Notes