一、分析目的:
(1)明确数据集中每个属性的含义;
(2)选择合适的方法处理数据集中的缺失值;
(3)判断哪些属性需要规范化,选择合适的方法对这些属性进行数据规范化;
(4)判断哪些属性可以离散化,选择合适的方法对这些属性进行数据离散化;
(5)将数据集的前70%作为训练集,剩余的30%作为测试集(去掉包含缺失值的样本)。对训练集分别随机抽取10%,30%,50%和80%的样本作为训练子集,利用训练子集训练线性回归模型,然后在测试集上预测房价属性。以MSE作为评估指标,观察不同采样率下模型性能的变化;
(6)结合数据集的现实背景,思考能否优化以上步骤,使这些步骤更符合实际情况?
二、属性含义
导入数据集,打印相关信息和前五行,如下图所示:
从图中可以看出,该数据集共有十个属性,分别为longitude(经度), latitude(维度), housing_median_age(房子年龄中位数), total_rooms(总房间数), total_bedrooms(总卧室数), population(人口数), households(家庭数), median_income(收入中位数), median_house_value(房价中位数), ocean_proximity(海洋临近度)。
其中,前九个属性均为float64类型,而最后一个属性为str类型。前九个均为数值属性,最后一个为标称属性。只有total_bedrooms存在缺失值。使用.value_counts()打印ocean_proximity属性的所有取值统计,如下图所示:
从图中看出,ocean_proximity属性总共有五种取值,分别为<1H OCEAN(小于1H车程), INLAND(内陆), NEAR OCEAN(临近海洋), NEAR BAY(临近海湾), ISLAND(海岛)。其中大部分地区靠近海洋或海湾,有6551位于内陆而5个在海岛上。
三、处理缺失值
使用data.isna().any()查看每列是否有缺失值,结果如下:
只有total_bedrooms存在缺失值。使用data['total_bedrooms'].describe()查看数据分布并使用.hist()绘制直方图可视化数据分布,结果如下所示:
从中发现,total_bedrooms属性的最大值为6445而最小值为1,数据分布十分不均匀,于是决定使用众数填充缺失值。填充之后再次使用data.isna().any()查看,显示已没有缺失值。
四、数据规范化
分析哪些数据需要进行规范化。使用.host()对所有属性进行可视化,结果如下所示:
打印数值属性相关统计如下所示:
结合两图分析得出:1)longitude和latitude为经纬度,区间范围较小且变化不大;2)housing_median_age变化范围为[1, 52],适合使用等宽离散化将数据划入[0, 10), [10, 20), [20, 30), [30, 40), [40, 50), [50, 60)的区间;3)total_rooms, total_bedrooms, population, households, median_income这些属性,最大值最小值相差较大且五个属性的取值范围相差较大,所以需要对这五个属性进行规范化。
选择使用最小-最大规范化,规范化后打印相关信息如下:
从图中可以看出相关属性的范围已经转变到[0, 1]之间。
实现代码如下所示:
# 最小最大规范化
selected_attributes = data.iloc[:, 3:8]
min_value = selected_attributes.min()
max_value = selected_attributes.max()
selected_attributes_normalized = (selected_attributes - min_value) / (max_value - min_value)
data.iloc[:, 3:8] = selected_attributes_normalized
print(data. Describe())
五、数据离散化
对longitude, latitude和housing_median_age进行等宽离散化,将数据划入新区间并重新打上标签。打印离散化后数据出现频次:
从中看出,只有housing_median_age分布较均匀,其余两个属性分布并不均匀。
此外,ocean_proximity属性本来就是离散值,使用one-hot编码进行处理,编码后打印数据集前五行如下所示:
实现代码如下所示:
# 离散化
bins_age = [0, 10, 20, 30, 40, 50, 60]
labels_age = [1, 2, 3, 4, 5, 6]
data['housing_median_age'] = pd.cut(data['housing_median_age'], bins=bins_age, labels=labels_age)
# print(data['housing_median_age'].value_counts())
bins_longitude = [-125, -123, -121, -119, -117, -115, -113]
labels_longitude = [1, 2, 3, 4, 5, 6]
data['longitude'] = pd.cut(data['longitude'], bins=bins_longitude, labels=labels_longitude)
# print(data['longitude'].value_counts())
bins_latitude = [32, 34, 36, 38, 40, 42]
labels_latitude = [1, 2, 3, 4, 5]
data['latitude'] = pd.cut(data['latitude'], bins=bins_latitude, labels=labels_latitude)
# print(data['latitude'].value_counts())
data = pd.get_dummies(data,columns=['ocean_proximity'])
print(data. Head())
六、线性回归模型预测
把median_house_value作为目标量y,其余属性作为X,进行训练集测试集划分。使用不同采样率训练模型并进行预测,计算MSE并添加到mse_result列表中。最后打印出所有的MSE值和对应的采样率如下图所示:
对应代码如下所示:
X = data. Drop(columns='median_house_value')
y = data['median_house_value']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=48)
sample_sizes = [0.1, 0.3, 0.5, 0.8]
mse_results = []
for sample_size in sample_sizes:
X_sampled, _, y_sampled, _ = train_test_split(X_train, y_train, train_size=sample_size, random_state=48)
model = LinearRegression()
model. Fit(X_sampled, y_sampled)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
mse_results.append(mse)
for i, sample_size in enumerate(sample_sizes):
print(f"Sample Size {int(sample_size*100)}%: {mse_results[i]}")
七、优化
1. 观察图十三发现MSE值非常大,不利于观察分析。于是对median_house_value属性也进行最小最大规范化。改进后不同采样率MSE值如下所示:
在采样率为10%,30%,50%时,MSE仍然非常大,只有在采样率80%时,MSE比较小。
2. 可以加入一些特征选择或者是降维的步骤。如果发现某些属性和房价关联较小,可以舍去不进行考虑;如果发现某个属性可以由其他属性表示或者有某些关系,可以不考虑该属性。
八、总结与结论
1. 各属性含义:
2. total_bedrooms属性存在缺失值,而该属性分布不均匀,所以使用众数填充缺失值。
3. 对total_rooms, total_bedrooms, population, households, median_income和median_house_value这些属性进行最小最大规范化。
4. 对longitude,latitude和housing_median_age进行离散化,划入等间距的不同区间并重新赋值1,2,3...。对ocean_proximity进行one-hot编码。
5. 采样率越大,MSE越小。
6. 可以进行数据规约,对步骤进行优化。