2021年MathorCup高校数学建模挑战赛——大数据竞赛赛道A -思路分享
Posted 开始King
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021年MathorCup高校数学建模挑战赛——大数据竞赛赛道A -思路分享相关的知识,希望对你有一定的参考价值。
4.8号公布了复赛获奖名单,比赛正式告一段落,为什么现在才开始写呢?其实一是最近一直很忙,二是感觉自己做的不咋地,趁今天有空就写写吧,时间一长就又不想写了。
好了胡扯到此结束,言归正传,这次比赛题目和数据下载
链接:https://pan.baidu.com/s/1RsQkTcERxgmHisMEGt62vA
提取码:60t9
初赛
1 读入数据和数据清洗
导入需要的包
import re
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from category_encoders.leave_one_out import LeaveOneOutEncoder
from sklearn.model_selection import cross_val_score
from sklearn.decomposition import PCA
import xgboost as xgb
1 给变量命名
首先读入数据,官方给的数据是没有列名的,为了方便后续的数据处理,首先读入数据,并给数据加上列名,注意到1,11,12列数据是时间类型的,直接在读入时设置parse_dates参数传化为时间类型
df = pd.read_table(r'D:\\比赛\\2021年MathorCup大数据竞赛赛道A\\附件\\附件1:估价训练数据.txt',
parse_dates=[1, 11, 12],sep='\\t', header=None, encoding='gbk')
# df = pd.read_table('../data/附件1:估价训练数据.txt', sep='\\t', header=None, encoding='gbk')
data = pd.DataFrame(data=df)
columns = ['carid', 'tradeTime', 'brand', 'serial', 'model', 'mileage', 'color', 'cityId', 'carCode',
'transferCount', 'seatings', 'registerDate', 'licenseDate', 'country', 'maketype', 'modelyear',
'displacement', 'gearbox', 'oiltype', 'newprice']
for i in range(1, 16):
str_ = 'anonymousFeature'+str(i)
columns.append(str_)
columns.append('price')
data.columns = columns
2 查看数据的类型和缺失情况
data.info()
data.isnull().sum()
3.
前五列’carid’, ‘tradeTime’, ‘brand’, ‘serial’, 'model’都是id和时间,不能做中心化操作,而且通过data.iloc[:, :5].isnull().sum()
发现没有缺失值,因此不需要处理。
其他列缺失值的情况
可以看出除了15个匿名特征外,carCode有9个缺失值,country有3757个缺失值maketype有3641个缺失值,modelyear有312个缺失值。gearbox有一个缺失值。
对于缺失值较少的列,如carCode和gearbox直接进行删除操作。country ,maketype 和modelyear由于缺失值较多,根据数据类型,定类数据选择使用众数填充比较适合。
nn_i = ['country', 'maketype', 'modelyear']
for i in nn:
x = int(data[i].mode())
data[i].fillna(x, inplace=True)
#data[i]=data[i].dropna()
data_1[‘country’].unique() 可以发现
这个0导致数据量纲较大,会对后期模型的性能产生影响,因此结合所给的信息将其改为779410
data.loc[data['country']==0,'country'] = 779410
4.对15个匿名变量的分析
上图圈出的特征由于数据缺失严重直接删除这些特征
data=data.drop(['anonymousFeature4','anonymousFeature7','anonymousFeature10','anonymousFeature15'
,'anonymousFeature1','anonymousFeature8','anonymousFeature9'],axis=1)
2特征构造
4.1对anonymousFeature11
根据显示的信息猜测此特征是某种物品的个数,预测应该为字符串中所有数字之和,使用正则匹配提取所有数值并求和作为新的anonymousFeature11。
def deal_11(x):
return sum([float(x) for x in re.findall("\\d",x)])
data_1['anonymousFeature11']=data_1['anonymousFeature11'].map(deal_11)
4.2对anonymousFeature12
根据其值的表现形式估计其为汽车的体积,所以其值应为三个数的乘积,使用*切分数据并求出乘积做为新的anonymousFeature12,并用切分得到的三个数据列构建三个新的特征anonymousFeature12_length,anonymousFeature12_width,anonymousFeature12_height。
# 处理匿名特征12
def deal_12(x):
li=[float(x) for x in re.findall("\\d+",x)]
return li[0]*li[1]*li[2]
data_1['anonymousFeature12_length']=data_1['anonymousFeature12'].apply(lambda x:int(x.split('*')[0]))
data_1['anonymousFeature12_width']=data_1['anonymousFeature12'].apply(lambda x:int(x.split('*')[1]))
data_1['anonymousFeature12_height']=data_1['anonymousFeature12'].apply(lambda x:int(x.split('*')[2]))
data_1['anonymousFeature12']=data_1['anonymousFeature12'].map(deal_12)
4.3对anonymousFeature13
把anonymousFeature13转换成字符串进行切片,取前四位为anonymousFeature13_year,其他为anonymousFeature13_month。
# 处理匿名特征13
def deal_13(x):
return x[:4], x[4:6]
data_1['anonymousFeature13']=data_1['anonymousFeature13'].astype('string')
data_1['anonymousFeature13_year']=data_1['anonymousFeature13'].map(deal_13) # (2017, 09)
data_1['anonymousFeature13_month']=data_1['anonymousFeature13_year'].apply(lambda x: int(x[1]))
data_1['anonymousFeature13_year']=data_1['anonymousFeature13_year'].apply(lambda x: int(x[0]))
data_1['anonymousFeature13']=data_1['anonymousFeature13'].astype('float')
经过以上处理,数据已经全部变成数值型特征和时间类型的特征
(5)处理定类特征
对color,carCode,country,modelyear这些类别行的特征,因为是定类数据,数据之间本来应该是没有相对大小的,但是转为数值后比如1,2,3会有相对大小,会对树模型产生不好的影响。因此本组选择使用Frequency编码对定类数据进行转换,Frequency编码通过计算特征变量中每个值的出现次数来表示该特征的信息。
# 处理定类数据(Frequency编码)
data['color'] = data['color'].map(data['color'].value_counts())
data['carCode'] = data['carCode'].map(data['carCode'].value_counts())
# data['country'] = data['country'].map(data['country'].value_counts())
data['modelyear'] = data['modelyear'].map(data['modelyear'].value_counts())
(6)再用时间类型的特征构建新特征
①基础周期特征的拆除(年月日特征拆解)
data['tradeTime_year']=data['tradeTime'].dt.year
data['tradeTime_month']=data['tradeTime'].dt.month
data['tradeTime_day']=data['tradeTime'].dt.day
data['registerDate_year']=data['registerDate'].dt.year
data['registerDate_month']=data['registerDate'].dt.month
data['registerDate_day']=data['registerDate'].dt.day
②时间差
‘old_year’=‘tradeTime’-‘registerDate’ (汽车的使用时间)
‘old_year_1’=‘tradeTime’-‘licenseDate’
# 构建新特征
data_1['old_year']=data_1['tradeTime']-data_1['registerDate']
data_1['old_year']=data_1['old_year'].apply(lambda x:str(x).split(' ')[0])
data_1['old_year']=data_1['old_year'].astype(int)
data_1['old_year_1']=data_1['tradeTime']-data_1['licenseDate']
data_1['old_year_1']=data_1['old_year_1'].apply(lambda x:str(x).split(' ')[0])
data_1['old_year_1']=data_1['old_year_1'].astype(int)
经过以上处理后,特征以全部转换成数据值
(7)数值特征的处理
数据分桶,对mileage特征进行数据分桶,mileage的均值为7.14,其余统计量如下
因此分组区间为 (0,1],(1,4],(4,7.15],(7.15,10],(10,50]
# 数据分桶
bin=[0, 1, 4, 7.15, 10, 50]
data_1['mileage_bin']=pd.cut(data_1['mileage'],bins=bin,labels=False)
(8)清除数据中的异常值
首先查看数据的分布,找出异常值
data_2.describe()
可以明显的看出,price有异常值,接下来用箱线图检测异常值,并构造函数处理异常值
# 看看有没有异常值
data_2.describe()
data_2=data_2[data_2['price']<80]
3特征选择
(1)从这些特征中选择出最合适的特征(特征选择),为模型构建做准备。
皮尔逊相关系数的特征选择
# 基于皮尔逊相关系数
pearson = data_2.corr()
index = pearson['price'][:-1].abs() > 0.1
X = data_2.iloc[:,:-1]
X_subset = X.loc[:, index]
# X_subset.columns
3模型训练预测
构建评估函数
def estimate(y_true=None,y_pred=None):
y_true=np.array(list(y_true))
y_pred=np.array(list(y_pred))
Ape=np.abs(y_pred-y_true)/y_true
Mape=sum(Ape)/len(y_true)
# Ape_count=[np.nan if x <=0.05 else x for x in Ape]
Ape_count=len(np.where(Ape<=0.05)[0])/len(Ape)
return 0.2*(1-Mape)+0.8*Ape_count
训练预测
X_train, X_test, y_train, y_test = train_test_split(X_subset,data_2['price'].to_numpy() , test_size=0.2,random_state=3)
random_model = RandomForestRegressor(n_estimators=500,random_state=33,n_jobs=-1)
random_model.fit(X_train,y_train)
y_pred = random_model.predict(X_test)
score = estimate(y_true=y_test,y_pred=y_pred)
以上基本就是初赛的模型构造模型过程,对附件二的预测已经任务二的模型等其他过程这里没有详细描述,完整的代码在附录获取。下面是复赛的模型
复赛
数据分析
导入包,并构造训练集和测试集
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import re
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.feature_selection import SelectKBest
import xgboost as xgb
import lightgbm as lgb
import warnings
warnings.filterwarnings('ignore')
"""
评估数据集的构造
"""
df_5 = pd.read_csv('./data/附件5:门店交易验证数据.txt', sep='\\t', parse_dates=[1], header=None, encoding='utf-8') # 附件五
df_2 = pd.read_csv('../data/附件2:估价验证数据.txt', sep='\\t', parse_dates=[1, 11, 12], header=None, encoding='utf-8') # 附件二的信息
columns = ['carid', 'tradeTime', 'brand', 'serial', 'model', 'mileage', 'color', 'cityId', 'carCode',
'transferCount', 'seatings', 'registerDate', 'licenseDate', 'country', 'maketype', 'modelyear',
'displacement', 'gearbox', 'oiltype', 'newprice']
for i in range(1,16):
columns.append('anonymousFeature'+str(i))
# 重命名数据列名
df_2.columns = columns
df_5.rename(columns=0:'carid',1:'pushDate',2:'pushPrice',3:'updatePriceTimeJson' ,inplace=True)
# df_5.to_csv(r'D:\\比赛\\2021年MathorCup大数据竞赛赛道A\\复赛\\附件五.csv', encoding='utf-8')
df_test = pd.merge(df_5, df_2, on='carid', how='left')
# df_test.to_csv(r'D:\\比赛\\2021年MathorCup大数据竞赛赛道A\\复赛\\任务一test.csv')
"""
训练集的构造
"""
df_1 = pd.read_csv('../data/附件1:估价训练数据.txt', sep='\\t', parse_dates=[1, 11, 12], encoding='utf-8', header=None) # 附件一
df_4 = pd.read_csv('../data/附件4:门店交易训练数据.txt', sep='\\t', parse_dates=[1, 4, 5], encoding='utf-8', header=None) # 附件四
columns.append('price')
df_1.columns=columns
df_4.rename(columns=0:'carid',1:'pushDate',2:'pushPrice',3:'updatePriceTimeJson',4:'pullDate',5:'withdrawDate',inplace=True)
df_train = pd.merge(df_4, df_1, how='left', on='carid')
# print(df_train.columns)
# print(df_test.columns)
# 调整trian的数据特征,保持与test一致
df_train['cycle'] = df_train['withdrawDate']-df_train['pushDate']
df_train=df_train.drop(['price', 'pullDate', 'withdrawDate'], axis=1)
df_train['cycle']=df_train['cycle'].astype('timedelta64[D]')
# df_train.to_csv(r'D:\\比赛\\2021年MathorCup大数据竞赛赛道A\\复赛\\任务一train.csv')
1 任务分析
根据题意,附件1和附件4合并作为训练集,附件5和附件2合并作为测试集根据所给的变量信息,初步判断,tradeTime, registerDate, licenseDate, pushDate,pullDate,withdrawDate为时间类型,因此在读入数据的时就直接通过设置parse_dates参数转化成时间类型(datetime64[ns] )
查看训练集的数据情况
df_train.info()
测试集的数据情况
df_test.info()
训练集的缺失值
df_train.isnull().sum()
测试集的缺失值
df_test.isnull().sum()
画图显示缺失情况,训练集
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
missing=df_train.isnull().sum()
missing=missing[missing>0]
missing.sort_values(inplace=True)
missing.plot.bar()
测试集
missing=df_test.isnull().sum()
missing=missing[missing>0]
missing.sort_values(inplace=True)
missing以上是关于2021年MathorCup高校数学建模挑战赛——大数据竞赛赛道A -思路分享的主要内容,如果未能解决你的问题,请参考以下文章
2021 年 MathorCup 高校数学建模挑战赛—赛道A二手车估价问题4 问题三思路和数据及参考资料
数学建模MATLAB应用实战系列(138)-2021年MathorCup高校数学建模挑战赛A题思路解析(附代码)
2021年MathorCup高校数学建模挑战赛——大数据竞赛A题
2021年MathorCup高校数学建模挑战赛A二手车估价问题数学建模