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ặcdf['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.5trong dữ liệu của bạn, dùngvalue.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
.xlsxthường đã là float đúng kiểu. Khi không phải vậy, cùng quy trìnhstr.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.

