24/9/6算法笔记 kaggle 房屋价格

预测模型主要分为两大类:

  1. 回归模型:当你的目标变量是连续的数值时,你会使用回归模型进行预测。回归模型试图找到输入特征和连续输出之间的关联。一些常见的回归模型包括:

    • 线性回归(Linear Regression)
    • 岭回归(Ridge Regression)
    • LASSO回归(LASSO Regression)
    • 弹性网回归(Elastic Net Regression)
    • 决策树回归(Decision Tree Regression)
    • 随机森林回归(Random Forest Regression)
    • 梯度提升回归(Gradient Boosting Regression)
    • XGBoost和LightGBM等基于树的模型
    • 支持向量回归(Support Vector Regression)
  2. 分类模型:当你的目标变量是离散的类别时,你会使用分类模型进行预测。分类模型试图找到输入特征和离散标签之间的关联。一些常见的分类模型包括:

    • 逻辑回归(Logistic Regression)
    • K最近邻分类(K-Nearest Neighbors Classification)
    • 支持向量机分类(Support Vector Machine Classification)
    • 决策树分类(Decision Tree Classification)
    • 随机森林分类(Random Forest Classification)
    • 梯度提升分类(Gradient Boosting Classification)
    • 神经网络分类(Neural Network Classification)

常见的离散类别实例:

  • 性别:男、女(有些情况下会考虑更多性别类别)。
  • 血型:A型、B型、AB型、O型。
  • 产品类型:手机、电脑、平板等。
  • 教育水平:小学、中学、大学等。
  • 天气状况:晴、阴、雨、雪等。

常见的连续数值实例:

  • 身高:一个人身高可以是1.75米,也可以是1.76米、1.75501米等等。
  • 温度:温度计可以测量从绝对零度到几千度的任意温度值。
  • 时间:时间可以精确到秒、毫秒、微秒等,并且可以在两个整点之间取任意值。
  • 重量:物体的重量可以在一定范围内取任意值,如50.5千克、55.375千克等。
  • 价格:商品的价格可以是连续的,如99.99美元。

我一共用了两种方法

下面是我参考李沐大神写的算法以及理解,他用的是神经网络,和k折线

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import torch
from torch import nn
from d2l import torch as d2l
import numpy as np
train_data = pd.read_csv("C:\\Users\\91144\\Desktop\\kaggle比赛数据\\房屋价格\\train.csv")
test_data = pd.read_csv("C:\\Users\\91144\\Desktop\\kaggle比赛数据\\房屋价格\\test.csv")
print(train_data.shape)
print(test_data.shape)

print(pd.DataFrame(train_data))

我们先把无关的两列去掉,ID和目标变量

#这通常是因为第一列是索引,最后一列是目标变量。

all_features = pd.concat((train_data.iloc[:,1:-1],test_data.iloc[:,-1]))

标准化

#找到数字列
numeric_features = all_features.dtypes[all_features.dtypes !='object'].index

#这段代码的目的是对所有的数值特征进行标准化处理。标准化是一种常见的特征缩放方法,它能够将特征的分布转变为均值为0,标准差为1的标准正态分布。这样可以消除特征之间的尺度差异,有利于模型的训练。
all_features[numeric_features] = all_features[numeric_features].apply(
    lambda x: (x-x.mean())/(x.std()))

#它会将DataFrame中所有的NaN值替换为括号里的值,这里是0。
all_features[numeric_features] = all_features[numeric_features].fillna(0)

处理离散值

all_features = pd.get_dummies(all_features,dummy_na = True)
all_features.shape

print(all_features.dtypes)
#指定了要选择的数据类型。np.number 是NumPy的一个类,表示所有的数值类型,包括整数和浮点数。
print(all_features.dtypes)
#指定了要选择的数据类型。np.number 是NumPy的一个类,表示所有的数值类型,包括整数和浮点数。
all_features = all_features.select_dtypes(include=[np.number])

#LabelEncoder 标签的编码是按照字母顺序进行的,它可以将分类特征的标签转换为数值。
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
#将字符串类型转化为数字
for col in all_features.columns:
    if all_features[col].dtype == 'object':
        all_features[col] = label_encoder.fit_transform(all_features[col])

数据通常被转化为张量(tensor)进行处理,原因有以下几点:

GPU 加速:张量运算可以在 GPU 上进行,这通常比在 CPU 上进行计算更快。这是因为 GPU 是专门为并行运算设计的,能够同时处理大量的数据,而深度学习中通常需要对大量的数据进行相同的运算。PyTorch 的张量(Tensor)和 TensorFlow 的张量都支持 GPU 加速。

统一的数据结构:在深度学习框架中,无论是输入数据、模型权重、偏置项、激活值还是梯度,都是以张量的形式存在的。这样,所有的运算都可以统一为张量运算,简化了编程。

自动求导:深度学习框架通常提供了自动求导的功能。在 PyTorch 和 TensorFlow 中,只要张量的 requires_grad 属性被设置为 True,那么在进行运算时就会自动构建计算图,从而可以自动计算梯度。这对于深度学习中的反向传播算法非常有用。

批处理:在机器学习和深度学习中,通常会一次处理多个样本,这被称为批处理。批处理可以提高计算效率,并且可以使模型的更新更加平稳。张量很自然地支持批处理,因为它是一个多维数组,可以用一个维度来表示批次中的样本。

n_train = train_data.shape[0]
train_features = torch.tensor(all_features[:n_train].values, # 从 DataFrame 中选取前 n_train 行,并转换为 numpy 数组
                            dtype = torch.float32)# 将 numpy 数组转换为 PyTorch 张量,并指定数据类型为 float32
test_features = torch.tensor(all_features[n_train:].values,
                            dtype = torch.float32) #将 numpy 数组转换为 PyTorch 张量,并指定数据类型为 torch.float32。
train_labels = torch.tensor(train_data['SalePrice'].values.reshape(-1,1),
                            dtype = torch.float32)
loss = nn.MSELoss() #定义了损失函数为均方误差(Mean Squared Error, MSE)
in_features = train_features.shape[1] #获取训练数据的特征数量。

#定义了一个简单的神经网络。这个网络只包含一个线性层(nn.Linear),输入特征的数量为 in_features,输出一个值。nn.Sequential 是一个容器,它按照顺序包含了一系列的模块。在这个例子中,只有一个模块,就是线性层。
def get_net():
    net = nn.Sequential(nn.Linear(in_features,1))
    return net
#它实现了从输入特征到输出预测值的线性映射。

net(features) 就是在用神经网络模型 net 根据特征 features 来进行预测。这个预测的结果,我们可以看作是模型对于每个输入样本的标签的预测值。然后,我们可以将这个预测值和真实的标签进行比较,计算出一个损失值(loss),这个损失值表示模型的预测结果和真实结果之间的差距。通过最小化这个损失值,我们可以训练模型以使其预测结果更接近真实结果。

这种误差度量通常用于评估预测模型的性能,特别是在预测正数连续值时(例如销售量、价格等)。RMSLE 是一种惩罚低估比高估更严重的损失函数。

def log_rmse(net,features,labels):
    clipped_preds = torch.clamp(net(features),1,float('inf'))  #torch.clamp 
函数将预测值限制在 [1, +∞) 范围内。这是为了避免在下一步计算对数时出现问题
(因为对数函数在 (0, +∞) 范围内是定义的)。
    rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels))) #均方误差
    return rmse.item()

def train(net,train_features,train_labels,test_features,test_labels,num_epochs,learning_rate,weight_decay,batch_size):
    train_ls,test_ls= [],[]
    train_iter = d2l.load_array((train_features,train_labels),batch_size) #d2l.load_array 函数将训练集的特征和标签加载到一个迭代器中,这样就可以按照批量大小进行迭代。
    optimizer = torch.optim.Adam(net.parameters(),lr = learning_rate,
                                 weight_decay = weight_decay)
    for epoch in range(num_epochs):
        for X,y in train_iter:
            optimizer.zero_grad() #梯度清零
            l = loss(net(X),y) 
            l.backward()  #进行反向传播,计算损失 l 对模型参数的梯度。
            optimizer.step() # 这行代码使用计算出的梯度更新模型的参数。
        train_ls.append(log_rmse(net,train_features,train_labels))  #计算训练集的对数均方根误差(log RMSE)并将其添加到 train_ls 列表中。
        if test_labels is not None:
            test_ls.append(log_rmse(net,test_features,test_labels))
    return train_ls,test_ls

k 折交叉验证是一种常用的模型验证技术,它将数据集分为 k 个子集,每次将其中一个子集作为验证集,其余的子集作为训练集。这个过程重复 k 次,每个子集都有一次机会作为验证集。

#k折交叉验证集的数据分割
def get_k_fold_data(k,i,X,y):
    assert k >1
    fold_size = X.shape[0]//k
    X_train,y_train = None,None
    for j in range(k):
        idx = slice(j*fold_size,(j+1)*fold_size)  #创建一个切片对象,用于选取第 j 个折的数据。
        X_part,y_part = X[idx,:],y[idx]
        if j==i:
            X_valid,y_valid = X_part,y_part
        elif X_train is None:
            X_train,y_train = X_part,y_part
        else:
            X_train = torch.cat([X_train,X_part],0) #将当前折的特征添加到训练特征中。
            y_train = torch.cat([y_train,y_part],0) #当前折的标签添加到训练标签中。
    return X_train,y_train,X_valid,y_valid

使用了 k 折交叉验证来训练和验证神经网络模型。

def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay, batch_size):
    train_l_sum, valid_l_sum = 0, 0
    fold = 1
    epochs = range(1, num_epochs + 1)
    for i in range(k):
        data = get_k_fold_data(k, i, X_train, y_train)
        net = get_net()
        train_ls, valid_ls = train(net, *data, num_epochs, learning_rate, weight_decay, batch_size)
        train_l_sum += train_ls[-1]
        valid_l_sum += valid_ls[-1]
        if i == 0:
            epochs = list(range(1, num_epochs + 1))
            d2l.plot(epochs, [train_ls, valid_ls], xlabel='epoch', ylabel='rmse', xlim=[1, num_epochs],
                     legend=['train', 'valid'], yscale='log')
        print(f'fold {fold}, train log rmse {float(train_ls[-1]):f}, valid log rmse {float(valid_ls[-1]):f}')
        fold += 1
    return train_l_sum / k, valid_l_sum / k   
k,num_epochs,lr,weight_decay,batch_size = 5,100,5,0,64
epochs = list(range(1, num_epochs + 1)) #创建了一个包含所有训练周期的列表。
train_l,valid_l = k_fold(k,train_features,train_labels,num_epochs,lr, #使用 k 折交叉验证来训练和验证模型,并获取训练损失和验证损失。
                        weight_decay,batch_size)
print(f'{k}-折验证:平均训练log rmse:{float(train_l):f},'
      f'平均验证log rmse:{float(valid_l):f}')

def train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size):
    net = get_net()
    train_ls, _ = train(net, train_features, train_labels, None, None, num_epochs, lr, weight_decay, batch_size)
    d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch', ylabel='log rmse', xlim=[1, num_epochs], yscale='log')
    print(f'train log rmse {float(train_ls[-1]):f}')
    
    preds = net(test_features).detach().numpy()
    preds = preds.flatten()  # 将二维数组转换为一维数组
    test_data['SalePrice'] = pd.Series(preds)
    submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)
    submission.to_csv('submission.csv', index=False)

# 调用函数
train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)

以下是使用k折交叉验证来评估神经网络模型的一般步骤:

  1. 准备数据:确保你的数据集已经被加载并且准备好用于训练。

  2. 定义神经网络模型:创建一个神经网络模型类或函数。

  3. 初始化评估指标:选择一个或多个评估指标,如准确率、均方误差等。

  4. k折循环

    • 将数据集分成k个子集。
    • 对于每一个子集:
      • 使用剩下的k-1个子集作为训练集来训练模型。
      • 使用当前的子集作为验证集来评估模型。
      • 记录评估指标。
  5. 计算平均评估指标:计算所有k次迭代的平均评估指标。

  6. 分析结果:分析k折交叉验证的结果,以确定模型的性能。

然后是根据讯飞的老师写的算法,运用堆叠法

from scipy.stats import norm,skew#获取统计信息
from scipy import stats
import numpy as np
import pandas as pd
import seaborn as sns
color = sns.color_palette() #创建了一个颜色调色板,可以用于 seaborn 图形的颜色设置。
sns.set_style('darkgrid') #这行代码设置了 seaborn 图形的风格。
import matplotlib.pyplot as plt
%matplotlib inline     #这行是 Jupyter Notebook 的魔术命令,用于在 notebook 中内嵌显示图形。

pd.set_option('display.float_format',lambda x:'{:3f}'.format(x))#限制浮点输出到小数点后3位
train = pd.read_csv("C:\\Users\\91144\\Desktop\\kaggle比赛数据\\房屋价格\\train.csv")
test = pd.read_csv("C:\\Users\\91144\\Desktop\\kaggle比赛数据\\房屋价格\\test.csv")
#检查样本和特征的数量
print("删除Id列前训练集大小:{}".format(train.shape))
print("删除Id列前测试集大小:{}".format(test.shape))

#保存Id列
train_ID = train['Id']
test_ID = test['Id']
#Id列用不到
#删除原数据的Id列
train.drop("Id",axis =1 ,inplace = True)
test.drop("Id",axis =1,inplace = True)

数据处理和特征工程

异常值处理

将数据可视化后可看见有几个点远离了,将他们删除

#观察是否有离群值
plt.figure(figsize = (14,4))

plt.subplot(121)
plt.scatter(x = train['GrLivArea'],y = train['SalePrice'])
plt.ylabel('SalePrice',fontsize=13)
plt.xlabel('GrLivArea',fontsize=13)

train = train.drop(train[(train['GrLivArea']>4000)&(train['SalePrice']<300000)].index)

目标变量分析

看数据是否符合正态分布

#分布图
fig,ax = plt.subplots(nrows = 2,figsize = (6,10))
sns.distplot(train['SalePrice'],fit = norm,ax=ax[0])
(mu,sigma) = norm.fit(train['SalePrice'])   #正态分布
ax[0].legend(['Normal dist.($\mu=$ {:.2f} and $\sigma = ${:.2f})'.format(mu,sigma)],loc = 'best')
ax[0].set_ylabel('Frequency')
ax[0].set_title('SalePrice distribution')
#QQ图  如果QQ图的点分布在一条直线上,那说明数据近似正态分布,斜率为标准差,截距为均值
stats.probplot(train['SalePrice'],plot=ax[1])
plt.show()

QQ 图,又称为量-量图(Quantile-Quantile plot),是一种用于比较两个数据集是否来自同一分布的可视化工具。它通过将两个数据集的分位数进行一一对应的方式,将它们的分布进行比较。

在QQ 图中,通常将一个数据集的分位数(纵轴)与另一个数据集的对应分位数(横轴)进行比较。如果两个数据集来自同一分布,那么点应该沿着一条直线排列。如果数据集的分布存在差异,QQ 图中的点会偏离这条直线。

QQ 图可以帮助我们判断一个数据集是否符合某种特定的分布假设,比如正态分布。如果在QQ 图中,点几乎在一条直线上,那么数据集很可能符合正态分布。如果点在直线上方或下方有明显的偏离,说明数据集分布与正态分布有所不同。

saleprice 分布呈正偏态,而线性回归模型要求因变量服从正态分布,我们对其做对数变换,让数据接近正态分布

#对数变换,将目标变量正太化
train["SalePrice"] = np.log1p(train["SalePrice"]) #np.log1p(x) 计算的是 log(1+x),
这个函数对于处理正偏斜度(右偏)的数据非常有用,
因为它可以帮助我们减小数据的偏斜度,使其更接近正态分布

#查看转换后数据分布
#分布图
fig,ax = plt.subplots(nrows = 2,figsize = (6,10))
sns.distplot(train['SalePrice'],fit = norm,ax=ax[0])
(mu,sigma) = norm.fit(train['SalePrice'])
ax[0].legend(['Normal dist.($\mu=$ {:.2f} and $\sigma = ${:.2f})'.format(mu,sigma)],loc = 'best')
ax[0].set_ylabel('Frequency')
ax[0].set_title('SalePrice sidtribution')
#QQ图  如果QQ图的点分布在一条直线上,那说明数据近似正态分布,斜率为标准差,截距为均值
stats.probplot(train['SalePrice'],plot=ax[1])
plt.show()

缺失值处理

把训练测试集整合,方便处理

all_data = pd.concat((train,test)).reset_index(drop = True)
all_data.drop(['SalePrice'],axis=1,inplace=True)

print("all_data size is :{}".format(all_data.shape))

统计各特征缺失情况

all_data_na = (all_data.isnull().sum()/len(all_data))*100
all_data_na

all_data_na = all_data_na.drop(all_data_na[all_data_na == 0].index).sort_values(ascending=False)
missing_data = pd.DataFrame({'Missing Ratio':all_data_na})
missing_data.head(10)

#缺失率条形图
fig,ax = plt.subplots(figsize = (15,8))
sns.barplot(x=missing_data.index,y=all_data_na)
plt.xticks(rotation=90)
plt.xlabel('Features',fontsize=15)
plt.ylabel('Percent of missing values',fontsize=15)
plt.title('Percent missing data by feature',fontsize=15)

填补缺失值

不同的缺失值,用不同方法填补

all_data["PoolQC"] = all_data["PoolQC"].fillna("None")
all_data["MiscFeature"] = all_data["MiscFeature"].fillna("None")
all_data["Alley"] = all_data["Alley"].fillna("None")
all_data["Fence"] = all_data["Fence"].fillna("None")
all_data["FireplaceQu"] = all_data["FireplaceQu"].fillna("None")
all_data["MasVnrType"] = all_data["MasVnrType"].fillna("None")
all_data["MasVnrArea"] = all_data["MasVnrArea"].fillna(0)
for col in ('GarageType', 'GarageFinish', 'GarageQual', 'GarageCond'):
    all_data[col] = all_data[col].fillna('None')
for col in ('GarageYrBlt', 'GarageArea', 'GarageCars'):
    all_data[col] = all_data[col].fillna(0)
for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    all_data[col] = all_data[col].fillna(0)
for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    all_data[col] = all_data[col].fillna('None')

对于缺失较少的离散型特征,比如Electrical.可以用众数填补缺失值

all_data['MSZoning'] = all_data['MSZoning'].fillna(all_data['MSZoning'].mode()[0])
all_data['Electrical'] = all_data['Electrical'].fillna(all_data['Electrical'].mode()[0])
all_data['KitchenQual'] = all_data['KitchenQual'].fillna(all_data['KitchenQual'].mode()[0])
all_data['Exterior1st'] = all_data['Exterior1st'].fillna(all_data['Exterior1st'].mode()[0])
all_data['Exterior2nd'] = all_data['Exterior2nd'].fillna(all_data['Exterior2nd'].mode()[0])
all_data['SaleType'] = all_data['SaleType'].fillna(all_data['SaleType'].mode()[0])

LotFrontage:由于房屋到街道的距离,最有可能与其附近其他房屋到街道的距离相同或相似,因此我们可以用中位数填补缺失值

all_data['LotFrontage'] = all_data.groupby("Neighborhood")["LotFrontage"].transform(lambda x:x.fillna(x.median()))

Functional:居家功能性,数据描述说NA表示类型Typ,因此,我们用其填充

all_data["Functional"] = all_data["Functional"].fillna("Typ")

Utilities:设备可用性,这特征对预测建模没有帮助,因此我们可以安全地删除它

all_data = all_data.drop(['Utilities'],axis=1)

最好缺人缺失值是否已经处理完毕

all_data.isnull().sum().max()

特征相关性,相关性矩阵热图:可以表现与目标值之间以及两两特征之间的相关程度,对特征的处理有指导意义

#seaborn中函数heatmap()可以查看特征如何与SalePrice相关联
numeric_cols = train.select_dtypes(include=[np.number])
corrmat = numeric_cols.corr()
plt.figure(figsize=(12,9))
sns.heatmap(corrmat,vmax=0.9,square=True)

all_data['MSSubClass'] = all_data['MSSubClass'].apply(str)#apply函数默认对列进行操作
all_data['YrSold'] = all_data['YrSold'].apply(str)
all_data['MoSold'] = all_data['MoSold'].apply(str)
from sklearn.preprocessing import LabelEncoder
cols = ('FireplaceQu', 'BsmtQual', 'BsmtCond', 'GarageQual', 'GarageCond',
        'ExterQual', 'ExterCond', 'HeatingQC', 'PoolQC', 'KitchenQual', 'BsmtFinType1',
        'BsmtFinType2', 'Functional', 'Fence', 'BsmtExposure', 'GarageFinish', 'LandSlope','LotShape',
        'PavedDrive', 'Street', 'Alley', 'CentralAir', 'MSSubClass', 'OverallCond','YrSold', 'MoSold')

#处理列,将标签编码应用于分类特征
for c in cols:
    lbe = LabelEncoder()
    all_data[c] = lbe.fit_transform(list(all_data[c].values))

print('Shape all_dat a:{}'.format(all_data.shape))
Shape all_data:(2917, 78)
all_data.shape

(2917, 78)

构造更多的特征是特征工程中一个重要的步骤,它可以帮助模型更好地理解数据、提取数据中的模式,并最终提升机器学习模型的性能。以下是构造更多特征的几个原因:

  1. 捕捉数据间的非线性关系:一些机器学习模型,特别是线性模型,难以捕获数据之间的复杂关系和非线性关系。通过构造交互项、多项式特征等,可以帮助模型更好地学习数据之间的非线性关系。

  2. 增加模型的表达能力:更多的特征可以增加模型的表达能力,使其能够更准确地拟合数据。这样可以降低模型的偏差,提高模型的准确性。

  3. 提高模型的泛化能力:构造更多特征可以帮助模型从训练数据中学到更多有用的信息,有助于提高模型的泛化能力,即在未见过的数据上表现良好。

  4. 减少过拟合:在某些情况下,增加更多特征可以减少模型的过拟合风险。通过添加更多特征,可以使模型更难以记住训练数据的细节,从而更好地泛化到新数据。

  5. 提高模型对异常值的鲁棒性:通过构造更多特征,可以使模型更加鲁棒,降低异常值对模型的影响。

总的来说,构造更多特征是一种优化模型性能的重要手段,可以帮助模型更好地理解数据、增加灵活性、降低过拟合风险,并提高预测的准确性和稳定性。

# 构造更多的特征
all_data['TotalSF'] = all_data['TotalBsmtSF'] + all_data['1stFlrSF'] + all_data['2ndFlrSF'] # 房屋总面积

all_data['OverallQual_TotalSF'] = all_data['OverallQual'] * all_data['TotalSF']  # 整体质量与房屋总面积交互项
all_data['OverallQual_GrLivArea'] = all_data['OverallQual'] * all_data['GrLivArea'] # 整体质量与地上总房间数交互项
all_data['OverallQual_TotRmsAbvGrd'] = all_data['OverallQual'] * all_data['TotRmsAbvGrd'] # 整体质量与地上生活面积交互项
all_data['GarageArea_YearBuilt'] = all_data['GarageArea'] * all_data['YearBuilt'] # 车库面积与建造时间交互项
#筛选出所有数值型特征
numeric_feats = all_data.dtypes[all_data.dtypes != "object"].index
#计算特征的偏度
numeric_data = all_data[numeric_feats]
skewed_feats = numeric_data.apply(lambda x:skew(x.dropna())).sort_values(ascending=False)
skewness = pd.DataFrame({'skew':skewed_feats})
skewness

new_skewness = skewness[skewness.abs() > 0.75]
print('有{}个特征被Box-Cox变换'.format(new_skewness.shape[0]))
有63个特征被Box-Cox变换
#Box-Cox变换是一种能够处理偏度问题的数学变换方法。
当你的数据不满足正态分布时,Box-Cox变换可以使数据更接近正态分布,
从而提高某些统计模型的效果(例如,许多机器学习算法都假设数据是
正态分布或至少是高斯分布的)。
from scipy.special import boxcox1p

skewed_features = new_skewness.index
lam = 0.15
for feat in skewed_features:
    all_data[feat] = boxcox1p(all_data[feat],lam)#指定要平滑的列和需要平滑到的峰度
df = pd.DataFrame({'color':['红','蓝','黄']})
df

lbl = LabelEncoder()

df['color'] = lbl.fit_transform(df['color'])

df

独热编码

df = pd.DataFrame({'color':['红','蓝','黄']})
pd.get_dummies(df)

all_data = pd.get_dummies(all_data)
print(all_data.shape)

(2917, 224)

建模

from sklearn. linear_model import ElasticNet, Lasso
from sklearn. ensemble import GradientBoostingRegressor
from sklearn. kernel_ridge import KernelRidge
from sklearn. pipeline import make_pipeline
from sklearn. preprocessing import RobustScaler
from sklearn. base import BaseEstimator, TransformerMixin, RegressorMixin, clone
from sklearn. model_selection import KFold, cross_val_score, train_test_split
from sklearn. metrics import mean_squared_error
import xgboost as xgb
import lightgbm as lgb
y_train = train.SalePrice.values
train = all_data[:train.shape[0]]
test = all_data[train.shape[0]:]

评价函数(Evaluation function)在机器学习中用于衡量模型在预测任务中的性能和准确度。它是通过对比模型的预测结果与真实标签或目标变量之间的差异来进行评估的。

评价函数的选择取决于具体的机器学习任务和目标。以下是几个常见的评价函数:

  1. 均方误差(Mean Squared Error,MSE):均方误差是回归任务中常用的评价函数,它计算预测值与真实值之间的平方误差的平均值。均方误差越小,表示模型的预测结果与真实值的拟合程度越好。

  2. 均方根误差(Root Mean Squared Error,RMSE):均方根误差是均方误差的平方根,它度量了回归模型预测结果的标准误差。与均方误差类似,均方根误差越小,表示模型的预测准确度越高。

  3. 平均绝对误差(Mean Absolute Error,MAE):平均绝对误差是回归任务中另一种常见的评价函数,它计算预测值与真实值之间的绝对误差的平均值。平均绝对误差越小,表示模型的预测结果与真实值的距离越近。

  4. 准确率(Accuracy):准确率是分类任务中常用的评价函数,它衡量模型正确分类的样本数与总样本数之间的比例。准确率越高,表示模型在分类任务中的预测准确度越高。

  5. 召回率(Recall) 和 精确度(Precision):召回率和精确度是在不均衡分类问题中常用的评价函数。召回率衡量模型对正例样本的识别能力,精确度衡量模型的预测结果中真正正例的比例。两者的取值范围都是0到1之间。

#评价函数
n_folds = 5
def rmsle_cv(model):
    kf = KFold(n_folds,shuffle = True,random_state=42).get_n_splits(train.values)  #shuffle打乱
    #评估模型常用指标
    rmse = np.sqrt(-cross_val_score(model,train.values,y_train,scoring = "neg_mean_squared_error",cv=kf))
    return(rmse)

基本模型LASSO Regression(套索回归)

lasso = make_pipeline(RobustScaler(),Lasso(alpha = 0.0005,random_state = 1))

核岭回归(Kernel Ridge Regression)是一种结合了岭回归(Ridge Regression)和核方法(Kernel methods)的回归算法。它在处理非线性问题时特别有效,并且对数据中存在的噪声和共线性具有较强的鲁棒性。

下面简单介绍核岭回归的基本原理:

  1. 岭回归(Ridge Regression):岭回归是一种线性回归的扩展形式,它通过在损失函数中加入正则化项(L2正则化)来控制模型的复杂度,防止过拟合。岭回归的目标是最小化损失函数和正则化项之和。

  2. 核方法(Kernel methods):核方法通过将数据映射到高维特征空间来解决非线性问题,同时保持计算的高效性。其中,核函数起到了至关重要的作用,它可以将数据映射到高维空间,并在该空间中进行线性操作,避免了显式地进行高维计算。

  3. 核岭回归(Kernel Ridge Regression):核岭回归结合了岭回归的正则化思想和核方法的非线性特性。它在进行岭回归时采用核技巧,将输入数据映射到特征空间中进行线性回归,从而可以处理非线性关系。

在核岭回归中,损失函数由两部分组成:回归损失(通常使用平方损失)和正则化项。正则化项包含了控制模型复杂度的超参数,以平衡拟合训练数据和避免过拟合的需求。

核岭回归的优点包括能够处理非线性关系、对噪声和共线性具有较强的鲁棒性,以及较好的泛化能力。然而,由于核方法的计算复杂度较高,处理大规模数据时可能需要耗费较多的计算资源。因此,在实际应用中,需要根据数据的特点和问题的需求来选择是否使用核岭回归以及合适的核函数。

#核岭回归

KRR = KernelRidge(alpha = 0.6,kernel='polynomial',degree=2,coef0 = 2.5)

这段代码的作用是创建了一个机器学习管道,其中包含数据标准化(RobustScaler)和Elastic Net回归(ElasticNet)两个步骤,并使用了指定的参数配置。这个管道可以直接用于拟合数据,并进行预测。

#lasticNet 是一种线性回归方法,它结合了 LASSO(最小绝对收缩和选择算子)和岭回归(Ridge Regression)的特点。
ENet = make_pipeline(RobustScaler(),ElasticNet(alpha=0.0005,l1_ratio=.9,random_state=3))
#梯度提升回归,通过顺序地训练决策树来最小化损失函数,并逐步改进模型的性能。
GBoost = GradientBoostingRegressor(n_estimators = 3000,learning_rate = 0.05,max_depth = 4,max_features = 'sqrt',
                                   min_samples_leaf = 15,min_samples_split=10,
                                   loss='huber',random_state = 5)
#一种优化的分布式梯度增强库,它设计用于速度和性能,同时保持灵活性。
model_xgb = xgb.XGBRegressor(colsample_bytree = 0.5,gamma=0.05,
                             learning_rate = 0.005,max_depth=3,
                             min_child_weight = 1.8,n_estimators = 2200,
                             reg_alpha=0.5,reg_lambda=0.8,
                             subsample=0.5,random_state=7,nthread=-1)
#LightGBM,LightGBM 是一种基于梯度提升框架的高效、分布式、高性能机器学习算法
model_lgb = lgb.LGBMRegressor(object='regression',num_leaves = 5,
                              learning_rate = 0.05,n_estimators=720,
                              max_bin=55,bagging_fraction=0.8,
                              bagging_freq=5,feature_fraction=0.2,
                              feature_fraction_seed=9,bagging_seed=9,
                              min_data_in_leaf=6,min_sum_hessian_in_leaf=11,verbose=-1)
#基本模型效果评价
models ={'Lasso':lasso,'ElasticNet':ENet,'Kernel Ridge':KRR,
        'Gradient Boosting':GBoost,'XGBoost':model_xgb,'LightGBM':model_lgb}
for model_name,model in models.items():
    score = rmsle_cv(model)
    print("{}:{:.4f}({:.4f})\n".format(model_name,score.mean(),score.std()))
Lasso:0.1114(0.0073)
ElasticNet:0.1115(0.0074)

Kernel Ridge:0.1175(0.0081)

Gradient Boosting:0.1168(0.0081)

XGBoost:0.1191(0.0056)

LightGBM:0.1161(0.0069)

堆叠法

堆叠法(Stacking)是一种集成学习方法,通过结合多个基础模型的预测结果来提高整体模型的泛化能力和性能。

在堆叠法中,我们首先将原始数据集划分为训练集和测试集。接下来,我们构建多个不同的基础模型,并在训练集上对它们进行拟合。然后,我们使用这些基础模型对测试集进行预测,并将它们的预测结果作为新的特征。最后,我们使用另一个模型(通常称为元模型或者堆叠模型)来基于这些新特征进行拟合和预测。

下面是堆叠法的基本步骤:

  1. 第一层(基础模型):选择不同类型的基础模型,例如决策树、支持向量机、随机森林等,并在训练集上对它们进行拟合(学习)。每个基础模型都会产生一组预测结果。

  2. 创建新的特征:使用基础模型对训练集的特征进行预测,得到一组新的特征。这些新的特征在训练集上是基于基础模型的预测结果得到的。

  3. 第二层(元模型):将创建的新特征与原始特征合并,并使用元模型(通常是一个简单的线性模型,如逻辑回归)来训练整体模型。这个元模型使用之前得到的新特征作为输入,并预测目标变量。

需要注意的是,在训练期间,基础模型和元模型通常都会使用交叉验证的方法来获得更可靠的效果评估。

堆叠法的优点包括能够利用多个基础模型的优势,提高整体模型的泛化能力。通过结合不同模型的预测结果,堆叠法可以有效地捕捉数据中的复杂关系和特征。

然而,堆叠法也有一些需要注意的方面。它在构建过程中会引入更多的计算成本和复杂性。此外,如果没有适当的模型选择和参数调整,堆叠法可能导致过拟合的问题。

总的来说,堆叠法是一种强大的集成学习方法,通过结合多个模型的预测结果来提高模型的性能和鲁棒性。

class StackingAveragedModels(BaseEstimator,RegressorMixin,TransformerMixin):
    def __init__(self,base_models,meta_model,n_folds = 5):
        self.base_models = base_models#第一层模型
        self.meta_model  = meta_model#第二层模型
        self.n_folds = n_folds
        
    #运用克隆的基本模型拟合数据
    def fit(self,X,y):
        self.base_models_ = [list()for x in self.base_models]
        self.meta_model_ = clone(self.meta_model)
        kfold = KFold(n_splits = self.n_folds,shuffle=True,random_state = 156)

        #训练克隆的第一层模型
        out_of_fold_predictions = np.zeros((X.shape[0],len(self.base_models)))
        for i, model in enumerate(self.base_models):
            for train_index, holdout_index in kfold.split(X, y):
                instance = clone(model)
                self. base_models_[i].append(instance)
                instance.fit(X[train_index], y[train_index])
                y_pred = instance.predict(X[holdout_index])
                out_of_fold_predictions[holdout_index, i] = y_pred

        #使用交叉验证预测的结果作为新特征,来训练克隆的第二模型
        self.meta_model_.fit(out_of_fold_predictions,y)
        return self

    def predict(self,X):
        meta_features = np.column_stack([np.column_stack([model.predict(X) for model in base_models]).mean(axis=1)
                                         for base_models in self.base_models_])
        return self.meta_model_.predict(meta_features)
stacked_averaged_models =StackingAveragedModels(base_models=(ENet, GBoost, KRR), meta_model=lasso)

score = rmsle_cv(stacked_averaged_models)
print ("Stacking Averaged models score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
Stacking Averaged models score: 0.1083 (0.0074)
#表示均方误差
def rmsle(y,y_pred):
    return np.sqrt(mean_squared_error(y,y_pred))
#stack模型
stacked_averaged_models.fit(train.values,y_train)
stacked_train_pred = stacked_averaged_models.predict(train.values)
stacked_pred = np.expm1(stacked_averaged_models.predict(test.values))
print(rmsle(y_train,stacked_train_pred))
0.0763193711203406
  1. XGBoost(Extreme Gradient Boosting)是一种高效的梯度提升算法,广泛应用于机器学习竞赛和实际问题中。它通过集成多个决策树模型来提高预测性能,具有出色的准确性和速度。

#XGBoost
model_xgb.fit(train,y_train)
xgb_train_pred = model_xgb.predict(train)
xgb_pred = np.expm1(model_xgb.predict(test))
print(rmsle(y_train,xgb_train_pred))
0.09401726360646369
  1. LightGBM 是一个基于梯度提升框架的快速、高效的机器学习库,专注于处理大规模数据集和高维特征的问题。它在训练过程中采用了一种称为基于直方图的决策树算法,具有快速训练速度和良好的准确性。

#LightGBM
model_lgb.fit(train,y_train)
lgb_train_pred = model_lgb.predict(train)
lgb_pred = np.expm1(model_lgb.predict(test.values))
print(rmsle(y_train,lgb_train_pred))
0.07158286128042535
print('集成模型的得分:{}'.format(rmsle(y_train,stacked_train_pred*0.70 + xgb_train_pred*0.15 + lgb_train_pred*0.15)))
集成模型的得分:0.07605329200791791

生成最终预测模型

ensemble = stacked_pred*0.70 + xgb_pred*0.15+lgb_pred*0.15

提交结果

sub = pd.DataFrame()
sub['Id']=test_ID
sub['SalePrice'] = ensemble
sub.to_csv('submission.csv',index = False)

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值