百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

仅用逻辑回归来对非线性决策边界建模

wptr33 2025-02-27 16:56 28 浏览

数据科学家,会经常被复杂的机器学习技术所吸引。使用某些深度神经网络(DNN)压缩1%的额外精度并在此过程中必须启动一个GPU实例,这使人非常满意。但是,这些技术通常使您的想法落到计算机上,使我们对模型的工作方式了解甚少。所以,本文想回到基础。

在本文中,我希望教给您一些有关特征工程的知识,以及如何使用它来对非线性决策边界进行建模。我们将探讨两种技术的优缺点:逻辑回归(具有特征工程)和NN分类器。将给出用于拟合这些模型以及可视化其决策边界的Python代码。您还可以在上找到完整的项目。最后,我希望让您理解为什么特征工程可能是其他非线性建模技术的更好替代方案。

什么是特征工程

每当您从原始数据创建特征或将现有特征添加到数据集时,就在进行特征工程。这通常是使用特定领域的领域知识完成的。例如,假设我们要预测一个人从手术中恢复所花费的时间。从以前的手术中,我们已经捕获了患者的康复时间,身高和体重。根据这些数据,我们还可以计算每个患者的BMI =身高/体重2。通过计算BMI并将其包括在数据集中,我们正在进行特征工程。



我们为什么进行特征工程

特征工程功能强大,因为它允许我们将非线性问题重新表述为线性问题。为了说明这一点,假设恢复时间与身高和体重具有以下关系:

Y =β?+β?(height)+β2(weight)+β?(height/weight2)+noise

从第三项来看,我们可以看到Y与身高和体重没有线性关系。这意味着我们可能不会期望线性模型(例如线性回归)在估计β系数方面做得很好。您可以尝试使用非线性模型(例如DNN),也可以通过进行一些特征工程来帮助我们的模型。如果我们决定将BMI作为功能包括在内,则关系变为:

Y =β?+β?(height)+β2(weight)+β?(BMI)+noise

现在可以将Y建模为3个变量的线性关系。结果,我们期望线性回归在估计系数方面做得更好。稍后,我们将看到相同的想法适用于分类问题。

为什么不让计算机来做

特征工程从本质上讲就是内核技巧,因为我们正在将特征映射到更高的平面。尽管使用内核技巧,通常很少涉及到思想。内核函数被视为超参数,可以使用蛮力找到最佳函数-尝试各种函数变化的负载。使用正确的内核函数,您可以为非线性关系建模。给定适当数量的隐藏层/节点,DNN还将自动构造特征的非线性函数。那么,如果这些方法可以对非线性关系进行建模,那么为什么还要打扰特征工程呢?

上面我们解释了特征工程如何使我们即使使用线性模型也可以捕获数据中的非线性关系。这意味着,根据问题,我们可以获得与非线性模型相似的性能。在本文后面的部分中,我们将详细介绍一个示例。除此之外,使用特征工程还有其他好处,这使这项技术值得一试。

首先,您将对模型的工作原理有更好的了解。这是因为您确切地知道模型用于进行预测的信息。此外,通过直接查看特征系数,可以轻松地解释逻辑回归等模型。第一个原因,即该模型更易于解释。如果您在行业中工作,这尤其重要。您的同事更有可能会接触到更简单的模型。第三个原因是您的模型不太适合训练数据。通过对不同超参数的强行加载,很容易最终在数据中建模噪声。相比之下,具有经过深思熟虑的特征,您的模型将是直观的,并且可能会模型化真实的潜在趋势。



数据集

让我们深入一个实际的例子。为了使内容尽可能清晰,将使用人工生成的数据集。为避免该示例过于沉闷,我们将围绕它创建一个叙述。因此,假设您的人事部门要求您创建一个模型,该模型可以预测是否会升职。该模型应考虑员工的年龄和绩效得分。

我们在下面的代码中为2000名假设的员工创建特征。员工的年龄可以在18至60岁之间。绩效得分可以在-10至10之间(最高为10分)。两种特征都经过混洗,因此它们之间没有关联。然后,我们使用年龄(a)和绩效(p)的以下函数来生成目标变量:

γ(a,p)= 100(a)+ 200(p)+ 500(a / p)-10000 + 500(noise)

当γ(a,p)≥0时,则晋升员工;当γ(a,p)<0时,则不晋升员工。我们可以看到术语a / p包含在上面的函数中。这意味着决策边界将不是年龄和绩效的线性函数。还包括随机噪声,因此数据无法完全分离。换句话说,模型不可能是100%准确的。

import numpy as np 
 import pandas as pd 
   n_points = 2000 
   age = np.round(np.linspace(18,60,n_points),2) #age of employee 
 np.random.shuffle(age)  
   performance = np.linspace(-10,10,n_points) #performance score of employee 
 np.random.shuffle(performance)  
   noise = np.random.randn(n_points)  
   g = (100*age) +200*(performance) + 500*age/performance -10000 + 500*noise 
 y = [1 if y>=0 else 0 for y in g]  
   data = pd.DataFrame(data={'age':age,'performance':performance,'y':y})

如果上面的步骤有点混乱,请不要担心。通过使用以下代码可视化数据集,我们可以使事情更清晰。在这里,我们创建了数据的散点图,结果如图1所示。只有两个功能,可以很容易地准确了解正在发生的事情。在y轴上,我们拥有员工的绩效得分,在x轴上,我们拥有员工的年龄。晋升员工的分数为红色,未晋升员工的分数为蓝色。最后,在2000名员工中,有459名(占23%)获得了晋升。对于不同的随机样本,此比率将略有变化。

import matplotlib.pyplot as plt 
 %matplotlib inline 
   plt.subplots(nrows=1, ncols=1,figsize=(15,10)) 
   plt.scatter('age','performance',c='#ff2121',data=data[data.y == 1]) 
 plt.scatter('age','performance',c='#2176ff',data=data[data.y == 0]) 
 plt.ylabel("Performance Score",size=20) 
 plt.xlabel('Age',size=20) 
 plt.yticks(size=12) 
 plt.xticks(size=12) 
 plt.legend(['Promoted','Not Promoted'],loc =2,prop={"size":20})

尽管生成了这些数据,但我们仍然可以对图进行实际说明。在图1中,我们可以看到3个不同的雇员组。第一个是绩效得分低于0的组。由于绩效不佳,这些员工中的大多数没有得到晋升,我们也可以期望其中的一些人被解雇。我们可以期望得分高于0的员工获得升职或接受其他职位。得分特别高的员工倾向于离职。这可能是因为它们的需求量很大,并且在其他地方收到了更好的报价。但是,随着雇主的年龄增长,他们需要更高的绩效分数才能离职。这可能是因为年长的员工更愿意担任目前的职位。

无论哪种叙述,很明显决策边界不是线性的。换句话说,不可能画出一条直线来很好地区分被提升和未被提升的群体。结果,我们不会期望线性模型做得很好。让我们通过仅使用年龄和绩效这两个特征来拟合逻辑回归模型来证明这一点。

逻辑回归

在下面的代码中,我们将2000名员工分为训练集(70%)和测试集(30%)。我们使用训练集来训练逻辑回归模型。然后,使用该模型,对测试集进行预测。测试仪的准确性为82%。这看起来似乎还不错,但是我们应该考虑不到23%的员工获得了晋升。因此,如果我们只是猜测没有一个员工会获得升职,那么我们应该期望其准确性约为77%。

from sklearn.model_selection import train_test_split 
 import sklearn.metrics as metric 
 import statsmodels.api as sm 
   x = data[['age','performance']] 
 x = sm.add_constant(x) 
 y = data['y'] 
 x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.3, random_state=101) 
   model = sm.Logit(y_train,x_train).fit() #fit logistic regression model 
   predictions = np.around(model.predict(x_test))  
 accuracy = metric.accuracy_score(y_test,predictions)

通过使用以下代码可视化模型的决策边界,我们可以更好地了解模型的特征。在这里,我们在样本空间内生成一百万个点。然后,我们使用逻辑回归模型对所有这些点进行预测。像图1中的散点图一样,我们可以绘制每个点。每个点的颜色由模型的预测确定-如果模型预测升级,则为粉红色,否则为浅蓝色。这使我们可以很好地近似决策边界,如图2所示。然后,我们可以在这些点上绘制实际数据集。

n_points = 1000000 #use many point to visualise decision boundry 
   age_db = np.linspace(18,60,n_points) 
 np.random.shuffle(age_db) 
   performance_db= np.linspace(-10,10,n_points) 
 np.random.shuffle(performance_db) 
   data_db = pd.DataFrame({'age':age_db,'performance':performance_db}) 
 data_db = sm.add_constant(data_db) 
   #make predictions on the decision boundry points 
 predictions = model.predict(data_db) 
 y_db = [round(p) for p in predictions]  
 data_db['y'] = y_db 
   fig, ax = plt.subplots( nrows=1, ncols=1,figsize=(15,10)) 
   #Plot decision boundry 
 plt.scatter('age','performance',c='#ffbdbd',s=1,data=data_db[data_db.y == 1]) 
 plt.scatter('age','performance',c='#b0c4ff',s=1,data=data_db[data_db.y == 0]) 
   #Plot employee data points  
 plt.scatter('age','performance',c='#ff2121',data=data[data.y == 1]) 
 plt.scatter('age','performance',c='#2176ff',data=data[data.y == 0]) 
 plt.ylabel("Performance Score",size=20) 
 plt.xlabel('Age',size=20) 
 plt.yticks(size=12) 
 plt.xticks(size=12)

查看决策边界,我们可以看到模型做得很糟糕。它预测有晋升的员工中大约有一半没有晋升。然后,对于大多数获得晋升的员工,它预测他们没有获得晋升。注意,决策边界是一条直线。这强调逻辑回归是线性分类器。换句话说,模型只能构造一个决策边界,该边界是您提供的要素的线性函数。在这一点上,我们可能很想尝试其他模型,但让我们看看是否可以使用特征工程来提高性能。



用于特征工程的逻辑回归

首先,如下面的代码所示,我们添加了其他特征(即年龄与性能的比率)。从那时起,我们将遵循与先前模型相同的过程。火车测试拆分与我们为" random_state"使用相同的值相同。最终,该模型实现了98%的准确度,这是一个重大改进。

该模型仍然只需要员工的年龄和绩效即可做出预测。这是因为附加功能是年龄和性能的函数。这使我们能够像以前一样可视化决策边界。那就是通过在样本空间中每个年龄表现点使用模型的预测。我们可以看到,在图3中,通过添加附加特征,逻辑回归模型能够对非线性决策边界进行建模。从技术上讲,这是年龄和性能的非线性函数,但仍是所有3个特征的线性函数。

使用逻辑回归的另一个好处是该模型是可以解释的。这意味着该模型可以用人类的术语来解释。换句话说,我们可以直接查看模型系数以了解其工作原理。我们可以在表1中看到模型特征的系数以及它们的p值。我们不会详细介绍,但是系数允许您根据获得的几率的变化来解释特征的变化。促销。如果某个特征的系数为正,则该特征值的增加会导致获得晋升的几率增加。

从表1可以看出,随着年龄的增长,晋升的可能性也会增加。另一方面,对于性能而言,这种关系并不明确。绩效的提高也会降低年龄/绩效比率。这意味着绩效提高的效果取决于员工的年龄。这非常直观,因为它与我们在散点图中看到的一致。在这种情况下,可能没有必要使用系数来以此方式解释模型。仅可视化决策边界就足够了,但是随着功能数量的增加,执行此操作变得更加困难。在这种情况下,模型系数是了解模型工作原理的绝佳工具。

同样,p值可以帮助我们理解模型。由于系数是统计估计值,因此它们周围存在一些不确定性。低p值使我们可以确定我们的系数不同于0。换句话说,我们可以确定系数为正或负。这很重要,因为如果我们不确定系数的符号,就很难用几率的变化来解释特征的变化。从表1可以看出,所有系数在统计上都是显着的。这并不奇怪,因为我们使用功能的功能生成了数据。

总的来说,当我们生成数据时,上面的分析非常简单。因为我们知道使用了什么函数来生成数据,所以很明显,附加特征将提高模型的准确性。实际上,这不是那么简单。如果您对数据没有很好的了解,则可能需要与人事部门的人员交谈。他们也许能够将过去所看到的任何趋势通知您。否则,通过使用各种图表和汇总统计数据探索该数据,您可以了解哪些特征可能很重要。但是,假设我们不想做所有这些艰苦的工作。

神经网络

为了进行比较,让我们使用非线性模型。在下面的代码中,我们使用Keras拟合神经网络。我们仅使用年龄和性能作为特征,因此NN的输入层的尺寸为2。有2个隐藏层,分别具有20和15个节点。两个隐藏层均具有relu激活功能,输出层具有S型激活功能。要训??练模型,我们使用10和100个纪元的批量。训练集大小为1400,这使我们有14000步。最后,该模型在测试集上达到了98%的精度。这与逻辑回归模型的准确性相同,但是我们不必进行任何特征工程。

查看图4中的NN决策边界,我们可以看到为什么将其视为非线性分类算法。即使我们只给出了模型的年龄和性能,它仍然能够构造非线性决策边界。因此,该模型在一定程度上为我们做了艰苦的工作。您可以说模型的隐藏层已自动完成要素工程。然后,考虑到该模型具有很高的准确性,并且我们需要较少的工作,为什么还要考虑逻辑回归呢?

NN的缺点是只能解释。这意味着,与逻辑回归不同,我们无法直接查看模型的参数以查看其工作原理。我们可以使用其他方法,但是最终,要理解NN的工作原理更加困难。向非技术人员解释这一点更加困难。这使得逻辑回归模型在行业环境中的价值更大。

工业界和学术界都存在许多问题,而且大多数问题都比本文中给出的示例更为复杂。所提出的方法显然不是所有这些问题的最佳解决方案。例如,如果您要进行图像识别,那么Logistic回归将无济于事。对于更简单的问题,通常只需要逻辑回归和对数据的充分理解。


相关推荐

oracle数据导入导出_oracle数据导入导出工具

关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...

继续学习Python中的while true/break语句

上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个else解...

python continue和break的区别_python中break语句和continue语句的区别

python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...

简单学Python——关键字6——break和continue

Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...

2-1,0基础学Python之 break退出循环、 continue继续循环 多重循

用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...

Python 中 break 和 continue 傻傻分不清

大家好啊,我是大田。今天分享一下break和continue在代码中的执行效果是什么,进一步区分出二者的区别。一、continue例1:当小明3岁时不打印年龄,其余年龄正常循环打印。可以看...

python中的流程控制语句:continue、break 和 return使用方法

Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...

L017:continue和break - 教程文案

continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...

作为前端开发者,你都经历过怎样的面试?

已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...

面试被问 const 是否不可变?这样回答才显功底

作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...

2023金九银十必看前端面试题!2w字精品!

导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。答案:CSS的盒模型是用于布局和定位元素的概念。它由内容区域...

前端面试总结_前端面试题整理

记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...

由浅入深,66条JavaScript面试知识点(七)

作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录由浅入深,66条JavaScript面试知识点(一)由浅入深,66...

2024前端面试真题之—VUE篇_前端面试题vue2020及答案

添加图片注释,不超过140字(可选)1.vue的生命周期有哪些及每个生命周期做了什么?beforeCreate是newVue()之后触发的第一个钩子,在当前阶段data、methods、com...

今年最常见的前端面试题,你会做几道?

在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...