从load_boston移除到数据源直连:高版本Python加载波士顿房价数据的替代方案解析
1. 为什么load_boston被移除了?
如果你最近在用Python 3.11或者更高版本的scikit-learn做机器学习项目,可能会发现一个奇怪的现象:以前常用的 load_boston() 函数突然报错了。这不是你的代码写错了,而是scikit-learn在1.2版本中主动移除了这个函数。
背后的原因其实很有意思。波士顿房价数据集是机器学习领域最经典的数据集之一,从1978年发布以来一直被广泛使用。但近年来,数据科学社区发现这个数据集存在一个严重的伦理问题——它包含了一个名为"B"的变量,这个变量实际上反映了社区的种族构成比例。原始研究假设这个因素会影响房价,这种假设本身就带有种族歧视的色彩。
scikit-learn维护团队经过讨论后决定,除非是专门研究机器学习伦理问题的场景,否则不应该继续使用这个数据集。这也是为什么在1.2版本后,你直接调用 load_boston() 会收到一个明确的错误提示,而不是默默地加载数据。
2. 官方推荐的替代方案
既然官方不建议使用波士顿房价数据集了,那我们应该用什么数据来做回归分析的练习呢?scikit-learn官方文档给出了两个不错的替代选择:
2.1 加州房价数据集
这是scikit-learn现在主推的回归分析数据集,使用方法非常简单:
from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing()
X = housing.data
y = housing.target
这个数据集包含了1990年加州人口普查中的房价信息,特点是:
- 样本量更大:20640条记录
- 特征更丰富:8个特征维度
- 没有伦理争议
- 数据更新:相比波士顿数据集晚了十几年
我实测下来发现,这个数据集做回归分析的效果其实比波士顿数据集更好,因为样本量更大,特征工程的空间也更广。
2.2 Ames房价数据集
如果你想要一个更接近波士顿数据集规模的选择,可以试试Ames数据集:
from sklearn.datasets import fetch_openml
housing = fetch_openml(name="house_prices", as_frame=True)
这个数据集包含了2011年爱荷华州Ames市的房价信息,特点是:
- 样本量适中:2930条记录
- 特征详细:80个特征维度
- 包含更多现代房屋特征
- 需要从OpenML平台下载
不过要注意,这个数据集返回的是Pandas DataFrame格式,如果你习惯用NumPy数组,需要额外做转换。
3. 如何继续使用波士顿数据集
我知道有些教学场景还是需要用到波士顿数据集,毕竟那么多教材和教程都是基于它写的。如果你确实需要使用这个数据集,官方也提供了从原始来源直接加载的方法:
import pandas as pd
import numpy as np
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
这段代码看起来有点复杂,我来解释下:
- 数据来自卡内基梅隆大学的统计库
- 原始数据是固定宽度的文本格式
- 需要跳过前22行说明文字
- 特征数据和目标值被交替存储,所以需要特殊处理
我建议把这部分代码封装成一个函数,方便重复使用:
def load_boston_alternative():
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
return data, target
4. 不同方案的对比与选择
面对这么多选择,到底该用哪个呢?我整理了一个对比表格帮你决策:
| 方案 | 数据来源 | 样本量 | 特征数 | 伦理风险 | 加载速度 | 适用场景 |
|---|---|---|---|---|---|---|
| 原load_boston | sklearn内置 | 506 | 13 | 高 | 快(已移除) | 不推荐 |
| 加州房价 | sklearn内置 | 20640 | 8 | 无 | 快 | 推荐首选 |
| Ames房价 | OpenML | 2930 | 80 | 无 | 慢(需下载) | 复杂分析 |
| 原始URL | CMU统计库 | 506 | 13 | 高 | 中等 | 必须用原数据时 |
根据我的经验,如果是教学演示,加州房价数据集完全够用;如果是真实项目,Ames数据集可能更有价值;只有当你必须复现旧代码时,才考虑从原始URL加载波士顿数据。
5. 迁移现有代码的实用技巧
如果你手头已经有基于波士顿数据集的代码,迁移到新数据集需要注意几个关键点:
- 特征名称变化:新数据集的列名完全不同,需要调整特征选择代码
- 数据规模差异:加州数据集大了40倍,可能需要调整测试集比例
- 数据分布不同:新数据的目标值范围需要重新探索
- 模型评估标准:误差范围可能需要重新设定
这里提供一个迁移示例,把原来的波士顿代码适配到加州数据集:
# 原波士顿代码
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
boston = load_boston()
X, y = boston.data, boston.target
model = LinearRegression().fit(X, y)
# 迁移后的加州代码
from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing()
X, y = housing.data, housing.target
model = LinearRegression().fit(X, y)
看起来改动不大,但实际使用中你可能需要:
- 调整可视化代码的坐标轴范围
- 修改特征工程的管道
- 重新调参优化模型
我在迁移自己的项目时发现,加州数据集对线性回归的挑战更大,因为特征间相关性更强,可能需要引入正则化。
6. 常见问题与解决方案
在实际操作中,你可能会遇到这些问题:
问题1 :从原始URL加载的数据没有特征名怎么办?
解决方案:可以手动添加特征名列表:
feature_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM',
'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT']
df = pd.DataFrame(data, columns=feature_names)
问题2 :加州数据集加载速度慢?
解决方案:第一次加载会下载约2MB的数据,可以缓存到本地:
from sklearn.datasets import fetch_california_housing
from joblib import Memory
memory = Memory(location='./cache')
fetch_california_housing_cached = memory.cache(fetch_california_housing)
housing = fetch_california_housing_cached()
问题3 :Ames数据集太大,内存不够?
解决方案:可以只加载部分特征:
housing = fetch_openml(name="house_prices", as_frame=True)
selected_features = ['LotArea', 'OverallQual', 'YearBuilt', 'TotRmsAbvGrd']
X = housing.data[selected_features]
y = housing.target
7. 最佳实践建议
经过多次项目实践,我总结出几个经验:
- 新项目一律使用加州或Ames数据集,避免伦理风险
- 教学场景可以继续使用波士顿数据,但要说明其历史背景
- 从原始URL加载时,建议添加异常处理:
try:
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
except Exception as e:
print(f"加载失败: {e}")
# 备用方案
data_url = "备用镜像URL"
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
- 对数据做探索性分析时,特别注意检查特征间的相关性
- 考虑数据集的时效性,加州数据是1990年的,对现代房价预测可能不够准确
8. 更深入的数据探索
如果你不满足于基本用法,可以尝试这些进阶操作:
获取完整的数据描述 :
print(housing.DESCR) # 加州数据集
print(fetch_openml(name="house_prices", as_frame=True).DESCR) # Ames数据集
转换为Pandas DataFrame并添加目标列 :
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target
可视化特征分布 :
import seaborn as sns
import matplotlib.pyplot as plt
sns.pairplot(df[['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'MedHouseVal']])
plt.show()
创建交互式可视化 :
import plotly.express as px
fig = px.scatter_3d(df, x='MedInc', y='AveRooms', z='MedHouseVal',
color='HouseAge', opacity=0.7)
fig.show()
这些技巧能帮你更深入地理解数据,为后续建模打下更好基础。
更多推荐
所有评论(0)