机器学习学习过程中遇到了一些困惑的问题,决定用试验的方法进行甄别、吃透。数学试验就是通过自创建的数据集运行算法,对比分析算法及参数的影响。自创的数据集有明确的规律和噪声,比公共数据集(如IRIS数据集等)能更高效的分析和研究。以后新学的机器学习知识和疑惑都应通过试验的方法研究吃透。
作为统计学习的方法,训练样本的分布对预测结果肯定会产生很重要的影响,我们自然要问,多密的样本才是足够的?样本如果存在缺失,不能覆盖测试样本时会有多大误差?怎么解决样本不足时,即小样本情况下的学习问题?本文对此进行试验分析。
本次试验:以y=sinx1+cosx2为例,研究样本分布对结果的影响。使用lightGBM.LGBMRegressor()算法。
# -*- coding: utf-8 -*-
""" Created on Thu Jul 26 06:25:42 2018 @author: Administrator """
import numpy as np
import pandas as pd
import math
import lightgbm as lgb
def gen_train_test():
table_train=pd.DataFrame(columns=['x1','x2','y'])
np.random.seed(0)
table_train['x1']=np.random.rand(10000)*2*(math.pi)
table_train['x2']=np.random.rand(10000)*2*(math.pi)
table_train['y']=table_train.x1.apply(lambda x:math.sin(x))+table_train.x2.apply(lambda x:math.cos(x))
table_test=pd.DataFrame(columns=['x1','x2'])
table_test['x1']=np.random.rand(10000)*2*(math.pi)
table_test['x2']=np.random.rand(10000)*2*(math.pi)
return table_train,table_test
def gen_xy(table_train,table_test):
x_train=table_train[['x1','x2']]
x_test =table_test[['x1','x2']]
y_train=table_train[['y']]
x_train = np.asarray(x_train)
y_train = np.asarray(y_train)
x_test = np.asarray(x_test)
return x_train,y_train,x_test
def my_RMSE(table_test,y_test):
table_test['y_test_real']=table_test.x1.apply(lambda x:math.sin(x))+table_test.x2.apply(lambda x:math.cos(x))
table_test['y_test']=y_test
RMSE=((table_test.y_test_real-table_test.y_test)**2).sum()/len(table_test)
print('RMSE is %.4f!'%RMSE)
return RMSE
def lgbR(x_train,y_train,x_test):
regr = lgb.LGBMRegressor(num_leaves=31, learning_rate=0.1, n_estimators=160, silent=False,num_threads=-1)
regr.fit(x_train, y_train)
y_test = regr.predict(x_test)
print("Training score:%f"%(regr.score(x_train,y_train)))
return y_test
table_train,table_test = gen_train_test()
x_train,y_train,x_test = gen_xy(table_train,table_test)
y_test = lgbR(x_train,y_train,x_test)
RMSE = my_RMSE(table_test,y_test)
运行结果:
Training score:0.999653
RMSE is 0.0005!
画出测试集中x1、x2和y_test及y_test_real的关系
import matplotlib.pyplot as plt
plt.plot(table_test.x1,table_test.y_test,’.’)
plt.plot(table_test.x2,table_test.y_test,’.’)
plt.plot(table_test.x1,table_test.y_test_real,’.’)
plt.plot(table_test.x2,table_test.y_test_real,’.’)

图中蓝色为预测值,红色为真实值。由于数据中的函数关系非常明确及简单,lgb预测的结果非常准确。下面开始试验不同样本分布对结果的影响:
使测试集中特征向量x1,x2的取值范围为0~2π,使训练集中特征向量x1,x2的取值范围为0~1.8π:
def gen_train_test():
......
table_train['x1']=np.random.rand(10000)*1.8*(math.pi)
table_train['x2']=np.random.rand(10000)*1.8*(math.pi)
运行结果为:
Training score:0.999717
RMSE is 0.0167!

可以看出,由于训练样本的范围没有能够覆盖测试样本,因此预测误差急剧增加,从图片中看,产生误差的原因是对于未覆盖部分样本,lgb算法是按照边界值来进行预测的。也就是说机器学习算法缺乏数据样本的外延性。
使测试集中特征向量x1,x2的取值范围为0~2π,使训练集中特征向量x1,x2的取值范围为(0~0.9π)U(1.1π~2π):
def gen_train_test():
......
table_train = table_train[(table_train.x1<0.9*math.pi)|(table_train.x1>1.1*math.pi)]
table_train = table_train[(table_train.x2<0.9*math.pi)|(table_train.x2>1.1*math.pi)]
运行结果为:
Training score:0.999391
RMSE is 0.0052!

可以看出,当训练样本中存在间隙时,也会带来预测误差,但和上一部分中提到的外部没有覆盖的情况相比,内部同样宽度的间隙带来的误差要小于外部空缺带来的误差。内部存在间隙时,lgb算法是按照间隙中的均值进行预测的。说明机器学习算法有一定的数据样本的内延性。
如果使用均匀间隙的训练样本,可以更明显的看出误差的原因:
def gen_train_test():
......
table_train['x1']=np.random.permutation(np.linspace(0,1,100)*2*(math.pi))
table_train['x2']=np.random.permutation(np.linspace(0,1,100)*2*(math.pi))
运行结果为:
Training score:0.939860
RMSE is 0.0872!

至此,我们可以得出结论,训练样本的间隙会对机器学习算法(仅讨论了lgb算法,其他非线性回归算法类似)的预测结果造成误差,误差的原因是算法对样本间隙按照均值处理造成的。
在训练样本中混入10%的噪声
def gen_train_test():
......
table_train['y'].iloc[np.random.choice(10000,1000)]=np.random.rand(1000)*4-2
运行结果为:
Training score:0.834473
RMSE is 0.0212!
训练标签值和测试标签值的分布(沿x1特征切面,x2特征未画)

可见,加入10%噪声后,误差有较大增长。但lightGBM有较强的去噪预测功能。
启示:可否用lightGBM对训练样本先降噪,再用降噪后的数据训练,是否会提高预测精度呢?
......
#y_test = lgbR(x_train,y_train,x_test) #替换为下面两句
y_train1=lgbR(x_train,y_train,x_train)
y_test=lgbR(x_train,y_train1,x_test)
运行结果为:
Training score:0.997589
RMSE is 0.0174!
用lightGBM对训练样本先降噪,再用降噪后的数据训练,确实有一定的效果。但效果并不是非常明显,这是因为去噪的同时也会把一些非噪声值产生一定的扰动,去噪效果主要取决于预测的效果本身,本例的预测效果非常好了,对于实际工程情况,预测效果没有这么好时,去噪后可能反而造成较多的非噪声值的扰动,反而会降低预测精度。
根据前面的讨论,对样本间隙进行插值,可以提高预测的精度。插值本身也是一种预测方法(非机器学习类方法),甚至在本例中,插值预测的精度可能还要高于lgb预测精度。python中似乎没有直接提供多维插值的算法,因此留下两个遗留题,待以后完成:
(1)编制多维插值的python程序。
(2)对比多维插值法和机器学习算法的效果,分析各自的优势。