某位老师想用学生上学期考试的成绩(Last Score)和本学期在学习上花费的时间(Hours Spent)来预期本学期的成绩:
面对这样一个需求,我们可能首先想到的是线性回归,毕竟,要做的是预测本次的成绩。那样的话,我们取 X = [“Last Score”, “Hours Spent”],y = “Score”。
用线性回归实现代码如下:
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import LinearRegression
import pandas as pd
# Importing dataset
data = pd.read_csv('data.csv', delimiter=',') # decimal : str, default ‘.’字符中的小数点 (例如:欧洲数据使用’,‘).
used_features = ["Last Score", "Hours Spent"]
X = data[used_features].values
scores = data["Score"].values
X_train = X[:11]
X_test = X[11:]
# Linear Regression - Regression
y_train = scores[:11]
y_test = scores[11:]
regr = LinearRegression()
regr.fit(X_train, y_train)
y_predict = regr.predict(X_test)
print(y_predict)
我们把前11个样本作为训练集,最后3个样本作为测试集。
这样训练出来之后,得到的预测结果为:[55.33375602 54.29040467 90.76185124],也就说 id 为 12-14 的三个同学的预测分数为55,54和91。
第一个差别比较大,id 为12的同学,明明考及格了,却被预测为不及格。
这是为什么呢?大家注意 id 为4的同学,这是一位学霸,他只用了20小时在学习上,却考出了第一名的好成绩。
回想一下线性回归的目标函数,我们不难发现,所有训练样本对于目标的贡献是平均的,因此,4号同学这种超常学霸的出现,在数据量本身就小的情况下,有可能影响整个模型。
这还是幸亏我们有历史记录,知道上次考试的成绩,如果 X 只包含“Hours Spent”,学霸同学根本就会带偏大多数的预测结果(自变量只有“Hours Spent”的线性回归模型会是什么样的?这个问题留给同学们自己去实践)。
那么我们看看用逻辑回归如何。用逻辑回归的时候,我们就不再是预测具体分数,而是预测这个学生本次能否及格了。
这样我们就需要对数据先做一下转换,把具体分数转变成是否合格,合格标志为1,不合格为0,然后再进行逻辑回归:
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import LinearRegression
import pandas as pd
# Importing dataset
data = pd.read_csv('data.csv', delimiter=',')
used_features = [ "Last Score", "Hours Spent"]
X = data[used_features].values
scores = data["Score"].values
X_train = X[:11]
X_test = X[11:]
# Logistic Regression – Binary Classification
passed = []
for i in range(len(scores)):
if(scores[i] >= 60):
passed.append(1)
else:
passed.append(0)
Y_train = passed[:11]
Y_test = passed[11:]
classifier = LogisticRegression(C=1e5)
classifier.fit(X_train, Y_train)
y_predict = classifier.predict(X_test)
print(y_predict)
这次的输出就是[1 0 1],对12、13、14号同学能否通过本次考试的判断是正确的。
LR 处理多分类问题
LR 是用来做二分类的,但是如果我们面对的是多分类问题:样本标签的枚举值多于2个,还能用 LR 吗?
当然是可以的。我们可以把二分类问题分成多次来做。
假设你一共有 n 个标签(类别),也就是说可能的分类一共有 n 个。那么就构造 n 个 LR 分类模型,第一个模型用来区分 label_1
和 non-label _1
(即所有不属于 label_1
的都归属到一类),第二个模型用来区分 label_2
和 non-label _2
……, 第 n 个模型用来区分 label_n
和 non-label _n
。
使用的时候,每一个输入数据都被这 n 个模型同时预测。最后哪个模型得出了 Positive 结果,就是该数据最终的结果。
如果有多个模型都得出了 Positive,那也没有关系。因为 LR 是一个回归模型,它直接预测的输出不仅是一个标签,还包括该标签正确的概率。那么对比几个 Positive 结果的概率,选最高的一个就是了。
例如,有一个数据,第一和第二个模型都给出了 Positive 结果,不过 label_1
模型的预测值是0.95,而 label_2
的结果是0.78,那么当然是选高的,结果就是 label_1
。
说起原理来好像挺麻烦,好在 sklearn 已经为我们处理了多分类问题,我们用 sklearn 来做多分类的时候,只是需要把 y 准备好,其他的,都和做二分类一样就可以了。
比如还是上面的例子,现在我们需要区分:学生的本次成绩是优秀(>=85),及格,还是不及格。我们就在处理 y 的时候给它设置三个值:0 (不及格),1(及格)和2(优秀),然后再做 LR 分类就可以了。代码如下:
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import LinearRegression
import pandas as pd
# Importing dataset
data = pd.read_csv('data.csv', delimiter=',')
used_features = [ "Last Score", "Hours Spent"]
X = data[used_features].values
scores = data["Score"].values
X_train = X[:11]
X_test = X[11:]
# Logistic Regression - Multiple Classification
level = []
for i in range(len(scores)):
if(scores[i] >= 85):
level.append(2)
elif(scores[i] >= 60):
level.append(1)
else:
level.append(0)
y_train = level[:11]
y_test = level[11:]
classifier = LogisticRegression(C=1e5)
classifier.fit(X_train, y_train)
y_predict = classifier.predict(X_test)
print(y_predict)
测试集的输出是:[1 0 2] —— 12号及格,13号不及格,14号优秀,还是比较准的。
data.csv
Id,Last Score,Hours Spent,Score
1,90,117,89
2,85,109,78
3,75,113,82
4,98,20,95
5,62,116,61
6,36,34,32
7,87,120,88
8,89,132,92
9,60,83,52
10,72,92,65
11,73,112,71
12,56,143,62
13,57,97,52
14,91,119,93