datawhale天池二手车比赛

该文详细介绍了使用PyTorch构建多层感知机(MLP)进行二手车价格预测的过程,包括数据预处理、特征工程、模型构建和训练。特征工程涉及离散特征编码、连续特征归一化以及对销售季节性、车型分类和使用年限的分析。同时,文中还对比了机器学习模型如XGBoost和LightGBM的使用方法,展示了如何在这些模型中进行特征选择、训练和结果融合。

听老师讲了很多,并结合天池正式赛里面的lgb与xgb模型baseline与特征工程,进行代码试验.

目录

一.MLP

1.1总览:机器学习与深度学习的区别与适用范围:

1.2注意细节:

1.3EDA

1.4特征编码

2.1构造dataset与loader

2.2Embedding:

2.3Model定义

2.4训练函数

二.特征工程选建

1.使用年限与报废判断

2.车的类型

3.是否新能源

4.销售淡旺季

5.地区编码

三.xgb与lgb

1.数据读取

2.特征选择

3. 模型训练与预测

3.1单模型训练

3.2融合训练

4.模型结果融合

5输出结果


一.MLP

1.1总览:机器学习与深度学习的区别与适用范围:

机器学习:
1模型构建:自己写
2:模型权重求解:自己写(需要用大量的数学公式来推导,每个模型都是有自己的方法)
3:使用方法:掉包scikit-learn/lightgbm/xgboost/catboost
深度学习
1:模型构件:自己写
2:模型权重求解:框架打包已经求解好了
3:使用情况:大量基于框架(torch/tf/paddle...)开发
有自动求导backforward等操作,直接搭积木就好。

1.2注意细节:

对于torch而言:一数据处理:1数据编码,将数据转换成计算机可认的形式;2dl中,每次都是batch小批训练,所以要进行dataset于loader构造;二模型设计:1需要于loader吐出来的数据形式对其;2实现模型里面的子模块;3把子模块拼成最终的模型。三跑模型:八股文形式,1训练流程、2验证/测试流程。

将掉包参数进行分离,避免动代码,config是偏数据集的参数。区分连续特征与离散特征(地区,性别...);model要不要使用离散特征,embedding,隐藏层。。

#参数配置

config = {
    "train_path":'../data/used_car_train_20200313.csv',
    "test_path":'../data/used_car_testB_20200421.csv',
    "epoch" : 15,
    "batch_size" : 512,
    "lr" : 0.001,
    "model_ckpt_dir":'./',
    "device" : 'cuda',
    "num_cols" : ['power', 'kilometer', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14'],
    "cate_cols" : ['model','brand','bodyType','fuelType','gearbox','seller','notRepairedDamage']
}

model_config = {
    "is_use_cate_cols" : True,
    "embedding_dim" : 4,
    "hidden_units" : [256,128,64,32]
}
model_config["num_cols"] = config['num_cols']
model_config['cate_cols'] = config['cate_cols']

num有:发动机频率,公里数,v系列特征;

cate有:1.车型;2.品牌;3.车身类型;4.燃油类型;5.变速箱;6.销售方;7.是否有尚未修复的损坏

train_df = pd.read_csv(config['train_path'],sep=' ')
test_df = pd.read_csv(config['test_path'],sep=' ')
print('Train data shape:',train_df.shape)
print('TestA data shape:',test_df.shape)

'''
Train data shape: (150000, 31)
TestA data shape: (50000, 30)
'''

1.3EDA

对具体的参数进行可视化查看,方便总体掌握数据情况:

# 连续特征
for col in config['num_cols']:
    # 绘制密度图
    sns.kdeplot(df[col], fill=True)

    # 设置图形标题和标签
    plt.title(f'{col} Distribution')
    plt.xlabel(col)
    plt.ylabel('Density')
    
    plt.show()
# 离散特征
for col in config['cate_cols']:
    # 统计特征频次
    counts = df[col].value_counts()

    # 绘制条形图
    counts.plot(kind='bar')

    # 设置图形标题和标签
    plt.title(f'{col} Frequencies')
    plt.xlabel(col)
    plt.ylabel('Frequency')

    # 显示图形
    plt.show()

1.4特征编码

遍历离散特征,补充缺失值,使用embedding操作,将每个城市变成向量,比如将not这个类中的每一个str值,进行一个取值索引。

代码中,unique是去除重复的值,然后再range进行赋值value。

# 离散特征编码
vocab_map = defaultdict(dict)
for col in tqdm(config['cate_cols']):
    df[col] = df[col].fillna('-1')
    map_dict = dict(zip(df[col].unique(), range(df[col].nunique())))
    # label enc
    df[col] = df[col].map(map_dict)
    vocab_map[col]['vocab_size'] = len(map_dict)
model_config['vocab_map'] = vocab_map

输出结果看一下:

model_config['vocab_map']

'''
defaultdict(dict,
            {'model': {'vocab_size': 249},
             'brand': {'vocab_size': 40},
             'bodyType': {'vocab_size': 9},
             'fuelType': {'vocab_size': 8},
             'gearbox': {'vocab_size': 3},
             'seller': {'vocab_size': 2},
             'notRepairedDamage': {'vocab_size': 3}})
'''

vocab_size表示这个key对应有多少类的赋值

将train与test拆分开,并对标签进行log变换,便于dl拟合。dl更适合参数量大的任务,本次任务数据量较小,所以要进行一些优化。

train_df = df[df['price'].notna()].reset_index(drop=True)
# 标签范围太大不利于神经网络进行拟合,这里先对其进行log变换
train_df['price'] = np.log(train_df['price'])
test_df = df[df['price'].isna()].reset_index(drop=True)
del test_df['price']

将连续数据进行归一化处理:

modifycol = config['num_cols']
df[modifycol] = df[modifycol].apply(
    lambda x: (x - x.mean()) / (x.std()))

2.1构造dataset与loader

构造dataset
继承父类,len的方法是返回数据集的长度,这是为了后续取batch用的。getitem方法要输出第index个数据,告诉它如何取出对应数据。
此处适配个数不确定的情况,使用字典更好。

#Dataset构造
class SaleDataset(Dataset):
    def __init__(self,df,cate_cols,num_cols):
        self.df = df
        self.feature_name = cate_cols + num_cols
            
    def __getitem__(self, index):
        data = dict()
        for col in self.feature_name:
            data[col] = torch.Tensor([self.df[col].iloc[index]]).squeeze(-1)
        if 'price' in self.df.columns:
            data['price'] = torch.Tensor([self.df['price'].iloc[index]]).squeeze(-1)
        return data

    def __len__(self):
        return len(self.df)
    
def get_dataloader(df, cate_cols ,num_cols, batch_size=256, num_workers=2, shuffle=True):
    dataset = SaleDataset(df,cate_cols,num_cols)
    dataloader = D.DataLoader(dataset, batch_size=batch_size, shuffle=shuffle, num_workers=num_workers)
    return dataloader

看一下getitem用法:

# sample
train_dataset = SaleDataset(train_df,config['cate_cols'],config['num_cols'])
train_dataset.__getitem__(888)

'''
{'model': tensor(11.),
 'brand': tensor(6.),
 'bodyType': tensor(0.),
 'fuelType': tensor(1.),
 'gearbox': tensor(2.),
 'seller': tensor(0.),
 'notRepairedDamage': tensor(1.),
 'power': tensor(0.1167),
 'kilometer': tensor(1.),
 'v_0': tensor(0.5566),
 'v_1': tensor(0.1054),
 'v_2': tensor(0.1718),
 'v_3': tensor(0.4344),
 'v_4': tensor(0.4444),
 'v_5': tensor(0.8196),
 'v_6': tens
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值