本文对机器学习课程考试中可能出现的模型代码题进行总结,仅供参考。
对数几率回归(Logistic Regression)是机器学习中一种广泛应用的统计学习方法,主要用于二分类问题。尽管其名字中包含“回归”这个词,但实际上它是一种分类算法,而不是传统的回归算法。
对数几率回归的核心思想是使用逻辑函数(也称为Sigmoid函数)将线性回归的输出映射到[0,1]区间,从而可以得到一个概率值。
Sigmoid函数定义为:
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
其中, z = w 0 + w 1 x 1 + w 2 x 2 + … + w n x n z = w_0 + w_1 x_1 + w_2 x_2 + \ldots + w_n x_n z=w0+w1x1+w2x2+…+wnxn是线性组合。
对于二分类问题,假设正类的标签为1,负类的标签为0,我们可以使用对数几率函数来建模某个实例属于正类的概率为:
P ( Y = 1 ∣ X ) = σ ( w T x ) = 1 1 + e − w T x P(Y=1|X) = \sigma(w^T x) = \frac{1}{1 + e^{-w^T x}} P(Y=1∣X)=σ(wTx)=1+e−wTx1
对数几率回归使用最大似然估计来估计参数 ( w )。对于给定的训练数据,损失函数(或对数似然函数)为:
L ( w ) = ∑ i = 1 m [ y ( i ) log ( σ ( w T x ( i ) ) ) + ( 1 − y ( i ) ) log ( 1 − σ ( w T x ( i ) ) ) ] L(w) = \sum_{i=1}^{m} [y^{(i)} \log(\sigma(w^T x^{(i)})) + (1 - y^{(i)}) \log(1 - \sigma(w^T x^{(i)}))] L(w)=i=1∑m[y(i)log(σ(wTx(i)))+(1−y(i))log(1−σ(wTx(i)))]
通常,为了最小化这个损失函数,可以使用梯度下降或其他优化算法。
总之,对数几率回归是一种基于线性模型和逻辑函数的分类算法,广泛应用于各种应用场景,如文本分类、信用评分、医学诊断等。
import numpy as np
import pandas as pd
def generate_data():
datasets = pd.read_csv('dataSet.csv', header=None).values.tolist()
labels = pd.read_csv('labels.csv', header=None).values.tolist()
return datasets, labels
def sigmoid(X):
hx = 1/(1+np.exp(-X))
return hx
#code end here
def gradientDescent(dataMatIn, classLabels):
alpha = 0.001 # 学习率,也就是题目描述中的 α
iteration_nums = 100 # 迭代次数,也就是for循环的次数
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose()
m, n = np.shape(dataMatrix) # 返回dataMatrix的大小。m为行数,n为列数。
weight_mat = np.ones((n, 1)) #初始化权重矩阵
for i in range(iteration_nums):
hx=sigmoid(dataMatrix*weight_mat)
weight_mat-=alpha*dataMatrix.transpose()*(hx-labelMat)
return weight_mat
if __name__ == '__main__':
dataMat, labelMat = generate_data()
print(gradientDescent(dataMat, labelMat))
支持向量机(Support Vector Machine,简称 SVM)是一种机器学习算法,主要用于分类和回归分析。尤其在分类问题中,SVM 是非常受欢迎和有效的方法之一。
在分类问题中,SVM 的目标是找到一个最优的超平面,以最大化两个不同类别的数据点(即支持向量)之间的间隔。这个超平面可以有效地将两个不同的类别分开。
线性可分情况:在两类数据是线性可分的情况下,SVM 试图找到一个使得间隔最大化的超平面。这个间隔是由距离最近的正类和负类样本点决定的,这些样本点被称为支持向量。
软间隔与核技巧:在实际应用中,数据往往不是完全线性可分的。为了解决这个问题,SVM 引入了“软间隔”概念,允许一些样本出现在错误的一侧。此外,通过核技巧,SVM 可以将线性不可分的数据映射到高维空间,从而使其线性可分。
在 SVM 中,损失函数旨在最大化间隔并确保所有的样本点(或大部分样本点)被正确分类。数学上,这通常通过求解一个二次规划(Quadratic Programming)问题来实现。
然而,SVM 也有其局限性,如处理大规模数据集时可能面临计算效率问题,对于高度非线性和复杂的问题,选择合适的核函数和参数也是一项挑战。
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
data = np.array(df.iloc[:100, [0, 1, -1]])
for i in range(len(data)):
if data[i,-1] == 0:
data[i,-1] = -1
return data[:,:2], data[:,-1]
#使用RBF(Radial basis function)核函数处理
def K(x,z,sigma=1.5):
return np.exp(np.dot((x-z),(x-z).T)/-(2*sigma**2))
#对应课本147页的g(x_i),该函数助于验证KKT条件
def g(i,x,y,alpha,b):
sum=b
for j in range(len(y)):
sum+=alpha[j]*y[j]*K(x[i],x[j])
return sum
#验证第i个样本点是否满足KKT条件
def isKKT(alpha,i,x,y,b,C):
if alpha[i]==0 and y[i]*g(i,x,y,alpha,b)>=1:
return True
elif alpha[i]==C and y[i]*g(i,x,y,alpha,b)<=1:
return True
elif alpha[i]>0 and alpha[i]<C and y[i]*g(i,x,y,alpha,b)==1:
return True
else:
return False
#验证第i个样本点违反KKT条件的程度。由于KKT条件和y_i*g(x_i)与1的不等式有关
#因此计算y_i*g(x_i)与1之间差值的绝对值作为衡量违反程度的标准
def vioKKT(alpha,i,x,y,b):
return abs(y[i]*g(i,x,y,alpha,b)-1)
#在数组x中找到值为a的元素第一次出现的位置
def findindex(x,a):
for i in range(len(x)):
if x[i]==a:
return i
#某个样本点分类误差函数
def E(w,b,x_k,y_k):
predi_k=int(np.sign(np.dot(w,x_k.T)+b))
return predi_k-y_k
#计算样本点与分割直线的距离
def distance_count(x,w,b):
return abs(w[0]*x[0]+w[1]*x[1]+b) / np.sqrt(w[0]**2 + w[1]**2)
SVM-sklearn
1.导库
2.加载数据
data = pd.read_csv('your_dataset.csv')
X = data.drop('target_column', axis=1)
y = data['target_column']
3.划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
4.数据预处理
# 使用 StandardScaler 进行特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
5.选择并训练模型
model = SVC(kernel='rbf', C=1.0, gamma='scale')
model.fit(X_train_scaled, y_train)
# kernel: 核函数的类型,可以选择线性核'linear'、多项式核'poly'、径向基核'rbf'等。
# C: 正则化参数,控制决策边界的平滑度,值越小,决策边界越平滑。
# gamma: 核函数的系数,影响数据映射到高维空间后的形状,值越大,影响范围越小。
6.模型评估
y_pred = model.predict(X_test_scaled)
print("Accuracy:", accuracy_score(y_test, y_pred))
print("Classification Report:\n", classification_report(y_test, y_pred))
在机器学习和数据挖掘中,信息增益(Information Gain)是用于特征选择的一个关键指标,特别是在决策树算法(如ID3、C4.5等)中。信息增益的目标是找到最能区分不同类别的特征。
信息增益的计算基于信息论中的熵(Entropy)概念。给定一个数据集,其熵表示了该数据集的不确定性或混乱程度。具体来说,熵的计算公式为:
Entropy ( S ) = − ∑ i = 1 c p i log 2 p i \text{Entropy}(S) = - \sum_{i=1}^{c} p_i \log_2 p_i Entropy(S)=−i=1∑cpilog2pi
其中,
p i p_i pi是数据集中第 i类样本所占的比例,c 是类别的总数。
在特征选择过程中,我们希望找到那些能最大程度地降低数据集整体熵的特征。因此,信息增益用于衡量某个特征引入后整体熵的减少量。对于特征 ( A ),其信息增益 Gain ( S , A ) \text{Gain}(S, A) Gain(S,A)的计算公式为:
Gain ( S , A ) = Entropy ( S ) − ∑ v ∈ Values ( A ) ∣ S v ∣ ∣ S ∣ × Entropy ( S v ) \text{Gain}(S, A) = \text{Entropy}(S) - \sum_{v \in \text{Values}(A)} \frac{|S_v|}{|S|} \times \text{Entropy}(S_v) Gain(S,A)=Entropy(S)−v∈Values(A)∑∣S∣∣Sv∣×Entropy(Sv)
其中:
通过计算不同特征的信息增益,我们可以确定哪个特征是最佳的划分特征,以便在决策树的构建过程中进行节点分裂。特征选择过程的目标是在保持模型预测准确性的同时,尽可能减少模型的复杂性。
import numpy as np
import pandas as pd
from collections import Counter
import random
dataSet = pd.read_csv('dataSet.csv', header=None).values.T # 转置 5*15数组
def entropy(data): # 信息熵 data 一维数组
numEntres = len(data)
cnt = Counter(data) # 计数每个值出现的次数 Counter({1: 8, 0: 5})
probability_lst = [1.0 * cnt[i] / numEntres for i in cnt]
return -np.sum([p * np.log2(p) for p in probability_lst]) # 返回信息熵
def calc_max_info_gain(dataSet): #信息增益
label = np.array(dataSet[-1])
total_entropy = entropy(label)
max_info_gain = [0, 0]
for feature in range(4): # 4种特征 我命名为特征:0 1 2 3
f_index = {}
for idx, v in enumerate(dataSet[feature]):
if v not in f_index:
f_index[v] = []
f_index[v].append(idx)
f_impurity = 0
for k in f_index:
# 根据该特征取值对应的数组下标 取出对应的标签列表 比如分支1有多少个正负例 分支2有...
f_l = label[f_index[k]]
f_impurity += entropy(f_l) * len(f_l) / len(label) # 循环结束得到各分支混杂度的期望
gain = total_entropy - f_impurity # 信息增益IG
if gain > max_info_gain[1]:
max_info_gain = [feature, gain]
return max_info_gain
if __name__ == '__main__':
info_res = calc_max_info_gain(dataSet)
print("信息增益最大的特征索引为:{0},对应的信息增益为{1}".format(info_res[0], info_res[1]))
通过交叉验证来选择适当的树深度是一种常见的模型选择方法。下面是一般的步骤:
划分数据集: 将数据集划分为训练集和验证集。通常,采用k折交叉验证,将数据集分成k个子集,每次使用k-1个子集作为训练数据,剩余的一个子集作为验证数据。
建立决策树: 使用训练集建立决策树模型,可以通过调整树的深度来控制模型的复杂性。
评估模型: 在每个交叉验证的迭代中,使用验证集评估模型性能。可以使用一些性能指标(如准确率、F1分数等)来衡量模型在验证集上的表现。
选择最佳深度: 对于每个树深度,计算模型在所有交叉验证迭代中的平均性能。选择在验证集上性能最好的树深度作为最终模型的深度。
训练最终模型: 使用整个训练集训练一个新的决策树模型,选择的深度是在验证集上表现最好的深度。
这个过程称为网格搜索(Grid Search),因为它涉及对深度的多个可能值进行搜索,找到使得模型性能最优的深度。在实际应用中,可以使用不同的性能指标、树的深度范围和交叉验证的折数进行调整,以获得最佳模型。
决策树-sklearn
1.导库
2.加载数据
data = pd.read_csv('your_dataset.csv')
X = data.drop('target_column', axis=1)
y = data['target_column']
3.划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
4.数据预处理
# 示例:使用 StandardScaler 进行特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
5.选择并训练模型
(1)决策树
model = DecisionTreeClassifier(criterion='gini', max_depth=None, random_state=42)
model.fit(X_train, y_train)
# criterion: 衡量分割质量的标准,可以选择基尼系数'gini'或信息增益'entropy'。
# max_depth: 决策树的最大深度,控制树的复杂度,防止过拟合。
# random_state: 为了确保可重复性,设置一个随机种子。
(2)随机森林
model = RandomForestClassifier(n_estimators=100, criterion='gini', max_depth=None, random_state=42)
model.fit(X_train, y_train)
# n_estimators: 随机森林中决策树的数量
(3)SVM
model = SVC(kernel='rbf', C=1.0, gamma='scale')
model.fit(X_train_scaled, y_train)
# kernel: 核函数的类型,可以选择线性核'linear'、多项式核'poly'、径向基核'rbf'等。
# C: 正则化参数,控制决策边界的平滑度,值越小,决策边界越平滑。
# gamma: 核函数的系数,影响数据映射到高维空间后的形状,值越大,影响范围越小。
5.模型评估
y_pred = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))
print("Classification Report:\n", classification_report(y_test, y_pred))
SVM伪代码
Input: 训练集 D = {(x1, y1), (x2, y2), ..., (xm, ym)}, 学习率 η, 松弛变量惩罚参数 C
Output: SVM模型参数 w, b
// 初始化模型参数
w = [0, 0, ..., 0] // 与特征数一致的零向量
b = 0
// 定义SVM模型的目标函数
def svm_objective_function(w, b, C, D):
loss = 0.5 * np.dot(w, w) // 正则化项
for i in range(len(D)):
xi, yi = D[i]
loss += C * max(0, 1 - yi * (np.dot(w, xi) + b)) // Hinge Loss
return loss
// 训练SVM模型
for epoch in range(num_epochs):
for i in range(len(D)):
xi, yi = D[i]
// 判断是否违反约束条件
if yi * (np.dot(w, xi) + b) < 1:
// 更新模型参数
w = w - η * (w - C * yi * xi)
b = b + η * C * yi
else:
// 没有违反约束条件,只更新正则化项
w = w - η * w
// 返回训练后的模型参数
Output: w, b