使用 Logistic 回归进行鸢尾花品种分类【课堂笔记】

前言

感觉如果只是看一遍老师提供的课件的话,对 pandas 库以及 sklearn 库中许多功能还是没有一个全面的认识,我感觉还是得自己多动手实践一下才行。(下文代码中使用的库均预先装好,下文代码均在 jupyter notebook 中运行。)

数据存入 csv 文件

我们已经将鸢尾花数据集中的数据存放到了 ./iris.csv 文件中,文件内容的前 10 10 10 行如下。

sepal_length,sepal_width,petal_length,petal_width,species
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
4.4,2.9,1.4,0.2,Iris-setosa
...

csv 文件中的第一行给出了每一列的字段名,其后每一行给出一条记录,值与值之间通过逗号分隔,记录之间通过换行分割。(如果我以后要制作自己的数据集的话,估计也要使用类似结构)

pandas.read_csv 读取 csv 文件

import pandas as pd
iris = pd.read_csv("./iris.csv") # 读取 csv 文件,并返回一个 DataFrame 数据框
print(type(iris)) # 输出 <class 'pandas.core.frame.DataFrame'>
print(type(iris["sepal_length"])) # 输出 <class 'pandas.core.series.Series'>

可见 DataFrame 可以通过指定一个下标选中相应的列。

seaborn.pairplot 观察数据关联

%matplotlib inline # 魔术指令,在 jupyter notebook 中显示 matplotlib 图像
import seaborn as sns
sns.pairplot(iris, hue='species') # 以 species 特征区分颜色

输出了如下图像:
数据关联
可以观察到 Iris-setosa 具有非常明显的区别于另外两者的特征。Iris-versicolorIris-virginica 的数据特征相靠近。

检查一下前十行的数据

iris.head(10) # 前十行的数据(在 jupyter notebook 中可以显示一个比较美观的 DataFrame)
# 同理还可以使用 iris.tail(10) 显示后十行的数据

数据如下:

前十行数据
可以看到,这些数据与前文中 csv 文件中的数据是一致的。

统计 species 的值

上文中的 iris 是一个 DataFrame 数据框,iris[species] 是从 iris 中取出的一列数据,是一个 Series 序列。可以使用 .value_counts 函数统计一个 Series 中出现的各种值。

print(iris["species"].value_counts())

输出:

Iris-virginica     50
Iris-setosa        50
Iris-versicolor    50
Name: species, dtype: int64

从输出可以看到带有 Iris-cirginicaIris-setosaIris-versicolor 标签的记录各有 50 50 50 条,数据集中总共有 150 150 150 条数据。不过说实话,我并不是很理解这个 dtype 为什么会是 int64

用 train_test_split 将标签和数据分离

from sklearn.model_selection import train_test_split
X = iris[["sepal_length","sepal_width","petal_length","petal_width"]]
y = iris["species"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify = y)

按照上述代码,我们得到的 X 是一个 DataFrame 数据框,它是 iris 数据框的一个子数据框,包含 iris 数据框中的四列内容。y 是一个 Series 序列,也就是 iris 数据框中的一个字段。

使用 train_test_split 函数,我们将数据集 ( X , y ) (X,y) (X,y) 随机地分成了训练集 ( X t r a i n , y t r a i n ) (X_{train}, y_{train}) (Xtrain,ytrain) 和测试集 ( X t e s t , y t e s t ) (X_{test}, y_{test}) (Xtest,ytest),其中 stratify = y 表示按照 y 值进行分层随机。换言之, y t r a i n y_{train} ytrain y t e s t y_{test} ytest 中三种花所占地比例均与 y y y 相同,为 1 : 1 : 1 1:1:1 1:1:1

使用 LogisticRegression 进行分类

from sklearn.linear_model import LogisticRegression
classifier = LogisticRegression(C=1e3, solver='lbfgs') # lbfgs 利用 损失函数 二阶导数 也就 海森阵 优化
classifier.fit(X_train, y_train) # 训练分类器

使用 matrics 进行性能评估

from sklearn import metrics
predict_y = classifier.predict(X_test) # 对测试集计算预测值向量
print (metrics.classification_report(y_test,predict_y)) # 根据预测值向量和测试集的标签生成报告
       precision    recall  f1-score   support

    Iris-setosa       1.00      1.00      1.00        15
Iris-versicolor       0.82      0.93      0.87        15
 Iris-virginica       0.92      0.80      0.86        15

    avg / total       0.92      0.91      0.91        45

由此可见,平均分类准确度为 91 % 91\% 91%

使用模型预测一个新的数据

print(classifier.predict([ [5.1, 3.5, 0.4, 1.2] ]))

输出:

['Iris-setosa']

注意:由于我们的输入应该是一个 DataFrame,换言之是一个表格,因此我们给出的输入数据必须用两层中括号括起来 (构成一个 list of list,外层 list 中的每个元素表示数据集中的一个记录,内层 list 中的某个元素表示某个记录中的某个字段),不然会报错(数据个数不匹配)。

其实这组数据只不过是抄了一下整个数据集中第一组元素的数据罢了,可以看到我们的模型给出了正确的预测。

课后作业:线性回归预测鸢尾花数据集

import pandas as pd
iris = pd.read_csv("./iris.csv") # 加载数据集合

%matplotlib inline
import seaborn as sns
sns.pairplot(iris,hue='species') # 输出 pairplot

# 可以看到在尺寸上,三种花具有顺序关系:
# Iris-setosa(蓝色) < Iris-versicolor < Iris-virginica
def species_to_id(species_name: str):
    dic = {"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2}
    return dic[species_name]

iris["species"] = iris["species"].map(species_to_id)
print(iris.head(1)) # 输出第一行进行检查

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
X = iris[["sepal_length", "sepal_width", "petal_length", "petal_width"]]
y = iris["species"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42,stratify=y) # 划分测试集

lm = LinearRegression()
lm.fit(X_train, y_train) # 进行线性回归
print("截距为:", lm.intercept_) # 常数项
pd.DataFrame([X.columns, lm.coef_]) # 各项系数

def to_regular(vals : float):
    if vals <= 0:
        return 0
    elif vals >= 2:
        return 2
    else:
        return int(round(vals)) # 四舍五入
predict_y = lm.predict(X_test) # 生成预测向量
predict_y = [to_regular(x) for x in predict_y]

from sklearn import metrics
print (metrics.classification_report(y_test,predict_y)) # 输出分析

import matplotlib.pyplot as plt
plt.scatter(lm.predict(X_test), lm.predict(X_test) - y_test, c="g", alpha=0.5)
plt.hlines(y=0, xmin=0, xmax=2)
plt.ylabel("Residuals")

本地测试分类准确度为 96 % 96\% 96%,甚至比 Logistic 回归更高一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值