📜  理解逻辑回归

📅  最后修改于: 2021-10-19 08:02:01             🧑  作者: Mango

先决条件:线性回归
本文讨论了 Logistic 回归的基础知识及其在Python的实现。逻辑回归基本上是一种监督分类算法。在分类问题中,目标变量(或输出)y 只能为给定的特征(或输入)集合 X 取离散值。

与流行的看法相反,逻辑回归是一种回归模型。该模型构建了一个回归模型来预测给定数据条目属于编号为“1”的类别的概率。就像线性回归假设数据遵循线性函数,逻辑回归使用 sigmoid函数对数据进行建模。

g(z) = \frac{1}{1 + e^-^z}\

只有当决策阈值被引入图片时,逻辑回归才成为一种分类技术。阈值的设置是Logistic回归的一个非常重要的方面,依赖于分类问题本身。

阈值的决定主要受精度和召回率的影响。理想情况下,我们希望精度和召回率都为 1,但这种情况很少发生。在精确召回权衡的情况下,我们使用以下参数来决定阈值:-

1.低精度/高召回率:在我们希望减少误报数量而不一定减少误报数量的应用中,我们选择具有低精度值或高召回率值的决策值。例如,在癌症诊断应用程序中,我们不希望任何受影响的患者被归类为不受影响,而没有过多注意患者是否被错误诊断为癌症。这是因为,可以通过进一步的医学疾病检测到癌症的不存在,但在已经被拒绝的候选人中无法检测到该疾病的存在。

2.高精度/低召回率:在我们希望减少误报数量而不一定减少误报数量的应用中,我们选择具有高 Precision 值或低 Recall 值的决策值。例如,如果我们对客户对个性化广告的反应是正面还是负面进行分类,我们希望绝对确定客户会对广告做出正面反应,否则,负面反应可能会导致客户的潜在销售损失.

根据类别的数量,Logistic回归可以分为:

  1. 二项式:目标变量只能有两种可能的类型:“0”或“1”,代表“赢”与“输”、“通过”与“失败”、“死”与“活”等。
  2. 多项式:目标变量可以有 3 种或更多可能的类型,这些类型没有排序(即类型没有定量意义),例如“疾病 A”、“疾病 B”和“疾病 C”。
  3. ordinal:它处理具有有序类别的目标变量。例如,测试分数可以分类为:“非常差”、“差”、“好”、“非常好”。在这里,每个类别都可以给出一个分数,如 0、1、2、3。

首先,我们探索最简单的逻辑回归形式,即二项逻辑回归

二项逻辑回归

考虑一个示例数据集,该数据集将学习小时数与考试结果进行映射。结果只能取两个值,即passed(1) 或 failed(0):


Hours(x) 0.50 0.75 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00 4.25 4.50 4.75 5.00 5.50
Pass(y) 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1

所以,我们有

即 y 是一个分类目标变量,它只能采用两种可能的类型:“0”或“1”。
为了概括我们的模型,我们假设:

  • 该数据集具有“p”个特征变量和“n”个观测值。
  • 特征矩阵表示为:
    这里,  x_{ij}表示值 j^{th}功能为 i^{th}观察。
    在这里,我们保持让 x_{i0} = 1.(继续阅读,一会儿你就会明白其中的逻辑)。
  • i^{th}观察, x_i ,可以表示为:
  • h(x_i)表示预测的响应 i^{th}观察,即 x_i .我们用来计算的公式 h(x_i)称为假设

如果你已经学习过线性回归,你应该记得在线性回归中,我们用于预测的假设是:

在哪里,  \beta_0, \beta_1,…, \beta_p是回归系数。
让回归系数矩阵/向量,  \beta是:

然后,以更紧凑的形式,

现在,如果我们尝试将线性回归应用于上述问题,我们很可能会使用我们上面讨论的假设获得连续值。此外,它没有意义 h(x_i)取大于 1 或小于 0 的值。
因此,对分类假设进行了一些修改:

在哪里,

称为逻辑函数sigmoid函数
这是一个显示 g(z) 的图:
乙状结肠
我们可以从上图中推断:

  • g(z) 趋向于 1 作为 z\rightarrow\infty
  • g(z) 趋向于 0,因为 z\rightarrow-\infty
  • g(z) 总是在 0 和 1 之间

所以,现在,我们可以为 2 个标签(0 和 1)定义条件概率 i^{th}观察为:

我们可以更简洁地写成:

现在,我们定义另一个术语,参数的可能性为:

为了更容易计算,我们采用对数似然

逻辑回归的成本函数与参数似然的倒数成正比。因此,我们可以使用对数似然方程获得成本函数J 的表达式:

我们的目标是估计 \beta使成本函数最小化!!

使用梯度下降算法

首先,我们取偏导数 J(\beta)每一个 \beta_j \in \beta推导随机梯度下降规则(我们在此仅提供最终推导值):

这里,y 和 h(x) 分别表示响应向量和预测响应向量。还,  x_j是表示观测值的向量 j^{th}特征。
现在,为了得到 min  J(\beta) ,

在哪里 \alpha称为学习率,需要明确设置。
让我们在示例数据集上查看上述技术的Python实现(从这里下载):

2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00 4.25 4.50 4.75 5.00 5.50
import csv
import numpy as np
import matplotlib.pyplot as plt
  
  
def loadCSV(filename):
    '''
    function to load dataset
    '''
    with open(filename,"r") as csvfile:
        lines = csv.reader(csvfile)
        dataset = list(lines)
        for i in range(len(dataset)):
            dataset[i] = [float(x) for x in dataset[i]]     
    return np.array(dataset)
  
  
def normalize(X):
    '''
    function to normalize feature matrix, X
    '''
    mins = np.min(X, axis = 0)
    maxs = np.max(X, axis = 0)
    rng = maxs - mins
    norm_X = 1 - ((maxs - X)/rng)
    return norm_X
  
  
def logistic_func(beta, X):
    '''
    logistic(sigmoid) function
    '''
    return 1.0/(1 + np.exp(-np.dot(X, beta.T)))
  
  
def log_gradient(beta, X, y):
    '''
    logistic gradient function
    '''
    first_calc = logistic_func(beta, X) - y.reshape(X.shape[0], -1)
    final_calc = np.dot(first_calc.T, X)
    return final_calc
  
  
def cost_func(beta, X, y):
    '''
    cost function, J
    '''
    log_func_v = logistic_func(beta, X)
    y = np.squeeze(y)
    step1 = y * np.log(log_func_v)
    step2 = (1 - y) * np.log(1 - log_func_v)
    final = -step1 - step2
    return np.mean(final)
  
  
def grad_desc(X, y, beta, lr=.01, converge_change=.001):
    '''
    gradient descent function
    '''
    cost = cost_func(beta, X, y)
    change_cost = 1
    num_iter = 1
      
    while(change_cost > converge_change):
        old_cost = cost
        beta = beta - (lr * log_gradient(beta, X, y))
        cost = cost_func(beta, X, y)
        change_cost = old_cost - cost
        num_iter += 1
      
    return beta, num_iter 
  
  
def pred_values(beta, X):
    '''
    function to predict labels
    '''
    pred_prob = logistic_func(beta, X)
    pred_value = np.where(pred_prob >= .5, 1, 0)
    return np.squeeze(pred_value)
  
  
def plot_reg(X, y, beta):
    '''
    function to plot decision boundary
    '''
    # labelled observations
    x_0 = X[np.where(y == 0.0)]
    x_1 = X[np.where(y == 1.0)]
      
    # plotting points with diff color for diff label
    plt.scatter([x_0[:, 1]], [x_0[:, 2]], c='b', label='y = 0')
    plt.scatter([x_1[:, 1]], [x_1[:, 2]], c='r', label='y = 1')
      
    # plotting decision boundary
    x1 = np.arange(0, 1, 0.1)
    x2 = -(beta[0,0] + beta[0,1]*x1)/beta[0,2]
    plt.plot(x1, x2, c='k', label='reg line')
  
    plt.xlabel('x1')
    plt.ylabel('x2')
    plt.legend()
    plt.show()
      
  
      
if __name__ == "__main__":
    # load the dataset
    dataset = loadCSV('dataset1.csv')
      
    # normalizing feature matrix
    X = normalize(dataset[:, :-1])
      
    # stacking columns wth all ones in feature matrix
    X = np.hstack((np.matrix(np.ones(X.shape[0])).T, X))
  
    # response vector
    y = dataset[:, -1]
  
    # initial beta values
    beta = np.matrix(np.zeros(X.shape[1]))
  
    # beta values after running gradient descent
    beta, num_iter = grad_desc(X, y, beta)
  
    # estimated beta values and number of iterations
    print("Estimated regression coefficients:", beta)
    print("No. of iterations:", num_iter)
  
    # predicted labels
    y_pred = pred_values(beta, X)
      
    # number of correctly predicted labels
    print("Correctly predicted labels:", np.sum(y == y_pred))
      
    # plotting regression line
    plot_reg(X, y, beta)
Estimated regression coefficients: [[  1.70474504  15.04062212 -20.47216021]]
No. of iterations: 2612
Correctly predicted labels: 100

后勤_reg
注意:梯度下降是多种估计方法之一 \beta .
基本上,这些是更高级的算法,一旦您定义了成本函数和梯度,就可以在Python轻松运行。这些算法是:

  • BFGS(Broyden–Fletcher–Goldfarb–Shanno 算法)
  • L-BFGS(类似于BFGS,但使用有限的内存)
  • 共轭梯度

与梯度下降相比,使用这些算法中的任何一种的优点/缺点:

  • 优点
    • 不需要选择学习率
    • 通常跑得更快(并非总是如此)
    • 可以为您在数值上近似梯度(并不总是很好)
  • 缺点
    • 更复杂
    • 除非你了解细节,否则更多的是黑匣子

多项 Logistic 回归

在多项 Logistic 回归中,输出变量可以有两个以上可能的离散输出。考虑数字数据集。这里,输出变量是可以从 (0, 12, 3, 4, 5, 6, 7, 8, 9) 中取值的数字值。
下面给出了使用 scikit-learn 对数字数据集进行预测的多项 Logisitc 回归的实现。

from sklearn import datasets, linear_model, metrics
   
# load the digit dataset
digits = datasets.load_digits()
   
# defining feature matrix(X) and response vector(y)
X = digits.data
y = digits.target
  
# splitting X and y into training and testing sets
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4,
                                                    random_state=1)
   
# create logistic regression object
reg = linear_model.LogisticRegression()
   
# train the model using the training sets
reg.fit(X_train, y_train)
  
# making predictions on the testing set
y_pred = reg.predict(X_test)
   
# comparing actual response values (y_test) with predicted response values (y_pred)
print("Logistic Regression model accuracy(in %):", 
metrics.accuracy_score(y_test, y_pred)*100)
Logistic Regression model accuracy(in %): 95.6884561892

最后,这里有一些关于 Logistic 回归的思考点:

  • 不假设因变量和自变量之间存在线性关系,但确实假设解释变量logit响应之间存在线性关系。
  • 自变量甚至可以是原始自变量的幂项或其他一些非线性变换。
  • 因变量不需要是正态分布的,但它通常假设一个指数族的分布(例如二项式、泊松、多项式、正态等);二元逻辑回归假设响应呈二项分布。
  • 不需要满足方差的同质性。
  • 错误需要是独立的,但不是正态分布的。
  • 它使用最大似然估计 (MLE) 而不是普通最小二乘法 (OLS) 来估计参数,因此依赖于大样本近似

参考:

  • http://cs229.stanford.edu/notes/cs229-notes1.pdf
  • http://machinelearningmastery.com/logistic-regression-for-machine-learning/
  • https://onlinecourses.science.psu.edu/stat504/node/164