搜索微信公众号:‘AI-ming3526’或者’计算机视觉这件小事’ 获取更多人工智能、机器学习干货
csdn:https://blog.csdn.net/baidu_31657889/
github:https://github.com/aimi-cn/AILearners
本文出现的所有代码,均可在github上下载,不妨来个Star把谢谢~:
Github代码地址
本篇文章继续对线性回归进行研究,对乐高玩具套件二手交易价格做出预测。
乐高玩具我们应该都知道,当然最熟悉的还是现在00后的小孩子们,90后的我都没玩过这样的拼装类玩具,许多大小不同的塑料插块组成拼接成不同的场景如房子机器人等等。。乐高公司每个套装包含的部件数目从10件到5000件不等。
一种乐高套件基本上在几年后就会停产,但乐高的收藏者之间仍会在停产后彼此交易。本次实例,就是使用回归方法对收藏者之间的交易价格进行预测。
书上说的是使用google的API获取我们需要的数据,但是这个api现在应该是处于关闭状态,而且google的api我们貌似也访问不了哈哈
但是我们有需要用到的html文件
原始数据下载地址:
数据下载
分析这些html文件 获取我们所需要的信息 创建lego.py文件 代码如下:
@File : getData.py
@Time : 2019/07/22 09:56:16
@Author : xiao ming
@Version : 1.0
@Contact : xiaoming3526@gmail.com
@Desc : 乐高玩具套件html文件数据获取
@github : https://github.com/aimi-cn/AILearners
from bs4 import BeautifulSoup
import numpy as np
import random
@description: 从页面读取数据,生成retX和retY列表
@param: retX - 数据X
retY - 数据Y
inFile - HTML文件
yr - 年份
numPce - 乐高部件数目
origPrc - 原价
@return:
def scrapePage(retX, retY, inFile, yr, numPce, origPrc):
with open(inFile, encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html)
i = 1
currentRow = soup.find_all('table', r = "%d" % i)
while(len(currentRow) != 0):
currentRow = soup.find_all('table', r = "%d" % i)
title = currentRow[0].find_all('a')[1].text
lwrTitle = title.lower()
if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):
newFlag = 1.0
else:
newFlag = 0.0
soldUnicde = currentRow[0].find_all('td')[3].find_all('span')
if len(soldUnicde) == 0:
print("商品 #%d 没有出售" % i)
else:
soldPrice = currentRow[0].find_all('td')[4]
priceStr = soldPrice.text
priceStr = priceStr.replace('$','')
priceStr = priceStr.replace(',','')
if len(soldPrice) > 1:
priceStr = priceStr.replace('Free shipping', '')
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.find_all('table', r = "%d" % i)
def setDataCollect(retX, retY):
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego8288.html', 2006, 800, 49.99)
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego10030.html', 2002, 3096, 269.99)
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego10179.html', 2007, 5195, 499.99)
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego10181.html', 2007, 3428, 199.99)
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego10189.html', 2008, 5922, 299.99)
scrapePage(retX, retY, 'C:/Users/Administrator/Desktop/blog/github/AILearners/data/ml/jqxxsz/8.Regression/lego/lego10196.html', 2009, 3263, 249.99)
if __name__ == '__main__':
lgX = []
lgY = []
setDataCollect(lgX, lgY)
结果如下:
我们对没有的商品做了处理。这些特征分别为:出品年份、部件数目、是否为全新(1为全新)、原价、售价(二手交易价格)。
我们已经处理好了数据集,接下来就是训练模型。首先我们需要添加全为0的特征X0列。因为线性回归的第一列特征要求都是1.0。然后使用最简单的普通线性回归i,在lego.py文件下添加代码如下:
@description: 数据标准化
@param: xMat - x数据集
yMat - y数据集
@return: inxMat - 标准化后的x数据集
inyMat - 标准化后的y数据集
def regularize(xMat, yMat):
inxMat = xMat.copy()
inyMat = yMat.copy()
yMean = np.mean(yMat, 0)
inyMat = yMat - yMean
inMeans = np.mean(inxMat, 0)
inVar = np.var(inxMat, 0)
print(inMeans)
inxMat = (inxMat - inMeans) / inVar
return inxMat, inyMat
@description: 计算平方误差
@param: yArr - 预测值
yHatArr - 真实值
@return: 平方误差
def rssError(yArr,yHatArr):
return ((yArr-yHatArr)**2).sum()
@description: 计算回归系数w
@param: xArr - x数据集
yArr - y数据集
@return: ws - 回归系数
def standRegres(xArr,yArr):
xMat = np.mat(xArr); yMat = np.mat(yArr).T
xTx = xMat.T * xMat
if np.linalg.det(xTx) == 0.0:
print("矩阵为奇异矩阵,不能转置")
return
ws = xTx.I * (xMat.T*yMat)
return ws
@description: 使用简单的线性回归
@param: None
@return: None
def useStandRegres():
lgX = []
lgY = []
setDataCollect(lgX, lgY)
data_num, features_num = np.shape(lgX)
lgX1 = np.mat(np.ones((data_num, features_num + 1)))
lgX1[:, 1:5] = np.mat(lgX)
ws = standRegres(lgX1, lgY)
print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % (ws[0],ws[1],ws[2],ws[3],ws[4]))
if __name__ == '__main__':
useStandRegres()
运行结果如下:
可以看到,模型预测采用的公式如上图红色框所示。虽然这个模型对于数据拟合得很好,但是看上不没有什么道理。套件里的部件数量越多,售价反而降低了,这是不合理的。
然后我们使用岭回归,通过交叉验证,找到使误差最小的λ对应的回归系数。在lego.py文件下添加代码如下:
@description: 岭回归
@param: xMat - x数据集
yMat - y数据集
lam - 缩减系数
@return: ws - 回归系数
def ridgeRegres(xMat, yMat, lam = 0.2):
xTx = xMat.T * xMat
denom = xTx + np.eye(np.shape(xMat)[1]) * lam
if np.linalg.det(denom) == 0.0:
print("矩阵为奇异矩阵,不能转置")
return
ws = denom.I * (xMat.T * yMat)
return ws
@description: 交叉验证岭回归
@param: xArr - x数据集
yArr - y数据集
numVal - 交叉验证次数
@return: wMat - 回归系数矩阵
def crossValidation(xArr, yArr, numVal = 10):
m = len(yArr)
indexList = list(range(m))
errorMat = np.zeros((numVal,30))
for i in range(numVal):
trainX = []; trainY = []
testX = []; testY = []
random.shuffle(indexList)
for j in range(m):
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)
for k in range(30):
matTestX = np.mat(testX); matTrainX = np.mat(trainX)
meanTrain = np.mean(matTrainX,0)
varTrain = np.var(matTrainX,0)
matTestX = (matTestX - meanTrain) / varTrain
yEst = matTestX * np.mat(wMat[k,:]).T + np.mean(trainY)
errorMat[i, k] = rssError(yEst.T.A, np.array(testY))
meanErrors = np.mean(errorMat,0)
minMean = float(min(meanErrors))
bestWeights = wMat[np.nonzero(meanErrors == minMean)]
xMat = np.mat(xArr); yMat = np.mat(yArr).T
meanX = np.mean(xMat,0); varX = np.var(xMat,0)
unReg = bestWeights / varX
print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % ((-1 * np.sum(np.multiply(meanX,unReg)) + np.mean(yMat)), unReg[0,0], unReg[0,1], unReg[0,2], unReg[0,3]))
@description: 岭回归测试
@param: xMat - x数据集
yMat - y数据集
@return: wMat - 回归系数矩阵
def ridgeTest(xArr, yArr):
xMat = np.mat(xArr); yMat = np.mat(yArr).T
yMean = np.mean(yMat, axis = 0)
yMat = yMat - yMean
xMeans = np.mean(xMat, axis = 0)
xVar = np.var(xMat, axis = 0)
xMat = (xMat - xMeans) / xVar
numTestPts = 30
wMat = np.zeros((numTestPts, np.shape(xMat)[1]))
for i in range(numTestPts):
ws = ridgeRegres(xMat, yMat, np.exp(i - 10))
wMat[i, :] = ws.T
return wMat
if __name__ == '__main__':
lgX = []
lgY = []
setDataCollect(lgX, lgY)
crossValidation(lgX, lgY)
运行结果如下:
这里随机选取样本,因为其随机性,所以每次运行的结果可能略有不同。不过整体如上图所示,可以看出,它与常规的最小二乘法,即普通的线性回归没有太大差异。我们本期望找到一个更易于理解的模型,显然没有达到预期效果。
现在,我们看一下在缩减过程中回归系数是如何变化的。在lego.py添加代码如下:
if __name__ == '__main__':
lgX = []
lgY = []
setDataCollect(lgX, lgY)
print(ridgeTest(lgX, lgY))
运行结果如下图所示:
看运行结果的第一行,可以看到最大的是第4项,第二大的是第1项。
因此,如果只选择一个特征来做预测的话,我们应该选择第4个特征,也就是原始加个。如果可以选择2个特征的话,应该选择第4个和第1个特征。
这种分析方法使得我们可以挖掘大量数据的内在规律。在仅有4个特征时,该方法的效果也许并不明显;但如果有100个以上的特征,该方法就会变得十分有效:它可以指出哪个特征是关键的,而哪些特征是不重要的。
当然我们也可以使用简单的Sklearn来实现岭回归。
AIMI-CN AI学习交流群【1015286623】 获取更多AI资料
扫码加群:
分享技术,乐享生活:我们的公众号计算机视觉这件小事每周推送“AI”系列资讯类文章,欢迎您的关注!
《机器学习实战》8.4 线性回归之乐高玩具套件二手交易价格预测搜索微信公众号:‘AI-ming3526’或者’计算机视觉这件小事’ 获取更多人工智能、机器学习干货csdn:https://blog.csdn.net/baidu_31657889/github:https://github.com/aimi-cn/AILearners本文出现的所有代码,均可在github上下载,不妨来个...
机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深度学习500问机器学习/深
目录预测数值型数据:回归1 利用线性回归找到最佳拟合直线2 局部加权线性回归3 示例:预测鲍鱼的年龄4 缩减系数来“理解”数据4.1 岭回归4.2 lasso4.3 前向逐步回归5 权衡偏差与方差6 示例:预测乐高玩具套装的价格6.1 收集数据:使用google购物的API6.2 训练算法:建立模型7 本章结束本节涉及的相关代码和数据本章内容:线性回归的相关特点主要是回归的一般方法:采用最小平方误差
调用上述函数:
输出得到的结果为: 将得到的权重系数,画图表示为:
得到的输出图像为:可以看到该
乐高是一个很受欢迎的玩具积木品牌。它们通常是成套出售的,用来制作特定的物品。每一套都包含许多不同形状、大小和颜色的零件。这个数据库包含了不同的乐高组合中包含哪些部件的信息。它最初是为了帮助那些已经拥有一些乐高积木套的人弄清楚他们还能用自己的作品制造出什么其他玩具。
colors.csv
downloads_schema.png
inventories.csv
inventory_parts.csv
inventory_sets.csv
part_categories.csv
parts.csv
sets.csv
themes.csv