线性回归-2-简单线性回归的代码实现

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

上篇文章简单介绍了简单线性回归,并从数学角度加以理解,本篇文章使用python实现一个简单的线性回归小例子。

1、简单线性回归算法的实现

1.1、数据源引入

首先引入一个数据源,该数据源中保存了工作年限与薪水的若干条相关信息

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

income = pd.read_csv(r'./file/Salary_Data.csv')
income.head()
# 绘制散点图
sns.lmplot(x = 'YearsExperience'
           , y = 'Salary'
           , data = income
           , ci = None
           , fit_reg=True)
# 显示图形
plt.show()
output_6_1.png

这里使用seaborn可以直接得到拟合的直线,这条直线就是我们需要预测的。

1.2、思路梳理

首先,我们可以假设线性关系为:y = ax + b 这根直线,然后再根据最小二乘法算a、b的值。我们还可以假设为二次函数:y = ax^2 + bx + c。可以通过最小二乘法算出a、b、c

实际上,同一组数据,选择不同的f(x),即模型,通过最小二乘法可以得到不一样的拟合曲线。不同的数据,更可以选择不同的函数,通过最小二乘法可以得到不一样的拟合曲线。

在本篇文章中,我们直接假设模型是一条直线,模型是:\sum_{i=1}^{m}\left(y^{(i)}-\hat{y}^{(i)}\right)^{2}

根据最小二乘法推导求出a、b的表达式:
a=\frac{\sum_{i=1}^{m}\left(x^{i}-\bar{x}\right)\left(y^{i}-\bar{y}\right)}{\sum_{i=1}^{m}\left(x^{(i)}-\bar{x}\right)^{2}} \quad b=\bar{y}-a \bar{x}

1.3、编码实现

首先我们计算xy的均值,通过均值计算ab的值

x_mean = round(income.YearsExperience.mean(),2)
y_mean = income.Salary.mean()
x_mean
y_mean
a_upper = 0.0
a_lower = 0.0

# for i,k in enumerate(income.YearsExperience):
#     a_upper += (k - x_mean)*(income.Salary[i] - y_mean)
#     a_lower += (k - x_mean)**2

# 或者写成一下形式,同时思考一下,在大量数据的情况下有何优化措施?
for x_i,y_i in zip(income.YearsExperience, income.Salary):   # zip函数打包成[(x_i,y_i)...]的形式
    a_upper = a_upper + (x_i - x_mean) * (y_i - y_mean)
    a_lower = a_lower + (x_i - x_mean) ** 2
    
a = a_upper/a_lower
b = y_mean - a * x_mean
a
b
5.31


76003.0


9449.94883432168


25823.771689751884

我们使用拟合好的模型预测样本中的y值并直接可视化,看看与seaborn中的是否相似

import matplotlib.pyplot as plt
%matplotlib inline

y_pre = a*income.YearsExperience + b
plt.figure(figsize=(4^2,4^2))
plt.scatter(income.YearsExperience, income.Salary)    # 绘制散点图
plt.plot(income.YearsExperience, y_pre,color='r')    # 绘制直线

2、numpy向量化运算

2.1、向量化运算简介与使用

我们可以使用numpy中的dot运算,非常快速地进行向量化运算。下面来介绍一下dot的使用:

dot()返回的是两个数组的点积(dot product)

如果处理的是一维数组,则得到的是两数组的內积

import numpy as np
d = np.arange(0,9)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8])
e = d[::-1]
# array([8, 7, 6, 5, 4, 3, 2, 1, 0])
np.dot(d,e) 
84

如果是二维数组(矩阵)之间的运算,则得到的是矩阵积(mastrix product)。

a = np.arange(1,5).reshape(2,2)

# array([[1, 2],
#      [3, 4]])

b = np.arange(5,9).reshape(2,2)
# array([[5, 6],
#       [7, 8]])
np.dot(a,b)

array([[19, 22],
       [43, 50]])

所得到的数组中的每个元素为:第一个矩阵中与该元素行号相同的元素与第二个矩阵与该元素列号相同的元素,两两相乘后再求和。下面使用一张图片理解这句话。

点积.png

此时我们再来看我们之前写的代码:

for x_i,y_i in zip(income.YearsExperience, income.Salary):   # zip函数打包成[(x_i,y_i)...]的形式
    a_upper = a_upper + (x_i - x_mean) * (y_i - y_mean)
    a_lower = a_lower + (x_i - x_mean) ** 2

a_upper = a_upper + (x_i - x_mean) * (y_i - y_mean)

实际上就是两数组的内积
可以写成

(income.YearsExperience - x_mean).dot(income.Salary - y_mean)

2.2、向量化运算的优点

向量化是非常常用的加速计算的方式,特别适合深度学习等需要训练大数据的领域。

以本文中的数据为例,比较向量化运算与普通计算速度的差异:

import time

a = income.YearsExperience
b = income.Salary
for i in range(500):
    a = a.append(income.YearsExperience)
    b = b.append(income.Salary)
a = a.reset_index()
b = b.reset_index()
tic = time.time()
c = np.dot(a.YearsExperience, b.Salary)
toc = time.time()
# print(len(a))
print("c: %f" % c)
print("vectorized version:" + str(1000*(toc-tic)) + "ms")

c = 0
tic = time.time()
for i in range(len(a)):
    c += a.YearsExperience[i] * b.Salary[i]
toc = time.time()
print("c: %f" % c)
print("for loop:" + str(1000*(toc-tic)) + "ms")
c: 7175302461.000004
vectorized version:0.0ms
c: 7175302460.999892
for loop:752.0430088043213ms

对于独立的样本,用for循环串行计算的效率远远低于向量化后,用矩阵方式并行计算的效率。因此:

只要有其他可能,就不要使用显示for循环。

3、简单的代码封装与调用

3.1、封装

%%writefile SimpleLinearRegression.py

import numpy as np

class SimpleLinearRegression:
    def __init__(self):
        """模型初始化函数"""
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """根据训练数据集x_train,y_train训练模型"""
        assert x_train.ndim ==1, "简单线性回归模型仅能够处理一维特征向量"
        assert len(x_train) == len(y_train), "特征向量的长度和标签的长度相同"
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        num = (x_train - x_mean).dot(y_train - y_mean)  # 分子
        d = (x_train - x_mean).dot(x_train - x_mean)    # 分母
        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        """给定待预测数据集x_predict,返回表示x_predict的结果向量"""
        assert x_predict.ndim == 1, \
            "简单线性回归模型仅能够处理一维特征向量"
        assert self.a_ is not None and self.b_ is not None, \
            "先训练之后才能预测"
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        """给定单个待预测数据x_single,返回x_single的预测结果值"""
        return self.a_ * x_single + self.b_

    def __repr__(self):
        """返回一个可以用来表示对象的可打印字符串"""
        return "SimpleLinearRegression()"
Overwriting SimpleLinearRegression.py

3.2、调用

from SimpleLinearRegression import SimpleLinearRegression

x = income.YearsExperience
y = income.Salary

reg = SimpleLinearRegression()
reg.fit(x,y)


reg.a_
reg.b_
9449.962321455077


25792.20019866869
x_predict = np.array([6])

reg.predict(x_predict)
array([82491.9741274])
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339