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

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

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

数据科学家,会经常被复杂的机器学习技术所吸引。使用某些深度神经网络(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回归将无济于事。对于更简单的问题,通常只需要逻辑回归和对数据的充分理解。


相关推荐

每天一个编程技巧!掌握这7个神技,代码效率飙升200%

“同事6点下班,你却为改BUG加班到凌晨?不是你不努力,而是没掌握‘偷懒’的艺术!本文揭秘谷歌工程师私藏的7个编程神技,每天1分钟,让你的代码从‘能用’变‘逆天’。文末附《Python高效代码模板》,...

Git重置到某个历史节点(Sourcetree工具)

前言Sourcetree回滚提交和重置当前分支到此次提交的区别?回滚提交是指将改动的代码提交到本地仓库,但未推送到远端仓库的时候。...

git工作区、暂存区、本地仓库、远程仓库的区别和联系

很多程序员天天写代码,提交代码,拉取代码,对git操作非常熟练,但是对git的原理并不甚了解,借助豆包AI,写个文章总结一下。Git的四个核心区域(工作区、暂存区、本地仓库、远程仓库)是版本控制的核...

解锁人生新剧本的密钥:学会让往事退场

开篇:敦煌莫高窟的千年启示在莫高窟321窟的《降魔变》壁画前,讲解员指着斑驳色彩说:"画师刻意保留了历代修补痕迹,因为真正的传承不是定格,而是流动。"就像我们的人生剧本,精彩章节永远...

Reset local repository branch to be just like remote repository HEAD

技术背景在使用Git进行版本控制时,有时会遇到本地分支与远程分支不一致的情况。可能是因为误操作、多人协作时远程分支被更新等原因。这时就需要将本地分支重置为与远程分支的...

Git恢复至之前版本(git恢复到pull之前的版本)

让程序回到提交前的样子:两种解决方法:回退(reset)、反做(revert)方法一:gitreset...

如何将文件重置或回退到特定版本(怎么让文件回到初始状态)

技术背景在使用Git进行版本控制时,经常会遇到需要将文件回退到特定版本的情况。可能是因为当前版本出现了错误,或者想要恢复到之前某个稳定的版本。Git提供了多种方式来实现这一需求。...

git如何正确回滚代码(git命令回滚代码)

方法一,删除远程分支再提交①首先两步保证当前工作区是干净的,并且和远程分支代码一致$gitcocurrentBranch$gitpullorigincurrentBranch$gi...

[git]撤销的相关命令:reset、revert、checkout

基本概念如果不清晰上面的四个概念,请查看廖老师的git教程这里我多说几句:最开始我使用git的时候,我并不明白我为什么写完代码要用git的一些列指令把我的修改存起来。后来用多了,也就明白了为什么。gi...

利用shell脚本将Mysql错误日志保存到数据库中

说明:利用shell脚本将MYSQL的错误日志提取并保存到数据库中步骤:1)创建数据库,创建表CreatedatabaseMysqlCenter;UseMysqlCenter;CREATET...

MySQL 9.3 引入增强的JavaScript支持

MySQL,这一广泛采用的开源关系型数据库管理系统(RDBMS),发布了其9.x系列的第三个更新版本——9.3版,带来了多项新功能。...

python 连接 mysql 数据库(python连接MySQL数据库案例)

用PyMySQL包来连接Python和MySQL。在使用前需要先通过pip来安装PyMySQL包:在windows系统中打开cmd,输入pipinstallPyMySQL ...

mysql导入导出命令(mysql 导入命令)

mysql导入导出命令mysqldump命令的输入是在bin目录下.1.导出整个数据库  mysqldump-u用户名-p数据库名>导出的文件名  mysqldump-uw...

MySQL-SQL介绍(mysql sqlyog)

介绍结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同...

MySQL 误删除数据恢复全攻略:基于 Binlog 的实战指南

在MySQL的世界里,二进制日志(Binlog)就是我们的"时光机"。它默默记录着数据库的每一个重要变更,就像一位忠实的史官,为我们在数据灾难中提供最后的救命稻草。本文将带您深入掌握如...