Python租房价格分析及预测(xgb+catboost+rf)

         

目录

一、数据介绍

二、统计分析

三、数据预处理

四、回归模型

五、划重点


        早年爬取过我爱我家上北京的部分租房信息,现在重新拿来分析和建模,以往文章大多偏二分类、这次来个数据分析+回归模型的文章。

一、数据介绍

        数据内容包括房子地址、周边情况、交通情况、户型朝向、小区房源情况、看房情况等等信息。数据获取见文末

二、统计分析

        样本量共4w+,包括各地区房源,按照所在区分组、平均租房价格进行倒序排序结果如下,排序基本符合预期

        由于房源的户型面积不一样,所以计算单位面积的月租金(元/月/平方米)查看,排序结果与预期基本一致、越往郊区越便宜

三、数据预处理

        1、序列编码:对于楼层-高低、装修程度、出租方式、有无电梯等有序类别变量和二值变量进行序列编码;

        2、数值提取:对于看房次数提取数值,地铁距离、小区在租/在售房子数量通过正则表达式匹配出相应的数值;

        3、单位面积价格:对于同小区已租房源计算单位面积租金,作为衡量小区价格水平信息的变量;

        4、文本特征:房源特色描述是房东、中介根据房子自身特点填写的文本内容,这里进行简单加工。由于房子优点越多、可能相应的描述会越长,所以提取文本长度;查看内容可以发现,按照空格、逗号、句号、顿号进行断句,每一句对应一个房子特点/优势,所以按照空格、逗号、句号、顿号进行断句,计算句子数量作为特征。

        5、类别型变量编码:以上数据处理后均为数值型变量,还剩所在区, 朝向,楼型, 供暖, 户型结构等类别型变量,这里使用目标编码、按照每一类值对应的房租价格均值进行编码

        6、缺失值处理:本文使用模型之一的rf训练数据不能包含空值,为方便直接使用均值填充

数据预处理代码

import re
def get_subway_distance(string):
    try:
        return re.findall('([1-9]*)米',string)[0]
    except:
        return np.nan
​
def get_build_year(string):
    try:
        return re.findall('年代([1-9]*)年',string)[0]
    except:
        return np.nan
​
def get_community_house_cnt(string):
    try:
        return re.findall('房源([1-9]*)套',string)[0]
    except:
        return np.nan
​
def data_pred(data):
    df=data.copy()
    df['楼层-高低']=df['楼层-高低'].map({'底层':1, '低楼层':2, '中楼层':3, '高楼层':4, '顶层':5})
    df['装修']=df['装修'].str.replace('装修:','').map({'毛坯':1, '简装':2, '精装':3, '豪装':4})
    df['出租方式']=df['出租方式'].str.replace('出租方式:','').map({'合租':1, '整租':2})
    df['电梯']=df['电梯'].str.replace('电梯:','').str.replace('电梯','').map({'无':0,'有':1})
    df['近7天看房次数']=df['近7天看房次数'].str.replace('次','').astype(float)
    df['近30天看房次数']=df['近30天看房次数'].str.replace('次','').astype(float)
​
    df['地铁距离']=df['地铁'].apply(get_subway_distance).replace('',np.nan).astype(float)
    df['建筑年代']=df['建筑年代'].apply(get_build_year).astype(float)
    df['小区在售房源']=df['小区在售房源'].apply(get_community_house_cnt).astype(float)
    df['小区在租房源']=df['小区在租房源'].apply(get_community_house_cnt).astype(float)
​
    df['已租房源1单价']=df['已租房源1_价格'].str.replace('元','').astype(float)/df['已租房源1_面积'].str.replace('m²','').astype(float)
    df['已租房源2单价']=df['已租房源2_价格'].str.replace('元','').astype(float)/df['已租房源2_面积'].str.replace('m²','').astype(float)
    df['已租房源3单价']=df['已租房源3_价格'].str.replace('元','').astype(float)/df['已租房源3_面积'].str.replace('m²','').astype(float)
​
    for i in range(1,6):
        df['特色{}_len'.format(i)]=df['特色{}'.format(i)].str.len()
        df['特色{}_sentence_len'.format(i)]=df['特色{}'.format(i)].str.split('[,;。、;,. ]').str.len()
​
    for col in ['朝向','楼型', '供暖', '户型结构']:
        df[col]=df[col].str.replace(col+':','')
​
    return df
​
df_copy=df.pipe(data_pred)
df_copy.head()
​
y='租金(元/月)'
float_fea=[col for col in df_copy.select_dtypes(include=['int',float]).columns if col!=y]
cate_fea=['所在区', '朝向','楼型', '供暖', '户型结构']
​
def target_encode(df,col):
    return df.groupby([col])[y].mean().to_dict()
​
def data_pred2(data):
    df=data.copy()
    for col in cate_fea:
        df[col]=df[col].map(target_encode(df,col))
    return df
​
def data_pred3(data):
    df=data.copy()
    df[float_fea+cate_fea]=df[float_fea+cate_fea].fillna(df[float_fea+cate_fea].mean())
    return df
​
df_copy2=data_pred2(df_copy)
df_copy3=data_pred3(df_copy2)
print(df_copy3.shape)
df_copy3.head()

四、回归模型

        划分训练集、测试集,分别构建rf、xgboost、catboost回归模型,使用r方、mape进行评估,结果如下

建模代码

def mape_value(y_true,df,model):
    y_pred=model.predict(df)
    r2=r2_score(y_true, y_pred)
    mape=np.mean(np.abs((y_true - y_pred) / y_true))
    return r2,mape
​
def init_params_rf():
    params_rf={
        'n_jobs':4,
        'max_samples':0.8,
        'n_estimators':500,
        'max_depth':4,
        'min_samples_leaf':1,
        'max_features':'auto',
        'min_impurity_decrease':0,
        'bootstrap':True,
        'oob_score':True,
        'random_state':1,
        'verbose':1
    }
    return params_rf
​
def model_train_sklearn_rf(df,y_name,model_fea):
​
    params=init_params_rf()
    model=RandomForestRegressor(**params)
    x_train,x_test, y_train, y_test =train_test_split(df[model_fea],df[y_name],test_size=0.3, random_state=2)
    model.fit(x_train,y_train)
​
    train_r2,train_mape=mape_value(y_train,x_train,model)
    test_r2,test_mape=mape_value(y_test,x_test,model)
​
    model_result={
        'train':y_train.count(),
        'test':y_test.count(),
        'all':df.shape[0],
        'train_r2':train_r2,'train_mape':train_mape,
        'test_r2':test_r2,'test_mape':test_mape
    }
    return model_result,model
​
rf_model_result,rf_model=model_train_sklearn_rf(df_copy3,y,float_fea+cate_fea)
rf_model_result
​
def init_params_xgb():
    params_xgb={
        'objective':'reg:squarederror',
        'eval_metric':'rmse',
        'nthread':4,
        'n_estimators':1400,
        'eta':0.1,
        'max_depth':3,
        'min_child_weight':10,
        'scale_pos_weight':1,
        'gamma':0,
        'reg_alpha':2,
        'reg_lambda':0,
        'subsample':0.8,
        'colsample_bytree':0.9,
        'seed':123
    }
    return params_xgb
​
def xgb_regression(df,y_name,model_fea):
​
    params=init_params_xgb()
    x_train,x_test, y_train, y_test =train_test_split(df[model_fea],df[y_name],test_size=0.3,random_state=2)
​
    model=XGBRegressor(**params)
    model.fit(x_train,y_train,eval_set=[(x_train, y_train),(x_test, y_test)],verbose=False)
    train_r2,train_mape=mape_value(y_train,x_train,model)
    test_r2,test_mape=mape_value(y_test,x_test,model)
​
    model_result={
        'train':y_train.count(),
        'test':y_test.count(),
        'all':df.shape[0],
        'train_r2':train_r2,'train_mape':train_mape,
        'test_r2':test_r2,'test_mape':test_mape
    }
    return model_result,model
​
xgb_model_result,xgb_model=xgb_regression(df_copy2,y,float_fea+cate_fea)
xgb_model_result
​
from catboost import CatBoostRegressor
def init_params_catboost():
    params={
        'loss_function': 'RMSE', # 损失函数,取值RMSE, Logloss, MAE, CrossEntropy, Quantile, LogLinQuantile, Multiclass, MultiClassOneVsAll, MAPE, Poisson。默认Logloss。
    #     'custom_loss': 'F1', # 训练过程中计算显示的损失函数,取值Logloss、CrossEntropy、Precision、Recall、F、F1、BalancedAccuracy、AUC等等
        'eval_metric': 'RMSE', # 用于过度拟合检测和最佳模型选择的指标,取值范围同custom_loss
        'iterations': 1300, # 最大迭代次数,默认500. 别名:num_boost_round, n_estimators, num_trees
        'learning_rate': 0.15, # 学习速率,默认0.03 别名:eta
        'random_seed': 123, # 训练的随机种子,别名:random_state
        'l2_leaf_reg': 0, # l2正则项,别名:reg_lambda
        'bootstrap_type': 'Bernoulli', # 确定抽样时的样本权重,取值Bayesian、Bernoulli(伯努利实验)、MVS(仅支持cpu)、Poisson(仅支持gpu)、No(取值为No时,每棵树为简单随机抽样);默认值GPU下为Bayesian、CPU下为MVS
    #     'bagging_temperature': 0,  # bootstrap_type=Bayesian时使用,取值为1时采样权重服从指数分布;取值为0时所有采样权重均等于1。取值范围[0,inf),值越大、bagging就越激进
        'subsample': 0.6, # 样本采样比率(行采样)
        'sampling_frequency': 'PerTree', # 采样频率,取值PerTree(在构建每棵新树之前采样)、PerTreeLevel(默认值,在子树的每次分裂之前采样);仅支持CPU
        'use_best_model': True, # 让模型使用效果最优的子树棵树/迭代次数,使用验证集的最优效果对应的迭代次数(eval_metric:评估指标,eval_set:验证集数据),布尔类型可取值0,1(取1时要求设置验证集数据)
        'best_model_min_trees': 2000, # 最少子树棵树,和use_best_model一起使用
        'depth': 6, # 树深,默认值6
        'grow_policy': 'SymmetricTree', # 子树生长策略,取值SymmetricTree(默认值,对称树)、Depthwise(整层生长,同xgb)、Lossguide(叶子结点生长,同lgb)
        'min_data_in_leaf': 10, # 叶子结点最小样本量
#         'max_leaves': 12, # 最大叶子结点数量
        'one_hot_max_size': 4, # 对唯一值数量<one_hot_max_size的类别型特征使用one-hot编码
        'rsm': 0.6, # 列采样比率,别名colsample_bylevel 取值(0,1],默认值1
        'nan_mode': 'Max', # 缺失值处理方法,取值Forbidden(不支持缺失值,输入包含缺失时会报错)、Min(处理为该列的最小值,比原最小值更小)、Max(同理)
        'input_borders': None, # 特征数据边界(最大最小边界)、会影响缺失值的处理(nan_mode取值Min、Max时),默认值None、在训练时特征取值的最大最小值即为特征值边界
        'boosting_type': 'Ordered', # 提升类型,取值Ordered(catboost特有的排序提升,在小数据集上效果可能更好,但是运行速度较慢)、Plain(经典提升)
        'max_ctr_complexity': 2, # 分类特征交叉的最高阶数,默认值4
        'logging_level':'Silent', # 模型训练过程的信息输出等级,取值Silent(不输出信息)、Verbose(默认值,输出评估指标、已训练时间、剩余时间等)、Info(输出额外信息、树的棵树)、Debug(debug信息)
        'metric_period': 1, # 计算目标值、评估指标的频率,默认值1、即每次迭代都输出目标值、评估指标
        'early_stopping_rounds': 2000,
        'border_count': 1000, # 数值型特征的分箱数,别名max_bin,取值范围[1,65535]、默认值254(CPU下), # 设置提前停止训练,在得到最佳的评估结果后、再迭代n(参数值为n)次停止训练,默认值不启用
        'feature_border_type': 'GreedyLogSum', # 数值型特征的分箱方法,取值Median、Uniform、UniformAndQuantiles、MaxLogSum、MinEntropy、GreedyLogSum(默认值) 
    }
    return params
​
def catboost_model(df,y_name,model_fea,cate_col=[]):
​
    x_train,x_test, y_train, y_test =train_test_split(df[model_fea],df[y_name],test_size=0.3,random_state=2)
​
    params=init_params_catboost()
    model = CatBoostRegressor(**params)
    model.fit(x_train, y_train,eval_set=[(x_train, y_train),(x_test,y_test)],cat_features=cate_col)
​
    train_r2,train_mape=mape_value(y_train,x_train,model)
    test_r2,test_mape=mape_value(y_test,x_test,model)
​
    model_result={
        'train':y_train.count(),
        'test':y_test.count(),
        'all':df.shape[0],
        'train_r2':train_r2,'train_mape':train_mape,
        'test_r2':test_r2,'test_mape':test_mape
    }
    return model_result,model
​
cat_model_result,cat_model=catboost_model(df_copy2,y,float_fea+cate_fea)
cat_model_result

五、划重点

        关注公众号 Python风控模型与数据分析,回复 房租价格预测 获取本篇数据及代码

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,你需要安装XGBoost库。可以通过在Anaconda Prompt中输入以下命令来安装它: ``` pip install xgboost ``` 然后,你需要准备你的数据集并进行数据预处理。在这里,我们假设你已经完成了这些步骤,并且想使用XGBoost进行回归分析预测。 以下是一个简单的XGBoost回归模型的示例代码: ```python import xgboost as xgb from sklearn.metrics import mean_squared_error import pandas as pd import numpy as np # 加载数据集 df = pd.read_csv('your_dataset.csv') # 分离特征和目标变量 X, y = df.iloc[:,:-1],df.iloc[:,-1] # 将数据集分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123) # 定义XGBoost回归模型 xg_reg = xgb.XGBRegressor(objective ='reg:squarederror', colsample_bytree = 0.3, learning_rate = 0.1, max_depth = 5, alpha = 10, n_estimators = 10) # 在训练集上训练模型 xg_reg.fit(X_train,y_train) # 在测试集上进行预测 preds = xg_reg.predict(X_test) # 计算MSE rmse = np.sqrt(mean_squared_error(y_test, preds)) print("RMSE: %f" % (rmse)) ``` 在这个示例中,我们使用了XGBRegressor类来定义我们的回归模型。我们为它提供了一些超参数,如树的深度,学习率和迭代次数等。然后,我们使用fit方法在训练集上训练模型,并使用predict方法在测试集上进行预测。最后,我们计算了均方根误差(RMSE)来衡量模型的性能。 你可以根据你的需求调整模型的超参数,以获得更好的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值