线性回归--乐高玩具价格预测

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 线性回归--乐高玩具价格预测

数据描述:

商城的网页包含如下的乐高玩具的相关信息

页面个数:

b7c6fb70c9f0b3d8affbeff61fb96de6_20200208230917791.png

页面详细:

ea4e773c5040e237f9ee51ca7d9c2b37_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlZGEz,size_16,color_FFFFFF,t_70.png

包含的特征:

年份、乐高的部件数目、全新与否、乐高玩具的原价

预测:

当前的售价

页面的解析

使用 BeautifulSoup

 lgX=[]#存储特征值
 lgY=[]#存放标签(实际销售价格)
 setDataCollect(lgX,lgY)
"""
函数说明:依次读取六种乐高套装的数据,并生成数据矩阵
Parameters:
"""
def setDataCollect(retX, retY):
    scrapePage(retX, retY, './lego/lego8288.html', 2006, 800, 49.99)#2006年的乐高8288,部件数目800,原价49.99
    scrapePage(retX, retY, './lego/lego10030.html', 2002, 3096, 269.99)#2002年的乐高10030,部件数目3096,原价269.99
    scrapePage(retX, retY, './lego/lego10179.html', 2007, 5195, 499.99)#2007年的乐高10179,部件数目5195,原价499.99
    scrapePage(retX, retY, './lego/lego10181.html', 2007, 3428, 199.99)#2007年的乐高10181,部件数目3428,原价199.99
    scrapePage(retX, retY, './lego/lego10189.html', 2008, 5922, 299.99)#2008年的乐高10189,部件数目5922,原价299.99
    scrapePage(retX, retY, './lego/lego10196.html', 2009, 3263, 249.99)#2009年的乐高10196,部件数目3263,原价249.99
"""
函数说明:从页面读取数据,生成retX和retY列表
Parameters:
    retX - 数据X
    retY - 数据Y
    inFile - HTML文件
    yr - 年份
    numPce - 乐高部件数目
    origPrc - 原价
Returns:
    no
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-16
"""  
import numpy as np
from bs4 import BeautifulSoup
import random
def scrapePage(retX, retY, inFile, yr, numPce, origPrc):
 #    fr = open(inFile); fw=open(outFile,'a') #a is append mode writing
 #    soup = BeautifulSoup(fr.read())
     # 打开并读取HTML文件
     with open(inFile, encoding='utf-8') as f:
         html = f.read()
     soup = BeautifulSoup(html)
     i=1
     # 根据HTML页面结构进行解析
     currentRow = soup.findAll('table', r="%d" % i)
     while(len(currentRow)!=0):
         #查找标题
         title = currentRow[0].findAll('a')[1].text
         lwrTitle = title.lower()#拷贝string的副本并转换为小写
         # 查找是否有全新标签
         if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):#不存在则返回-1,否则返回当前子串所在字符串位置的索引
             newFlag = 1.0
         else:
             newFlag = 0.0
         # 查找是否已经标志出售,我们只收集已出售的数据
         soldUnicde = currentRow[0].findAll('td')[3].findAll('span')#是否在售 sold/unsold
         if len(soldUnicde)==0:
             print("item #%d did not sell" % i)#第几项--对应第几table
         else:# 解析页面获取当前价格
             soldPrice = currentRow[0].findAll('td')[4]
             priceStr = soldPrice.text
             priceStr = priceStr.replace('$','') #strips out $
             priceStr = priceStr.replace(',','') #strips out ,
             if len(soldPrice)>1:
                 priceStr = priceStr.replace('Free shipping', '') #strips out Free Shipping
             print("%s\t%d\t%s" % (priceStr,newFlag,title))#价格 全新否 题目
             #fw.write("%d\t%d\t%d\t%f\t%s\n" % (yr,numPce,newFlag,origPrc,priceStr))
             sellingPrice = float(priceStr)
             # 去掉不完整的套装价格
             if  sellingPrice > origPrc * 0.5:#大于原价的一半则留下
                 #输出年份--乐高部件数目--全新与否--原价--销售价格(待预测量)
                 print("%d\t%d\t%d\t%f\t%f" % (yr, numPce, newFlag, origPrc, sellingPrice))
                 retX.append([yr, numPce, newFlag, origPrc])#年份--乐高部件数目--全新与否--原价(特征)
                 retY.append(sellingPrice)#真实值
         i += 1
         currentRow = soup.findAll('table', r="%d" % i)

页面的表格结构:

09419b84bd825e88dcc276105a366b7e_20200208234446729.png

1)解析标题

09419b84bd825e88dcc276105a366b7e_20200208234446729.png

2)全新与否的解析

3)是否出售,只解析待销售的乐高玩具

86f2af5e003f12f3fe0e3c40484d5366_2020020823502653.png

–解析页面获取当前价格

注意的是:去掉不完整的套装价格(判断依据售价大于原价的一半则留下,否则认为套装不完整)

将以上每个条目(Table):年份、乐高的部件数目、全新与否、乐高玩具的原价构成特征向量

售价作为标签

建立模型预测

数据预处理

添加常数项特征:总共5个特征

shape(lgX)
lgX1=mat(ones((63,5)))#年份--乐高部件数目--全新与否--原价(特征) +常数项特征x0=1
lgX1[:,1:5]=mat(lgX)
lgX[0]#测试
lgX1[0]#测试

数据回归分析

标准回归及测试
##标准回归
ws=standRegres(lgX1,lgY)
ws#测试
###单个样本预测
lgX1[0]*ws
lgX1[-1]*ws
lgX1[43]*ws
###多个样本的预测误差
yHat=lgX1*ws#标准线性回归预测
rssError(lgY,yHat.T.A)
"""
函数说明:标准回归
Parameters:
    xArr - 特征矩阵
    yArr -响应值
Returns:
     ws- 回归系数
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-10
"""   
def standRegres(xArr,yArr):
    xMat = mat(xArr); yMat = mat(yArr).T
    xTx = xMat.T*xMat#计算xTx
    if linalg.det(xTx) == 0.0:#判断行列式是否为0
        print("This matrix is singular, cannot do inverse")
        return
    ws = xTx.I * (xMat.T*yMat)#计算回归系数
    return ws

误差计算函数

"""
函数说明:平方误差函数
Parameters:
Returns:
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-10
"""  
def rssError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
    return ((yArr-yHatArr)**2).sum()

实验结果:

和标准的售价的均方误差和

交叉验证–岭回归

1)采用10折交叉验证以评估岭回归参数;

2)每一折验证:随机打乱数据,其中训练集和测试集的划分 90%训练 10%测试;

3)10(10折)x30(岭回归参数),通过按照列取平均可获得每个岭回归参数的10折交叉验证平均值,找出误差最小的岭回归参数。

4)数据的还原

可参考博客的数据标准化与去标准化部分的描述:回归分析及实际案例:预测鲍鱼年龄

在岭回归中要求数据要标准化再参与计算,那么在训练完成后新的数据如何进行预测?这个新的数据怎么利用训练的数据进行标准化?

解决方法是:利用在训练数据中得出的回归参数,通过变换实现变相的在新数据预测时的标准化

新的数据一般预测过程:

数据标准化:XT=(XTest-mean(XTrain))/Var(XTrain)

预测:Ytest=XT*Ws+mean(YTrain)

将上述的公式变换:

Ytest=((XTest-mean(XTrain))/Var(XTrain))*Ws+mean(YTrain)

设UnReg=Ws/Var(XTrain)

constantTerm=-mean(XTrain)*Ws/Var(XTrain)+mean(YTrain)

则Ytest=XTest*UnReg+constantTerm(现在的新变换后的预测过程)

##交叉验证--岭回归
ridgeWs,ridgeunReg,ridgeConstantTerm=crossValidation(lgX,lgY,10)#目的是找出最佳的岭回归系数
##测试均方误差
####和标准线性回归的比较
##第一种计算思路:
ridgeW=mat(ones((1,5)))#回归系数的重新组合
ridgeW[0,0]=ridgeConstantTerm
ridgeW[0,1:5]=ridgeunReg
ridgeyHat=lgX1*ridgeW.T#岭回归预测
rssError(lgY,ridgeyHat.T.A)#误差计算
##第二种计算的思路:
xMat=mat(lgX)
yMat=mat(lgY)
ridgeyHat=xMat*ridgeunReg.T+ridgeConstantTerm#岭回归预测
rssError(yMat.A,ridgeyHat.T.A)#误差计算
"""
函数说明:交叉验证测试岭回归
Parameters:
    xArr - 特征
    yArr - 标签
    numVal=10 - 交叉验证的次数
Returns: 
    bestWeights 最佳的岭回归参数
    为了和标准线性回归比较
    unReg,constantTerm 数据标准化还原后的特征参数和常量参数
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-28
""" 
def crossValidation(xArr,yArr,numVal=10):
    m = len(yArr)#样本点个数                           
    indexList = list(range(m))
    errorMat = zeros((numVal,30))#create error mat 30columns numVal rows
    for i in range(numVal):#交叉验证
        trainX=[]; trainY=[]
        testX = []; testY = []
        random.shuffle(indexList)#随机打乱样本索引
        #训练集和测试集的划分 90%训练  10%测试
        for j in range(m):#create training set based on first 90% of values in indexList
            if j < m*0.9: 
                trainX.append(xArr[indexList[j]])
                trainY.append(yArr[indexList[j]])
            else:
                testX.append(xArr[indexList[j]])
                testY.append(yArr[indexList[j]])
        #岭回归(岭回归次数默认)
        wMat = ridgeTest(trainX,trainY)    #30*特征数 get 30 weight vectors from ridge
        #30组回归系数
        for k in range(30):#loop over all of the ridge estimates
            matTestX = mat(testX); matTrainX=mat(trainX)
            meanTrain = mean(matTrainX,0)
            varTrain = var(matTrainX,0)
            matTestX = (matTestX-meanTrain)/varTrain #regularize test with training params
            yEst = matTestX * mat(wMat[k,:]).T + mean(trainY)#test ridge results and store
            errorMat[i,k]=rssError(yEst.T.A,array(testY))
            #print errorMat[i,k]
    #计算所有这些误差值的均值
    meanErrors = mean(errorMat,0)#errorMat为 10*30   30个岭回归参数  10次交叉验证  按照把轴向数据求平均  得到每列数据的平均值,也即是10折交叉验证的平均   calc avg performance of the different ridge weight vectors
    minMean = float(min(meanErrors))#哪个岭回归参数下的误差最小
    bestWeights = wMat[nonzero(meanErrors==minMean)]#找出误差最小的回归参数
    #can unregularize to get model
    #when we regularized we wrote Xreg = (x-meanX)/var(x)
    #we can now write in terms of x not Xreg:  x*w/var(x) - meanX/var(x) +meanY
    xMat = mat(xArr); yMat=mat(yArr).T
    meanX = mean(xMat,0); varX = var(xMat,0)
    unReg = bestWeights/varX
    print("the best model from Ridge Regression is:\n",unReg)
    #标准化后数据还原
    constantTerm=-1*sum(multiply(meanX,unReg)) + mean(yMat)
    print("with constant term: ",constantTerm)
    return bestWeights,unReg,constantTerm

实验结果

31abeda4e5d011a113f8e8731bf4b409_20200209130813523.png

标准线性回归和岭回归得出的拟合结果差不多,没有实现很好的拟合效果!

可进一步观察岭回归过程中的参数变换情况:

ridgeTest(lgX,lgY)#返回30组不同参数下的回归系数
"""
函数说明:岭回归
Parameters:
    xMat- 数据的特征 假设有n 样本个数有m
    yMat- 响应值
    lam-- 调节的参数
Returns:
     ws-- 计算出的回归系数
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-10
"""  
def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat#2*2   n*n
    denom = xTx + eye(shape(xMat)[1])*lam#n*n
    if linalg.det(denom) == 0.0:
        print("This matrix is singular, cannot do inverse")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws
"""
函数说明:岭回归参数lambda调节
Parameters:
    xArr- 特征矩阵
    yArr- 响应值
Returns:
    wMat - 返回一组w(维数和特征数对应)系数
Author:
    heda3
Blog:
    https://blog.csdn.net/heda3
Modify:
    2020-01-10
"""  
def ridgeTest(xArr,yArr):
    xMat = mat(xArr); yMat=mat(yArr).T
    #数据标准化处理
    yMean = mean(yMat,0)
    yMat = yMat - yMean     #to eliminate X0 take mean off of Y
    #regularize X's
    xMeans = mean(xMat,0)   #calc mean then subtract it off
    xVar = var(xMat,0)      #calc variance of Xi then divide by it
    xMat = (xMat - xMeans)/xVar
    numTestPts = 30#设置lambda参数迭代次数
    wMat = zeros((numTestPts,shape(xMat)[1]))#30*2的矩阵
    for i in range(numTestPts):
        ws = ridgeRegres(xMat,yMat,exp(i-10))
        wMat[i,:]=ws.T
    return wMat

《机器学习实战》

目录
相关文章
|
5天前
|
机器学习/深度学习 数据采集 供应链
使用Python实现智能食品价格预测的深度学习模型
使用Python实现智能食品价格预测的深度学习模型
29 6
|
2月前
|
机器学习/深度学习 自然语言处理 搜索推荐
基于图神经网络的电商购买预测
基于图神经网络的电商购买预测
|
3月前
|
机器学习/深度学习 数据采集 算法
基于机器学习的二手房价格分析与预测设计与实现
本文通过机器学习技术对西安市二手房市场价格进行分析与预测,利用数据预处理、特征提取和模型训练,深入挖掘影响房价的关键因素,旨在为市场参与者提供科学的定价信息和决策支持。
111 1
基于机器学习的二手房价格分析与预测设计与实现
|
6月前
|
机器学习/深度学习 数据采集 人工智能
SPSS modeler利用类神经网络对茅台股价涨跌幅度进行预测
SPSS modeler利用类神经网络对茅台股价涨跌幅度进行预测
|
6月前
|
数据可视化
数据分享|R语言逐步回归模型对电影票房、放映场数、观影人数预测可视化2
数据分享|R语言逐步回归模型对电影票房、放映场数、观影人数预测可视化
|
6月前
|
数据可视化
数据分享|R语言逐步回归模型对电影票房、放映场数、观影人数预测可视化1
数据分享|R语言逐步回归模型对电影票房、放映场数、观影人数预测可视化
|
6月前
|
算法 数据挖掘
R语言面板数据回归:含时间固定效应混合模型分析交通死亡率、酒驾法和啤酒税
R语言面板数据回归:含时间固定效应混合模型分析交通死亡率、酒驾法和啤酒税
|
6月前
|
数据采集 机器学习/深度学习 供应链
python基于评论情感分析和回归、arima销量预测的购物网站选品
python基于评论情感分析和回归、arima销量预测的购物网站选品
|
6月前
R语言多元逐步回归模型分析房价和葡萄酒价格:选择最合适的预测变量
R语言多元逐步回归模型分析房价和葡萄酒价格:选择最合适的预测变量
|
6月前
用R语言用Nelson Siegel和线性插值模型对债券价格和收益率建模
用R语言用Nelson Siegel和线性插值模型对债券价格和收益率建模
下一篇
无影云桌面