zoukankan      html  css  js  c++  java
  • 手撸机器学习算法

    系列文章目录:

    算法介绍

    今天我们来一起学习一个除了线性回归外最最最简单的回归算法:多项式回归

    从线性回归到多项式回归

    事实上与线性回归相比,多项式回归没有增加任何需要推导的东西,唯一增加的是对原始数据进行多项式特征转换,这有点类似我们在非线性问题中对特征的处理:将(x_1)转换为(x_1^2),之前我们是通过对数据的探索来决定如何进行转换,在多项式回归中,则是简单的指定一个阶,然后对所有列构建N元N次的方程中的所有项即可,这么说有点抽象,下面举个简单的例子:
    对有两个特征的数据做三阶的多项式特征转换:(x_1 + x_2) 转换为 (x_1^3 + x_2^3 + x_1^2*x_2 + x_2^2*x_1 + x_1^2 + x_2^2 + x_1*x_2 + x_1 + x_2),可以看到,通过做三阶变换,特征数从两个增长到了九个,多项式特征转换是非常简单且实用的构建特征手段之一,它不仅能构建特征自身的高阶版,同时还能构建特征与特征之间的组合特征,通常效果都不错哦;

    代码实现

    上面说了,多项式回归与线性回归唯一区别就在多项式特征构建上,因此代码部分也主要关注这一点,关于多项式特征构建,大家既可以基于sklearn库中的方法实现,也可以自己实现,都很简单哈;

    sklearn实现多项式特征构建

    from sklearn.preprocessing import PolynomialFeatures
    poly = PolynomialFeatures(degrees)
    X = poly.fit_transform(X)
    

    自己实现多项式特征构建

    def build_combs(self,elements,times):
        '''
        构建多项式的元组合
        elements 元数
        times 次数
        '''
        x_list = sum([[i]*times for i in range(elements)],[])
        combs = sum([list(set(combinations(x_list,i))) for i in range(1,times+1)],[])
        return [list(comb) for comb in combs]
    
    def polynomial(self,x):
        '''
        x shape = [1 N]
        '''
        fun = lambda x,y:x*y
        return [reduce(fun,x[comb]) for comb in self.combs]
    

    运行结果

    全部代码

    多项式回归代码

    import numpy as np
    from itertools import combinations
    from functools import reduce
    from 线性回归最小二乘法矩阵实现 import LinearRegression as LR
    
    class PolynomialRegression(LR):
        def __init__(self,X,y,degrees=1):
            self.combs = self.build_combs(X.shape[1],degrees)
            X = np.array([self.polynomial(x) for x in X])
            super(PolynomialRegression,self).__init__(X,y)
    
        def predict(self,x):
            x = self.polynomial(x)
            return super(PolynomialRegression,self).predict(x)
    
        def build_combs(self,elements,times):
            '''
            构建多项式的元组合
            elements 元数
            times 次数
            '''
            x_list = sum([[i]*times for i in range(elements)],[]) # 二元二次 [1 1 2 2]
            combs = sum([list(set(combinations(x_list,i))) for i in range(1,times+1)],[]) # 二元二次 [[1 1] [2 2] [1 2] [1] [2]]
            return [list(comb) for comb in combs]
    
        def polynomial(self,x):
            '''
            x shape = [1 N]
            '''
            fun = lambda x,y:x*y
            return [reduce(fun,x[comb]) for comb in self.combs]
    
    

    测试代码

    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.model_selection import train_test_split as tts
    from 多项式回归 import PolynomialRegression as PR
    
    rnd = np.random.RandomState(3)
    x_min, x_max = 0, 10
    
    def pain(pos=141,xlabel='x',ylabel='y',title='',x=[],y=[],line_x=[],line_y=[]):
        plt.subplot(pos)
        plt.title(title)
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        plt.scatter(x,y)
        plt.plot(line_x,line_y)
    
    # 上帝函数 y=f(x)
    def f(x):
        return x**5-22*x**4+161*x**3-403*x**2+36*x+938
    
    # 上帝分布 P(Y|X)
    def P(X):
        return f(X) + rnd.normal(scale=30, size=X.shape)
    
    # 通过 P(X, Y) 生成数据集 D
    X = rnd.uniform(x_min, x_max, 50)   # 通过均匀分布产生 X
    y = P(X)                            # 通过 P(Y|X) 产生 y
    
    plt.subplot(332)
    plt.scatter(x=X, y=y)
    xx = np.linspace(x_min, x_max)
    plt.plot(xx, f(xx), 'k--')
    
    X_train,X_test,y_train,y_test = tts(X,y,test_size=0.3,random_state=10086)
    X_train,X_test,y_train,y_test = X_train.reshape(-1,1),X_test.reshape(-1,1),y_train.reshape(-1,1),y_test.reshape(-1,1)
    
    for pos,deg in zip([334,335,336,337,338,339],[1,3,5,8,15,20]):
        model = PR(X=X_train,y=y_train,degrees=deg)
        w,b = model.train()
        x_min,x_max = min(X_train),max(X_train)
        line_x = [x_min+(x_max-x_min)*(i/100) for i in range(100)]
        line_y = [model.predict(x) for x in line_x]
        pain(pos,'x','y','DEG='+str(deg),X_train[:,0],y_train[:,0],line_x,line_y)
    
    plt.tight_layout()
    plt.show()
    

    最后

    可以看到,实际上多项式回归是非常简单的,实际应用上对于很多简单任务的拟合效果也非常好,解释性也不错;

    作者:Ho Loong
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    AtCoder Beginner Contest 167
    AtCoder Beginner Contest 165
    Codeforces Round #732 (Div. 2)
    【贪心 + 模拟】UVA10382 Watering Grass
    【BCC】冗余路径(做法 + 证明)
    数据库作业[定时执行任务]的创建(转)
    SQL数据类型大全 《转自网络》
    C#的OpenFileDialog和SaveFileDialog的常见用法(转)
    团队展示(团队)
    高级软件工程第一次作业--准备
  • 原文地址:https://www.cnblogs.com/helongBlog/p/14892200.html
Copyright © 2011-2022 走看看