预测指标
分类常见的评估指标:
对于二类分类器/分类算法,评价指标主要有accuracy, [Precision,Recall,F-score,Pr曲线],ROC-AUC曲线。
对于多类分类器/分类算法,评价指标主要有accuracy, [宏平均和微平均,F-score]。
回归预测类常见的评估指标:
平均绝对误差(Mean Absolute Error, MAE):
均方误差(Mean Squared Error, MSE):
R-Square(R2):
残差平方和:
总平均值:
R2表达式:
R2用于度量因变量的变异中可由自变量解释部分所占的比例,取值范围是 0~1,R2越接近1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用x的变化来解释y值变化的部分就越多,回归的拟合程度就越好。所以R2也称为拟合优度(Goodness of Fit)的统计量。
代码示例
数据读取pandas
import pandas as pd
import numpy as np
## 1) 载入训练集和测试集;
path = './datalab/231784/'
Train_data = pd.read_csv(path+'used_car_train_20200313.csv', sep=' ')
Test_data = pd.read_csv(path+'used_car_testA_20200313.csv', sep=' ')
print('Train data shape:',Train_data.shape)
print('TestA data shape:',Test_data.shape)
Train_data.head()
分类指标评价计算
## accuracy
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 1, 0, 1]
y_true = [0, 1, 1, 1]
print('ACC:',accuracy_score(y_true, y_pred))
## Precision,Recall,F1-score
from sklearn import metrics
y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]
print('Precision',metrics.precision_score(y_true, y_pred))
print('Recall',metrics.recall_score(y_true, y_pred))
print('F1-score:',metrics.f1_score(y_true, y_pred))
## AUC
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
print('AUC socre:',roc_auc_score(y_true, y_scores))
结果如下:
ACC: 0.75
Precision 1.0
Recall 0.5
F1-score: 0.6666666666666666
AUC socre: 0.75
回归指标评价计算
# coding=utf-8
import numpy as np
from sklearn import metrics
# MAPE需要自己实现
def mape(y_true, y_pred):
return np.mean(np.abs((y_pred - y_true) / y_true))
y_true = np.array([1.0, 5.0, 4.0, 3.0, 2.0, 5.0, -3.0])
y_pred = np.array([1.0, 4.5, 3.8, 3.2, 3.0, 4.8, -2.2])
# MSE
print('MSE:',metrics.mean_squared_error(y_true, y_pred))
# RMSE
print('RMSE:',np.sqrt(metrics.mean_squared_error(y_true, y_pred)))
# MAE
print('MAE:',metrics.mean_absolute_error(y_true, y_pred))
# MAPE
print('MAPE:',mape(y_true, y_pred))
## R2-score
from sklearn.metrics import r2_score
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2, 8]
print('R2-score:',r2_score(y_true, y_pred))
测试结果
MSE: 0.2871428571428571
RMSE: 0.5358571238146014
MAE: 0.4142857142857143
MAPE: 0.1461904761904762
R2-score:0.948608137045
数据分析
EDA-数据探索性分析
- 载入各种数据科学以及可视化库:
*数据科学库 pandas、numpy、scipy;
*可视化库 matplotlib、seabon;
*其他; - 载入数据:
*载入训练集和测试集;
*简略观察数据(head()+shape); - 数据总览:
*通过describe()来熟悉数据的相关统计量
*通过info()来熟悉数据类型 - 判断数据缺失和异常
*查看每列的存在nan情况
*异常值检测 - 了解预测值的分布
*总体分布概况(无界约翰逊分布等)
*查看skewness and kurtosis
*查看预测值的具体频数 - 特征分为类别特征和数字特征,并对类别特征查看unique分布
- 数字特征分析
*相关性分析
*查看几个特征得 偏度和峰值
*每个数字特征得分布可视化
*数字特征相互之间的关系可视化
*多变量互相回归关系可视化 - 类型特征分析
*unique分布
*类别特征箱形图可视化
*类别特征的小提琴图可视化
*类别特征的柱形图可视化类别
*特征的每个类别频数可视化(count_plot) - 用pandas_profiling生成数据报告
代码示例
载入各种数据科学以及可视化库
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
载入数据
## 1) 载入训练集和测试集;
path = './datalab/231784/'
Train_data = pd.read_csv(path+'used_car_train_20200313.csv', sep=' ')
Test_data = pd.read_csv(path+'used_car_testA_20200313.csv', sep=' ')
## 2) 简略观察数据(head()+shape)
Train_data.head(n=7).append(Train_data.tail())#pandas里面的tail函数,就是添加最后几行,默认n等于5
print(Train_data.shape)
执行结果:
SaleID name regDate model brand ... v_10 v_11 v_12 v_13 v_14
0 0 736 20040402 30.0 6 ... -2.881803 2.804097 -2.420821 0.795292 0.914762
1 1 2262 20030301 40.0 1 ... -4.900482 2.096338 -1.030483 -1.722674 0.245522
2 2 14874 20040403 115.0 15 ... -4.846749 1.803559 1.565330 -0.832687 -0.229963
3 3 71865 19960908 109.0 10 ... -4.509599 1.285940 -0.501868 -2.438353 -0.478699
4 4 111080 20120103 110.0 5 ... -1.896240 0.910783 0.931110 2.834518 1.923482
5 5 137642 20090602 24.0 10 ... 1.885526 -2.721943 2.457660 -0.286973 0.206573
6 6 2402 19990411 13.0 4 ... -4.902200 1.610616 -0.834605 -1.996117 -0.103180
149995 149995 163978 20000607 121.0 10 ... 1.988114 -2.983973 0.589167 -1.304370 -0.302592
149996 149996 184535 20091102 116.0 11 ... 1.839166 -2.774615 2.553994 0.924196 -0.272160
149997 149997 147587 20101003 60.0 11 ... 2.439812 -1.630677 2.290197 1.891922 0.414931
149998 149998 45907 20060312 34.0 10 ... 2.075380 -2.633719 1.414937 0.431981 -1.659014
149999 149999 177672 19990204 19.0 28 ... 1.978453 -3.179913 0.031724 -1.483350 -0.342674
[12 rows x 31 columns]
(150000, 31)
养成看数据集的head()习惯以及shape,确保了解数据集的组成。
总览数据概况
describe函数可以描述每一列的个数count、平均值mean、方差std、最小值min、中位数25%、50%、75%、以及最大值max。通过这个表格可以掌握数据的大概的范围以及异常值的判断。
Train_data.describe()
运行结果:
SaleID name regDate model ... v_11 v_12 v_13 v_14
count 150000.000000 150000.000000 1.500000e+05 149999.000000 ... 150000.000000 150000.000000 150000.000000 150000.000000
mean 74999.500000 68349.172873 2.003417e+07 47.129021 ... 0.009035 0.004813 0.000313 -0.000688
std 43301.414527 61103.875095 5.364988e+04 49.536040 ... 3.286071 2.517478 1.288988 1.038685
min 0.000000 0.000000 1.991000e+07 0.000000 ... -5.558207 -9.639552 -4.153899 -6.546556
25% 37499.750000 11156.000000 1.999091e+07 10.000000 ... -1.951543 -1.871846 -1.057789 -0.437034
50% 74999.500000 51638.000000 2.003091e+07 30.000000 ... -0.358053 -0.130753 -0.036245 0.141246
75% 112499.250000 118841.250000 2.007111e+07 66.000000 ... 1.255022 1.776933 0.942813 0.680378
max 149999.000000 196812.000000 2.015121e+07 247.000000 ... 18.819042 13.847792 11.147669 8.658418
[8 rows x 30 columns]
info函数可以了解数据每列的type,有助于了解是否存在除了nan以外的特殊符号异常。
Train_data.info()
运行结果:
--- ------ -------------- -----
0 SaleID 150000 non-null int64
1 name 150000 non-null int64
2 regDate 150000 non-null int64
3 model 149999 non-null float64
4 brand 150000 non-null int64
5 bodyType 145494 non-null float64
6 fuelType 141320 non-null float64
7 gearbox 144019 non-null float64
8 power 150000 non-null int64
9 kilometer 150000 non-null float64
10 notRepairedDamage 150000 non-null object
11 regionCode 150000 non-null int64
12 seller 150000 non-null int64
13 offerType 150000 non-null int64
14 creatDate 150000 non-null int64
15 price 150000 non-null int64
16 v_0 150000 non-null float64
17 v_1 150000 non-null float64
18 v_2 150000 non-null float64
19 v_3 150000 non-null float64
20 v_4 150000 non-null float64
21 v_5 150000 non-null float64
22 v_6 150000 non-null float64
23 v_7 150000 non-null float64
24 v_8 150000 non-null float64
25 v_9 150000 non-null float64
26 v_10 150000 non-null float64
27 v_11 150000 non-null float64
28 v_12 150000 non-null float64
29 v_13 150000 non-null float64
30 v_14 150000 non-null float64
dtypes: float64(20), int64(10), object(1)
memory usage: 35.5+ MB
判断数据缺失和异常
## 1) 查看每列的存在nan情况
print(Train_data.isnull().sum())
# nan可视化
missing = Train_data.isnull().sum()
missing = missing[missing > 0]
missing.sort_values(inplace=True)
missing.plot.bar()
msno.matrix(Train_data.sample(250))
plt.show()
运行结果:
SaleID 0
name 0
regDate 0
model 1
brand 0
bodyType 4506
fuelType 8680
gearbox 5981
power 0
kilometer 0
notRepairedDamage 0
regionCode 0
seller 0
offerType 0
creatDate 0
price 0
v_0 0
v_1 0
v_2 0
v_3 0
v_4 0
v_5 0
v_6 0
v_7 0
v_8 0
v_9 0
v_10 0
v_11 0
v_12 0
v_13 0
v_14 0
dtype: int64
nan可视化
[图片上传失败...(image-52e663-1585054900291)]
bar通过以上nan可视化可以很直观地了解哪些列存在缺省值,主要的目的在于nan存在的个数是否真的很大,如果很小的话一般选择填充,如果使用lgb等树模型可以直接空缺,让树自己去优化,但如果nan存在的过多、可以考虑删掉。
在上面查看异常值缺省时,除了notRepairedDamage为object类型其他都为数字,下面我们将这一项里面的不同的值显示一下:
print(Train_data['notRepairedDamage'].value_counts())
显示结果:
0.0 111361
- 24324
1.0 14315
Name: notRepairedDamage, dtype: int64
其中’_‘也是缺省值,这里我们先替换成nan
Train_data['notRepairedDamage'].replace('_', np.nan, inplace = True)
print(Train_data['notRepairedDamage'].value_counts())
print(Train_data.isnull().sum())#判断缺省值
删除特征倾斜严重的类别
del Train_data['seller']
del Train_date['offerType']
了解预测值的分布
print(Train_date['price'].value_counts())
## 1) 总体分布概况(无界约翰逊分布等)
import scipy.stats as st
y = Train_data['price']
plt.figure(1); plt.title('Johnson SU')
sns.distplot(y, kde=False, fit=st.johnsonsu)
plt.figure(2); plt.title('Normal')
sns.distplot(y, kde=False, fit=st.norm)
plt.figure(3); plt.title('Log Normal')
sns.distplot(y, kde=False, fit=st.lognorm)
结果如下:
500 2337
1500 2158
1200 1922
1000 1850
2500 1821
...
25321 1
8886 1
8801 1
37920 1
8188 1
Name: price, Length: 3763, dtype: int64
[图片上传失败...(image-ac795-1585054900291)]
价格不服从正态分布,所以在进行回归之前,它必须进行转换。
对于线性回归模型,当因变量
## 2) 查看skewness and kurtosis
plt.figure(1)
sns.distplot(Train_data['price']);
print("Skewness: %f" % Train_data['price'].skew())
print("Kurtosis: %f" % Train_data['price'].kurt())
plt.figure(2)
sns.distplot(Train_data.skew(),color='blue',axlabel ='Skewness')
plt.figure(3)
sns.distplot(Train_data.kurt(),color='orange',axlabel ='Kurtness')
plt.show()
#运行结果
Skewness: 3.346487
Kurtosis: 18.995183
image
skewness表示偏度,描述的是总体取值分布的对称性,是由三阶中心距计算出来的。
kurtosis表示峰度,描述的是数据分布顶的尖锐程度,是由四阶标准距计算出来的
## 3) 查看预测值的具体频数
plt.hist(Train_data['price'], orientation = 'vertical',histtype = 'bar', color ='red')
plt.show()
[图片上传失败...(image-e2da3e-1585054900291)]
查看频数,大于20000的值极少,然后将它进行log变换试一下。
# log变换 z之后的分布较均匀,可以进行log变换进行预测,这也是预测问题常用的trick
plt.hist(np.log(Train_data['price']), orientation = 'vertical',histtype = 'bar', color ='red')
plt.show()
image
特征分为类别特征和数字特征,并对类别特征查看unique分布
数据类型:
name - 汽车编码
regDate - 汽车注册时间
model - 车型编码
brand - 品牌
bodyType - 车身类型
fuelType - 燃油类型
gearbox - 变速箱
power - 汽车功率
kilometer - 汽车行驶公里
notRepairedDamage - 汽车有尚未修复的损坏
regionCode - 看车地区编码
seller - 销售方 【以删】
offerType - 报价类型 【以删】
creatDate - 广告发布时间
price - 汽车价格
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'【匿名特征,包含v0-14在内15个匿名特征】
# 分离label即预测值
Y_train = Train_data['price']
numeric_features = ['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' ]
categorical_features = ['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage', 'regionCode',]
# 特征nunique分布
for cat_fea in categorical_features:
print(cat_fea + "的特征分布如下:")
print("{}特征有个{}不同的值".format(cat_fea, Train_data[cat_fea].nunique()))
print(Train_data[cat_fea].value_counts())
结果示例:
Name: fuelType, dtype: int64
gearbox的特征分布如下:
gearbox特征有个2不同的值
0.0 111623
1.0 32396
Name: gearbox, dtype: int64
notRepairedDamage的特征分布如下:
notRepairedDamage特征有个2不同的值
0.0 111361
1.0 14315
数字特征分析
numeric_features.append('price')
print(numeric_features)
## 1) 相关性分析
price_numeric = Train_data[numeric_features]
correlation = price_numeric.corr()#生成相关系数矩阵
print(correlation['price'].sort_values(ascending = False),'\n')#按照某个字段中的数据进行排序
f , ax = plt.subplots(figsize = (7, 7))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True, vmax=0.8)
plt.show()
del price_numeric['price']
## 2) 查看几个特征得 偏度和峰值
for col in numeric_features:
print('{:15}'.format(col),
'Skewness: {:05.2f}'.format(Train_data[col].skew()) ,
' ' ,
'Kurtosis: {:06.2f}'.format(Train_data[col].kurt())
)
## 3) 每个数字特征得分布可视化
f = pd.melt(Train_data, value_vars=numeric_features)#melt进行格式转换
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False)# FacetFrid 多图共放初始化
g = g.map(sns.distplot, "value")#map应用上一行数据
## 4) 数字特征相互之间的关系可视化
sns.set()
columns = ['price', 'v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']
sns.pairplot(Train_data[columns],size = 2 ,kind ='scatter',diag_kind='kde')#使用kde查看匿名特征相对分布
plt.show()
print(Train_data.columns)#打印索引
print(y_train)
运行结果:
[图片上传失败...(image-d1fce-1585054900291)]
power Skewness: 65.86 Kurtosis: 5733.45
kilometer Skewness: -1.53 Kurtosis: 001.14
v_0 Skewness: -1.32 Kurtosis: 003.99
v_1 Skewness: 00.36 Kurtosis: -01.75
v_2 Skewness: 04.84 Kurtosis: 023.86
v_3 Skewness: 00.11 Kurtosis: -00.42
v_4 Skewness: 00.37 Kurtosis: -00.20
v_5 Skewness: -4.74 Kurtosis: 022.93
v_6 Skewness: 00.37 Kurtosis: -01.74
v_7 Skewness: 05.13 Kurtosis: 025.85
v_8 Skewness: 00.20 Kurtosis: -00.64
v_9 Skewness: 00.42 Kurtosis: -00.32
v_10 Skewness: 00.03 Kurtosis: -00.58
v_11 Skewness: 03.03 Kurtosis: 012.57
v_12 Skewness: 00.37 Kurtosis: 000.27
v_13 Skewness: 00.27 Kurtosis: -00.44
v_14 Skewness: -1.19 Kurtosis: 002.39
price Skewness: 03.35 Kurtosis: 019.00
Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',
'gearbox', 'power', 'kilometer', 'notRepairedDamage', 'regionCode',
'creatDate', 'price', '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'],
dtype='object')
0 1850
1 3600
2 6222
3 2400
...
149997 7500
149998 4999
149999 4700
Name: price, Length: 150000, dtype: int64
图片太大就不放了
多变量关系可视化
## 5) 多变量互相回归关系可视化
fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6), (ax7, ax8), (ax9, ax10)) = plt.subplots(nrows=5, ncols=2, figsize=(24, 20))#分成5*2个格子,每个格子的内容由下所示
# ['v_12', 'v_8' , 'v_0', 'power', 'v_5', 'v_2', 'v_6', 'v_1', 'v_14']
v_12_scatter_plot = pd.concat([Y_train,Train_data['v_12']],axis = 1)
sns.regplot(x='v_12',y = 'price', data = v_12_scatter_plot,scatter= True, fit_reg=True, ax=ax1)#使用函数regplot回归分析绘图,通过date绘制出回归分析线
v_8_scatter_plot = pd.concat([Y_train,Train_data['v_8']],axis = 1)
sns.regplot(x='v_8',y = 'price',data = v_8_scatter_plot,scatter= True, fit_reg=True, ax=ax2)
v_0_scatter_plot = pd.concat([Y_train,Train_data['v_0']],axis = 1)
sns.regplot(x='v_0',y = 'price',data = v_0_scatter_plot,scatter= True, fit_reg=True, ax=ax3)
power_scatter_plot = pd.concat([Y_train,Train_data['power']],axis = 1)
sns.regplot(x='power',y = 'price',data = power_scatter_plot,scatter= True, fit_reg=True, ax=ax4)
v_5_scatter_plot = pd.concat([Y_train,Train_data['v_5']],axis = 1)
sns.regplot(x='v_5',y = 'price',data = v_5_scatter_plot,scatter= True, fit_reg=True, ax=ax5)
v_2_scatter_plot = pd.concat([Y_train,Train_data['v_2']],axis = 1)
sns.regplot(x='v_2',y = 'price',data = v_2_scatter_plot,scatter= True, fit_reg=True, ax=ax6)
v_6_scatter_plot = pd.concat([Y_train,Train_data['v_6']],axis = 1)
sns.regplot(x='v_6',y = 'price',data = v_6_scatter_plot,scatter= True, fit_reg=True, ax=ax7)
v_1_scatter_plot = pd.concat([Y_train,Train_data['v_1']],axis = 1)
sns.regplot(x='v_1',y = 'price',data = v_1_scatter_plot,scatter= True, fit_reg=True, ax=ax8)
v_14_scatter_plot = pd.concat([Y_train,Train_data['v_14']],axis = 1)
sns.regplot(x='v_14',y = 'price',data = v_14_scatter_plot,scatter= True, fit_reg=True, ax=ax9)
v_13_scatter_plot = pd.concat([Y_train,Train_data['v_13']],axis = 1)
sns.regplot(x='v_13',y = 'price',data = v_13_scatter_plot,scatter= True, fit_reg=True, ax=ax10)
类别特征分析
## 1) unique分布
for fea in categorical_features:
print(Train_data[fea].nunique())#返回唯一值的个数
print(categorical_features)
#运行结果:
99662
248
40
8
7
2
3
7905
['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage', 'regionCode']
## 2) 类别特征箱形图可视化
# 因为 name和 regionCode的类别太稀疏了,这里我们把不稀疏的几类画一下
categorical_features = ['model',
'brand',
'bodyType',
'fuelType',
'gearbox',
'notRepairedDamage']
for c in categorical_features:
Train_data[c] = Train_data[c].astype('category')#转化为category类型
if Train_data[c].isnull().any():
Train_data[c] = Train_data[c].cat.add_categories(['MISSING'])
Train_data[c] = Train_data[c].fillna('MISSING')
def boxplot(x, y, **kwargs):
sns.boxplot(x=x, y=y)
x=plt.xticks(rotation=90)
f = pd.melt(Train_data, id_vars=['price'], value_vars=categorical_features)
g = sns.FacetGrid(f, col="variable", col_wrap=2, sharex=False, sharey=False, size=5)
g = g.map(boxplot, "value", "price")
后续再记!!!
网友评论