Author:Robin Chen
Motto:Talk with the shortest sentence.
一、 逻辑回归用来干什么?
逻辑回归并不是回归的,是用来分类的,而分类是有监督学习的一种。
比如:左边的是漫威阵营,右边的是DC阵营。就是一个二分类,但是我们是知道每个英雄是属于哪个阵营,假如不知道的话,那就叫无监督学习了。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/18cd49fc1490a913a64af7e30cfbf9b2.jpeg)
二、逻辑回归的适用范围
(一)逻辑回归一般适用于 【二】分类,较少用于多分类。
(二)数据要求:自变量可以是:离散型和连续型变量,因变量一般是二分类的离散型变量。
比如:上一幅图的英雄,不是Marvel阵营就是DC阵营。
三、逻辑回归的思想
首先介绍一个函数,Sigmoid函数。之所以取这个函数,是因为它的值域为[0,1]。
![Sigmoid函数](https://i-blog.csdnimg.cn/blog_migrate/c16580a8919b2ffb6d05c5a75a2b513b.png)
图1 Sigmoid函数
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4d8823e853e5b2034cbd130f82714929.jpeg)
图2 Sigmoid函数的图像
LR就是引用了这个函数,把类似于 y = α x 1 + β x 2 + ε y = \alpha x_{1}+\beta x_{2}+\varepsilon y=αx1+βx2+ε 的多元回归的函数形式代入到Sigmoid函数中,转换成: Y ( x ) = 1 1 + e − ( α x 1 + β x 2 + ε ) Y(x) = \frac{1}{1+e^{-( \alpha x_{1}+\beta x_{2}+\varepsilon)}} Y(x)=1+e−(αx1+βx2+ε)1 这个样子了。其中的X为用于分类的数据标签就将Y值压缩在0-1之间,可以坚持如下规则来进行分类:
假如Y>0.5的话,那么我们可以把它分为【Marvel】阵营,
假如Y<0.5的话,那么我们可以把它分为【DC】阵营。
至于为什么是0.5,这个是结合实际情况,以及用途来决定了。大多数情况是以0.5为界定的。那么就可以分类了,就这么简单.
四、损失函数之交叉熵
【熵】的概念。它是热力学中表征物质状态的参量之一,利用【熵】是为了测量指标的混乱程度。表达形式为:
从上面的式子可以看出,【熵】其实就是某个信息量的期望值。 p i p_{i} pi为众多事件中,第 i i i个事件发生的概率。为了更好的理解【交叉熵】,首先介绍一下【相对熵】的概念。相对熵(relative entropy)又称为KL散度(Kullback-Leibler divergence),用来测量是两个随机分布间的距离。记为 D k l D{_{kl}} Dkl(p||q) 。它度量当真实分布为p时,假设分布q的无效性。【相对熵】的公式为
D k l ( p ∣ ∣ q ) = E p [ l o g p ( x ) q ( x ) ] = ∑ p ( x ) l o g p ( x ) q ( x ) D{_{kl}}(p||q) = E_{p}[log\frac{p(x)}{q(x)}]= \sum p(x)log\frac{p(x)}{q(x)} Dkl(p∣∣q)=Ep[logq(x)p(x)]=∑p(x)logq(x)p(x), x ϵ X x\epsilon X xϵX
D k l ( p ∣ ∣ q ) = ∑ [ p ( x ) l o g    p ( x ) − p ( x ) l o g   q ( x ) ] D{_{kl}}(p||q)= \sum[p(x)log\,\,p(x)-p(x)log\,q(x)] Dkl(p∣∣q)=∑[p(x)logp(x)−p(x)logq(x)]
D k l ( p ∣ ∣ q ) = H ( u ) − ∑ [ p ( x ) l o g   q ( x ) ] D{_{kl}}(p||q)= H(u)-\sum[p(x)log\,q(x)] Dkl(p∣∣q)=H(u)−∑[p(x)logq(x)]
这时的 − ∑ [ p ( x )   ⋅ l o g   q ( x ) ] -\sum[p(x)\,\cdot log\,q(x)] −∑[p(x)⋅logq(x)]就是交叉熵,定义为:
C E H ( p , q ) = E p [ − l o g   q ] CEH(p,q) = E_{p}[-log\,q] CEH(p,q)=Ep[−logq] = − ∑ [ p ( x )   ⋅ l o g   q ( x ) ] -\sum[p(x)\,\cdot log\,q(x)] −∑[p(x)⋅logq(x)]
因而,【交叉熵】和【相对熵】的关系为:
交叉熵= H ( P ) H(P) H(P) + 相对熵
p:真实样本分布,服从参数为p的0-1分布,即X∼B(1,p)
q:待估计的模型,服从参数为q的0-1分布,即X∼B(1,q)
C E H ( p , q ) = − ∑ [ p ( x )   ⋅ l o g   q ( x ) ] CEH(p,q) = -\sum[p(x)\,\cdot log\,q(x)] CEH(p,q)=−∑[p(x)⋅logq(x)] msp; msp;
C E H ( p , q ) = − [ P p ( x = 1 )   l o g P q ( x = 1 ) + P p ( x = 0 )   l o g P q ( x = 0 ) ] CEH(p,q) = -[P_{p}(x=1)\,logP_{q}(x=1)+P_{p}(x=0)\,logP_{q}(x=0)] CEH(p,q)=−[Pp(x=1)logPq(x=1)+Pp(x=0)logPq(x=0)]
C E H ( p , q ) = − [ y   l o g h Θ ( x ) + ( 1 − y )   l o g ( 1 − h Θ ( x ) ) ] CEH(p,q) = -[y\,logh_{\Theta }(x)+(1-y)\,log(1-h_{\Theta }(x))] CEH(p,q)=−[yloghΘ(x)+(1−y)log(1−hΘ(x))]
最后,LR的代价函数是使用的【交叉熵】函数来做的,至于为什么使用【交叉熵】函数,我个人感觉是LR是二分类的算法,考虑到【交叉熵】与【相对熵】的关系(上文提及:交叉熵用来测量是两个随机分布间的距离),所以选择的这个函数吧。另外,通过构造似然函数,然后函数对数求导,结果和交叉熵的计算结果是一样的。
此时,代价函数为:
最后求导数为(推导过程在这里,这个最好自己推导下):
其中 h Θ ( x i ) − y i h_{\Theta}\left(x^{i}\right)-y^{i} hΘ(xi)−yi就是预测值与真实值之间的误差。在后面梯度下降的时候,就是用数据矩阵与误差项的乘积来梯度下降的。
五、代码
这里使用的泰坦尼克号幸存与否的数据,来简单举个例子。
下面是提取建模前的变量,把与【幸存与否】的代码去掉,留下相关的变量。
数据介绍:
PassengerId:乘客Id Survived:0代表死掉了,1代表活下来了
Pclass:1,2,3代表经济社会地位1最高,3最低
Name:乘客姓名, Sex:代表性别 , Age:年龄
SibSp:由两部分组成,
Sibling(兄弟姐妹,堂妹都合适),
Spouse代表(丈夫或妻子)
Parch:父母和孩子组成,若只跟保姆写0
Ticket:票的数字 Fare:乘客票价 Cabin:船舱数字
Embarked:登船仓:C=Cherbourg,Q=Queenstown,S=Southampton
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df = pd.read_csv(r"C:\Users\73918\Desktop\T\project\Titanic-dataset\train.csv",encoding = 'GBK')
tdf = pd.read_csv(r"C:\Users\73918\Desktop\T\project\Titanic-dataset\test.csv",encoding = 'GBK')
combine = [df,tdf]
df["Sex"]= df["Sex"].replace(["male","female"],[1,0])
df["Embarked"]= df["Embarked"].replace(["S","C","Q"],[2,1,0])
a =df[['Pclass','Survived']].groupby(['Pclass'],as_index=False).mean().sort_values(by='Survived',ascending=False)
b =df[["Embarked",'Survived']].groupby(["Embarked"],as_index=False).mean().sort_values(by='Survived',ascending=False)
c =df[["Sex",'Survived']].groupby(["Sex"],as_index=False).mean().sort_values(by='Survived',ascending=False)
d =df[['SibSp','Survived']].groupby(['SibSp'],as_index=False).mean().sort_values(by='Survived',ascending=False)
e =df[['Parch','Survived']].groupby(['Parch'],as_index=False).mean().sort_values(by='Survived',ascending=False)
print(a)
print(b)
print(c)
print(d)
print(e)
g = sns.FacetGrid(df,col='Survived')
g.map(plt.hist,'Age',bins=20)
plt.show()
g = sns.FacetGrid(df,col='Survived')
g.map(plt.hist,'Pclass',bins=3)
plt.show()
grid = sns.FacetGrid(df,col='Survived',row='Pclass',size=2.2,aspect=3.8)
grid.map(plt.hist,'Age',alpha=.5,bins=20)
grid.add_legend()
plt.show()
for dataset in df:
dataset.loc[dataset['Fare'] <= 7.91, 'Fare'] = 0
dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2
dataset.loc[dataset['Fare'] > 31, 'Fare'] = 3
dataset['Fare'] = dataset['Fare'].astype(int)
f =df[['Fare','Survived']].groupby(['Fare'],as_index=False).mean().sort_values(by='Survived',ascending=False)
print(f)
for i in range(len(df)):
row = df.iloc[i]
if row['Fare'] <= 7.91:
df.iloc[[i],[8]] = 0
elif 7.91 < row['Fare'] < 14.454:
df.iloc[[i],[8]] = 1
elif 14.454 < row['Fare'] < 31:
df.iloc[[i], [8]] = 2
else:
df.iloc[[i], [8]] = 3
f =df[['Fare','Survived']].groupby(['Fare'],as_index=False).mean().sort_values(by='Survived',ascending=False)
print(f)
其中,sex=0为女性,sex=1为男性,
最后确定要提取的变量有:年龄、性别、经济地位、票价。这里提取的比较粗糙,重在举例,海涵海涵(数据中的缺失值,我直接删了)。关于数据预处理的东西,可以参考数据分析之泰但尼克号这篇博客,个人感觉处理的很到位。
下面简单试一下LR的模型。可以得出来模型得分是79.27。
import pandas as pd
from sklearn.linear_model import LogisticRegression
df = pd.read_csv(r"C:\Users\73918\Desktop\data.csv",encoding="GBK")
X_train = df.drop(['Survived','PassengerId'],axis=1)
Y_train = df['Survived']
tdf = pd.read_csv(r"C:\Users\73918\Desktop\test.csv",encoding="GBK")
X_test = tdf.drop(['PassengerId','Embarked'],axis=1)
Logreg = LogisticRegression()
Logreg.fit(X_train,Y_train)
Y_pred = Logreg.predict(X_test)
acc_log = round(Logreg.score(X_train,Y_train) * 100,2)
print(acc_log)
#输出79.27