Python 数据分析学习(3)逻辑回归预测实例

Python 数据分析学习(3)逻辑回归预测实例


前言

带有什么特征的人在Titanic号事件中有更高的生存率?我们构建一个模型来预测不同特征的人的生存情况。本文是学习知乎的文章https://zhuanlan.zhihu.com/p/53176091/的一些个人感受。

1.提出问题

带有什么特征的人在Titanic号事件中有更高的生存率?我们构建一个模型来预测不同特征的人的生存情况。

2.理解数据

2.1 基本概念

  先整理下概念。
1.训练集:可以简单理解为是上课学的知识,用来训练模型得到参数。
2.验证集可以理解成课后习题,可以纠正和强化知识点,用来评估不同超参数训练出的模型效果,从而优化模型。
3.测试集可以理解为期末考试,用来评估最终模型的效果。
对同一个 任务,测试集要和训练集严格分开,测试集只能进行测试,不能参与训练。
4.超参数:在训练前需要设定的很多其它参数,就是超参数,必须预先选定哪个函数空间作为模型框架,需要选择哪种损失函数来衡量输出与标签之间的差异,需要哪种优化算法等等这些问题涉及到的参数,炼丹师和根据不同的机器学习任务来选择相对适配的超参数。但是有时候参数太多,很难通过经验来选择最优的模型,这时候就可以借助验证集,去找最优的模型。这时候就将训练集再划分为训练集和验证集。
在训练集训练出模型后用验证集评估模型,找到一组最优的超参数,然后将超参数固定再拿到整个训练集上重新训练模型,最终由测试评估性能。常规划分是训练集、测试集验证集分别占比60%,20%,20%。数据集数量比较庞大的话 100:1:1也可。

2.2 下载数据。

https://www.kaggle.com/c/titanic
其中
gender_submission.csv 文件记录真实的存活情况,1表示存活,0表示不幸遇难;
test.csv 为测试数据集;
train.csv 为训练数据集。

其中

gender_submission.csv 文件记录真实的存活情况,1表示存活,0表示不幸遇难;
test.csv 为测试数据集;
train.csv 为训练数据集。

  各字段含义如下:

Age 年龄
Cabin 船舱号
Embarked 登船港口
Fare 票价
Name 乘客姓名
Parch 不同代直系亲属人数
SibSp 同代直系亲属人数
PassengerId 乘客ID
Pclass 客舱等级
Sex 性别
Ticket 船票编号
Survived 存活情况

2.3 导入数据

#导入包
import numpy as np
import pandas as pd
#导入数据
train = pd.read_csv("./train.csv")
test = pd.read_csv("./test.csv")
#查看文件大小
print('训练数据集大小:',train.shape)
print('测试数据集大小:',test.shape)
训练数据集大小: (891, 12)
测试数据集大小: (418, 11)

  合并两个表的的代码的一般为

data = pd.concat([train,test],axis=0)

axis的意思是“轴”,决定了两个数据集是纵向的合并,还是横向的合并。
axis=0是纵向的合并,把很多行合并在一起,由于默认是纵向的合并,axis=0写不写都可以。
axis=1是横向的合并,把很多列合并在一起。

2.4 查看字段

train.head()
#查看描述统计和信息
train.describe()
#根据描述统计没有观察到异常值
train.info()
训练数据集大小: (891, 12)
测试数据集大小: (418, 11)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

通过info可以看出总共有891条数据,其中Age,Cabin(船舱号),Embarked(登船港口),Fare(票价),Survived(存活情况)均有不同程度的数据缺失,包含数值型数据(Age,Fare和Survived)和字符型数值(Cabin和Embarked),这就需要我们根据不同的数据类型进行相应的数据预处理。

3.数据清洗(Data Preparaion)

这一步我们主要对缺失数据进行补充,并对数据进行特征工程。

3.1数据预处理

对于数值型数据(Age,Fare)缺失值,我们采用平均值来填充; 对于分类数据(Cabin,Embarked),我们采用众数填充(众数填充是一种处理缺失数据的方法,它使用变量中出现次数最多的值来替换缺失值。‌这种方法适用于类别变量,尤其是当数据集的分布偏斜或者具有很多类别时,使用众数填充可以是一个有效的策略。);

from pandas import DataFrame
train['Age']  = train['Age'].fillna(train['Age'].mean())
#年龄因为不可从其他途径得知,采用平均年龄填充,此步骤对最终预测结果有影响。
full.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)

fillna() 方法用于填充 DataFrame 中的 NaN 值。这个方法提供了多种填充方式,包括使用常数值填充、前向填充、后向填充等。使用 fillna() 可以很方便地处理数据中的缺失值,提高数据的质量。
它的格式如下full[‘Age’] (要被补充的列为Age) = full[‘Age’].fillna(full[‘Age’].mean())
fillna()的括号里填写要被替换的值比如 fillna(0)那就是Age的值都被替换成0
使用均值填充缺失值:import pandas as pd
data = pd.read_csv(‘data.csv’)
data.fillna(data.mean(), inplace=True)

使用中位数填充缺失值:

import pandas as pd
data = pd.read_csv('data.csv')
data.fillna(data.median(), inplace=True)

使用众数填充缺失值

import pandas as pd
data = pd.read_csv('data.csv')
data.fillna(data.mode(), inplace=True)

使用前向填充或后向填充:

import pandas as pd
data = pd.read_csv('data.csv')
data.fillna(method='ffill', inplace=True) # 使用前向填充
data.fillna(method='bfill', inplace=True) # 使用后向填充

在python中 inplace=True 这个语法。运行后,后面的运行就在前一次数据的基础上了,所以一般不用。
但是有些有时候确实某些数据确定没用的时候,可以用这个永久删掉,比如其实这个训练集姓名是没有用的,可以永久的删掉。

df_train.drop(columns=["Name”],inplace=True)
df_train.headO
train['Fare'] = train['Fare'].fillna(train['Fare'].mean())#船票价格用平均值填充
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          891 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB


其实港口和船舱号不是很重要,可以直接删掉,下面只是展示下填充

train['Embarked'].value_counts()#查看登船港口的分布
S    914
C    270
Q    123
Name: Embarked, dtype: int64
train['Embarked'] = train['Embarked'].fillna('S')#S港登船的人最多,对空值使用S港填充
train['Cabin'].head()#查看船舱号,head函数是返回数组的前几行,如果不加参数默认是5行
0     NaN
1     C85
2     NaN
3    C123
4     NaN
Name: Cabin, dtype: object
train['Cabin']=train['Cabin'].fillna('U')#船舱号Cabin的缺失值比较多,我们对于空值填充U(Unknow)
train.head(10)

.head函数在数据缺失值处理的时候查看缺失值比较有用,可以轻松查看列表的样子

3.2 特征提取

  特征的选择和提取的好坏很大程度上决定了模型的上限,算法做到的只能是尽量逼近这个上限。如何提取尽可能多的特征并选择优质的特征是很重要的一个过程。

3.2.1整理数据

新建了一个叫做 Familynum 的变量,他表示乘客同城的家庭成员数就等于同城的伴侣或同胞数,加上同城的父母或孩子数,这样做是因为本质上像伴侣、同胞、父母、孩子都属于家庭成员。我这里是把它简化成了同一个因素,那后续也进行了一些数据的探索.
train.info()
train[‘FamilyNum’]=train[‘SibSp’]+train[‘Parch’]
train.head(20)

3.2.2探索数据

在着手逻辑回归分析之前,我们可以先借助数据可视化,探索数值变量的分布,以及与乘客是否幸存存在相关性的变量,为后续的进一步分析提供方向。这里可以用一些可视化操作,安装可视化的库,Seaborn 是一个用于数据可视化的 Python 库,它建立在 Matplotlib 之上,并提供了许多方便的函数来创建高质量的统计图形。matplotlib.pyplot 是 Matplotlib 库的一个模块,它提供了一个类似于 MATLAB 的绘图接口,使得使用 Matplotlib 进行绘图变得更加直观和易于使用。安装库使用

pip install seaborn
#设置图表色盘为”pastet
sns.set_palette("pastel")
#设置图表尺寸
plt.rcParams["figure.figsize"] =[7.00,3.50]
plt.rcParams["figure.autolayout"] =True
幸存比例
# 计算'Survived'列中每个值的计数
survived_count = train['Survived'].value_counts()

# 提取'Survived'列中每个值的标签
survived_label = survived_count.index

# 使用Matplotlib的pie函数创建饼图
# 参数survived_count表示饼图的各个部分的大小
# 参数labels表示饼图中的标签,这里就是survived_label
# 参数autopct表示自动显示每个部分的百分比,格式为'%.1f%%',即保留一位小数
plt.pie(survived_count, labels=survived_label, autopct='%.1f%%')

# 添加标题
plt.title('Survival Rate Distribution')

# 显示饼图
plt.show()

在这里插入图片描述
从以上饼图来看,泰坦尼克号遇难乘客多于幸存乘客,比例约为3:2。

乘客年龄
# 创建一个包含两个子图的图形
figure, axes = plt.subplots(1, 2)

# 创建第一个子图,绘制'Age'列的直方图
# 参数train表示数据集
# 参数x='Age'表示绘制'Age'列的直方图
# 参数ax=axes[0]表示将直方图绘制在第一个子图上
sns.histplot(train, x='Age', ax=axes[0])

# 创建第二个子图,绘制'Age'列的箱线图
# 参数train表示数据集
# 参数y='Age'表示绘制'Age'列的箱线图
# 参数ax=axes[1]表示将箱线图绘制在第二个子图上
sns.boxplot(train, y='Age', ax=axes[1])

# 显示图形
plt.show()

在这里插入图片描述

大多数乘客年龄位于20岁到40岁之间,但有不少老年乘客以及婴儿。

乘客年龄与是否幸存
# 使用Seaborn的histplot函数创建直方图
# 参数cleaned_titanic_train表示数据集
# 参数x='Age'表示直方图的x轴是'Age'列
# 参数hue='Survived'表示根据'Survived'列的值进行分组
# 参数alpha=0.4表示透明度,即直方图的填充颜色透明度为0.4
sns.histplot(cleaned_titanic_train, x='Age', hue='Survived', alpha=0.4)

# 显示图形
plt.show()

在这里插入图片描述
从乘客年龄直方图来看,只有婴儿群体幸存比例较高,绝大部分其余年龄段都是遇难人数多于幸存人数。

家庭成员数与是否幸存的关系
#家庭成员数与是否幸存的关系
sns.countplot(data=train,x='FamilyNum',hue='Survived')

在这里插入图片描述
从是否幸存与乘客家庭成员之间的柱状图来看,独身的乘客中遇难的多于幸存的。从有携带家庭成员的乘客来看,家庭成员在1~3位之间的幸存人数超过遇难人数,但同乘家庭成员超过3位后,遇难的更多。

3.2.2分析数据

移除大概率不影响乘客幸存概率的变量

数据里面包含了一些和生还概率可能无关的变量,比如说乘客的姓名,像这个肯定是没啥关系的。因为我总不能还去分析这个英文名的风水吧?然后像船票的号、船舱的号以及登船的这个港口,还有他的ID,就是乘客的 ID 也是大概率不会有什么影响的,所以说我们可以把他们都给移除掉


train:这是一个Pandas DataFrame对象,它包含了原始的titanic_train数据集。
.drop():这是一个Pandas方法,用于从DataFrame中删除列。
['PassengerId', 'Name', 'Ticket', 'Cabin', 'Embarked']:这是一个列表,包含了train DataFrame中要删除的列的名称。
axis=1:这是一个参数,指定沿着DataFrame的哪一轴(轴0是行,轴1是列)来删除列。在这个例子中,axis=1意味着我们要删除列。
train =train.drop(['PassengerId',‘Name','Ticket',‘Cabin','Embarked'],axis=1)
train.head()

那下一步是我们要给分类变量引入虚拟变量,也就是分别用 0 和1表示是否属于该类别,那一看到这个 survive 它本身就是用 0和1表示的,所以我们不需要再动它了。然后另外两个分类变量,它们分别是 pclass 船舱等级以及 sex 性别。

分类变量onehot化
onehot_columns =["Pclass","Sex"]#把需要onehot编码的列通通扔进去
train= pd.get_dummies(
   train,     #这行传入整个train                            
   columns=onehot_columns ,#传入上面的列"Pclass","Sex"#要转码的列
   prefix=onehot_columns,# 生成的列名的前缀意思就是sex列编程sex_male 和sex_fmale,方便查看
#把空值也做编码          
    drop_first=True)           # 删掉第一列 ,防止出现问题
train.head()

在这里插入图片描述

划分自变量和因变量

因变量是Survived变量,因为我们进行逻辑回归的目的,是根据其它可能对乘客生还概率有影响的变量,来预测幸存情况

y=train['Survived']

我们可以把除Survived之外的先纳入自变量,但需要查看它们之间的相关性,如果其中有些变量之间相关性很高,会导致共线性。

X=train.drop(['Survived'],axis=1)
X.corr()

在这里插入图片描述

我们认为,当相关系数的绝对值大于0.8的时候,可能导致严重共线性,所以我们检查的时候,找绝对值大于0.8的值即可。

X.corr().abs()>0.8

单元格里面每一个数字它的绝对值都会去拿去和 0.8 进行比较。

在这里插入图片描述

那可以看到的这个 Sibsp 它们之间的相关系数是大于 0.8 的。那这个其实是符合预期的,因为咱们说到底 family num 它就是 sibsp和这个 parch 它们俩加一起得到的,那为了解决这个问题,我们可以把 Sibsp 这个变量给它移除掉。后另外这个 partch 它和 family num 之间也必然是强相关。因为这个 是一个道理,我们可以回去看一下他们之间相关系数,那你看到果然是比较大的一个数字,0.78,四舍五入也有 0.8 了。那为了避免算法无法收敛,我们要对这俩进行移除。

X = X.drop(['Parch', 'SibSp'], axis=1)

4.模型训练

4.1 划分训练集测试集

y=df_coded.pop('Survived')# pop删除并返回该列的值,这里就是删除Survived列

在这里插入图片描述

x=df_coded
x.head()

在这里插入图片描述
x没有Survived那一列了

from sklearn.model_selection import train_test_split#划分训练集和测试集

划分出训练集和测试集再进行下一步。

train_X, test_X, train_y, test_y = train_test_split(x,y,                                      
             train_size=.8)

X:这是您特征数据集,通常是一个二维数组或者pandas DataFrame。
y:这是目标变量(标签)数据集,通常是一个一维数组或者pandas Series。
train_size=0.8:这个参数指定了训练集应该占总数据集的80%,剩下的20%将用作测试集。

print ('原始数据集特征:',source_X.shape, 
       '训练数据集特征:',train_X.shape ,
      '测试数据集特征:',test_X.shape)
原始数据集特征: (1309, 29) 
训练数据集特征: (1047, 29) 
测试数据集特征: (262, 29)

也可以用随机种子分开

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)

4.2引入逻辑回归模型

from sklearn.linear_model import LogisticRegression#导入逻辑回归模块
logreg=LogisticRegression(solver='liblinear')#使用solver求解器
model.score(X,y)

LogisticRegression:这是scikit-learn库中的一个类,用于实现逻辑回归模型。逻辑回归是一种广泛用于二分类问题的统计方法,尽管它也可以用于多分类问题。
solver:这个参数用于指定用于优化问题的求解器。不同的求解器适用于不同类型的问题和数据大小。
‘liblinear’:这是一个适用于小数据集的线性求解器。它适用于标准的逻辑回归(不带正则化项或带有L1和L2正则化项的逻辑回归)。对于多类问题,它默认使用一对多(one-vs-rest)的方法。
以下是LogisticRegression类中solver参数的一些常见选项:

‘liblinear’:适用于小数据集。
‘newton-cg’、‘sag’、‘saga’ 和 ‘lbfgs’:这些是适用于大数据集的优化求解器。其中,'sag’和’saga’适用于大规模稀疏数据集。

4.3用测试集来预测

把次数集和训练集对齐

test['Age'] = test['Age'].fillna(test['Age'].mean())
test['Fare'] = test['Fare'].fillna(test['Fare'].mean())
test.info()
test['FamilyNum'] = test['SibSp'] + test['Parch']
test = test.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Embarked', 'SibSp','Parch'],axis=1)
test = pd.get_dummies(test, columns=onehot_columns, prefix=onehot_columns, drop_first=True, dtype=int)

显示预测结果

predictions = model.predict(test)
predictions

在这里插入图片描述

4.4完整代码

import pandas as pd
train = pd.read_csv("./train.csv")
test = pd.read_csv("./test.csv")
print('训练数据集大小:', train.shape)
print('测试数据集大小:', test.shape)
train.head()
train.describe()
train.info()
train['Age'] = train['Age'].fillna(train['Age'].mean())
train.info()
train['FamilyNum'] = train['SibSp'] + train['Parch']
train.head(20)
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_palette("pastel")
plt.rcParams["figure.figsize"] = [7.00, 3.50]
plt.rcParams["figure.autolayout"] = True
survived_count = train['Survived'].value_counts()
survived_label = survived_count.index
plt.pie(survived_count, labels=survived_label, autopct='%.1f%%')
plt.show()
figure, axes = plt.subplots(1, 2)
sns.histplot(train, x='Age', ax=axes[0])
sns.boxplot(train, y='Age', ax=axes[1])
plt.show()
sns.histplot(train, x='Age', hue='Survived', alpha=0.4)
plt.show()
train = train.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Embarked'], axis=1)
onehot_columns = ["Pclass", "Sex"]
train = pd.get_dummies(train, columns=onehot_columns, prefix=onehot_columns, drop_first=True, dtype=int)
train.head()
y = train['Survived']
X = train.drop(['Survived'], axis=1)
X.corr()
X = X.drop(['Parch', 'SibSp'], axis=1)
X.head()
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X, y)
score = model.score(X, y)
print("模型得分:", score)
test['Age'] = test['Age'].fillna(test['Age'].mean())
test['Fare'] = test['Fare'].fillna(test['Fare'].mean())
test.info()
test['FamilyNum'] = test['SibSp'] + test['Parch']
test = test.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Embarked', 'SibSp','Parch'],axis=1)
test = pd.get_dummies(test, columns=onehot_columns, prefix=onehot_columns, drop_first=True, dtype=int)
predictions = model.predict(test)
predictions

总结

利用一个例子学习逻辑回归的模型

  • 19
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值