Логистическая регрессия для машинного обучения (реализация на чистом Python)

машинное обучение искусственный интеллект Python алгоритм

Логистическая регрессия — это обобщенная линейная регрессия, в которой используется машинное обучение для классификации или прогнозирования путем построения функции регрессии.

принцип

В предыдущей статье кратко была представлена ​​линейная регрессия, которая в принципе похожа на логистическую регрессию.

  1. функция предсказания (h). Эта функция является функцией классификации, которая используется для прогнозирования результата оценки входных данных. Процесс имеет решающее значение и должен предсказать «грубую форму» функции, например, является ли она линейной или нелинейной. Эта статья относится к соответствующей части практики машинного обучения и рассматривает набор данных.
// 两个特征
-0.017612   14.053064   0
-1.395634   4.662541    1
-0.752157   6.538620 0
-1.322371   7.152853    0
0.423363 11.054677   0
0.406704    7.067335    1

image.png
Как показано выше, красный и зеленый представляют две разные категории. Можно предсказать, что классификационная функция будет примерно прямой линией.

  1. Функция стоимости (функция потерь): отклонение между выходом h, предсказанным функцией, и категорией обучающих данных y, (h-y) или другими формами. Принимая во внимание стоимость всех обучающих данных, суммируйте или усредните их, что является чрезвычайно J-функцией, которая представляет собой отклонение между прогнозируемым значением и фактическим значением всех обучающих данных.

  2. Очевидно, что чем меньше значение функции J, тем точнее прогнозируемая функция (то есть точнее функция h), поэтому необходимо найти минимальное значение функции J. Иногда требуется градиентный спуск.

Конкретный процесс

Создайте функцию предсказания

Логистическая регрессия называется регрессией, которая на самом деле является классификацией и используется для задач с двумя классами. Сигмоидальная функция дана прямо здесь.

image.png
image.png

Затем определите границы классификации, Как упоминалось выше, для набора данных требуется линейная граница. Разные данные требуют разных границ.

image.png

Функция классификации определена, и ее вход обозначен как z, тогда

image.png
Вектор x является переменной функции и входными данными. Эти данные имеют две особенности и могут быть представлены как z = w0x0 + w1x1 + w2x2. w0 — постоянный член, и x0 должен быть равен 1 (см. код ниже). Вектор W является функцией коэффициента регрессии, а T представлен как вектор-столбец. Следующим шагом является определение наилучших коэффициентов регрессии w(w0, w1, w2).

функция стоимости

Исходя из вышеизложенного, функция предсказания имеет вид:

image.png
image.png
Здесь нет вывода, вы можете обратиться к статьеСводка по логистической регрессии

image.png

С приведенной выше функцией стоимости вы можете использовать метод градиентного подъема, чтобы найти минимальное значение функции J. Смотрите ссылку выше для вывода.

В итоге: формула обновления градиента выглядит следующим образом:

image.png

Далее идет реализация кода Python:

# sigmoid函数和初始化数据
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def init_data():
    data = np.loadtxt('data.csv')
    dataMatIn = data[:, 0:-1]
    classLabels = data[:, -1]
    dataMatIn = np.insert(dataMatIn, 0, 1, axis=1)  #特征数据集,添加1是构造常数项x0
    return dataMatIn, classLabels
//  梯度上升
def grad_descent(dataMatIn, classLabels):
    dataMatrix = np.mat(dataMatIn)  #(m,n)
    labelMat = np.mat(classLabels).transpose()
    m, n = np.shape(dataMatrix)
    weights = np.ones((n, 1))  #初始化回归系数(n, 1)
    alpha = 0.001 #步长
    maxCycle = 500  #最大循环次数

    for i in range(maxCycle):
        h = sigmoid(dataMatrix * weights)  #sigmoid 函数
        weights = weights + alpha * dataMatrix.transpose() * (labelMat - h)  #梯度
    return weights
// 计算结果
if __name__ == '__main__':
    dataMatIn, classLabels = init_data()
    r = grad_descent(dataMatIn, classLabels)
    print(r)

Введите следующее:

[[ 4.12414349]
 [ 0.48007329]
 [-0.6168482 ]]

Приведенный выше w является желаемым коэффициентом регрессии. w0 = 4,12414349, w1 = 0,4800, w2=-0,6168 Ранее предсказанное уравнение линии 0 = w0x0 + w1x1 + w2x2 вводится в коэффициенты регрессии для определения границы. х2 = (-w0 - w1*x1) / w2

Постройте изображение функции:

def plotBestFIt(weights):
    dataMatIn, classLabels = init_data()
    n = np.shape(dataMatIn)[0]
    xcord1 = []
    ycord1 = []
    xcord2 = []
    ycord2 = []
    for i in range(n):
        if classLabels[i] == 1:
            xcord1.append(dataMatIn[i][1])
            ycord1.append(dataMatIn[i][2])
        else:
            xcord2.append(dataMatIn[i][1])
            ycord2.append(dataMatIn[i][2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1,s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')
    x = np.arange(-3, 3, 0.1)
    y = (-weights[0, 0] - weights[1, 0] * x) / weights[2, 0]  #matix
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()

следующее:

image.png

Улучшение алгоритма

Стохастический градиентный подъем

В приведенном выше алгоритме для каждой циклической матрицы выполняется m * n умножений, а временная сложность равна maxCycles* m * n. Когда объем данных велик, временная сложность очень велика. Здесь попробуйте использовать стохастический градиентный подъем для улучшения.随机梯度上升法的思想是,每次只使用一个数据样本点来更新回归系数。这样就大大减小计算开销。Алгоритм следующий:

def stoc_grad_ascent(dataMatIn, classLabels):
    m, n = np.shape(dataMatIn)
    alpha = 0.01
    weights = np.ones(n)
    for i in range(m):
        h = sigmoid(sum(dataMatIn[i] * weights))  #数值计算
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatIn[i]
    return weights

провести тестирование:

image.png

Улучшения стохастического градиентного подъема

def stoc_grad_ascent_one(dataMatIn, classLabels, numIter=150):
    m, n = np.shape(dataMatIn)
    weights = np.ones(n)
    for j in range(numIter):
        dataIndex = list(range(m))
        for i in range(m):
            alpha = 4 / (1 + i + j) + 0.01 #保证多次迭代后新数据仍然有影响力
            randIndex = int(np.random.uniform(0, len(dataIndex)))
            h = sigmoid(sum(dataMatIn[i] * weights))  # 数值计算
            error = classLabels[i] - h
            weights = weights + alpha * error * dataMatIn[i]
            del(dataIndex[randIndex])
    return weights

image.png

Коэффициенты регрессии для трех вышеупомянутых случаев можно изобразить в виде флуктуаций. Можно обнаружить, что третий метод сходится быстрее.评价算法优劣势看它是或否收敛,是否达到稳定值,收敛越快,算法越优。

Суммировать

Градиентный подъем и градиентный спуск, используемые здесь, одинаковы, оба они предназначены для нахождения максимального значения функции, и символ необходимо изменить. Градиент означает перемещение на определенное расстояние по направлениям x и y соответственно. (производная стоимости по x, y соответственно).

Пожалуйста, смотрите полный код:github: logistic regression

Справочная статья:Логистическая регрессия и реализация машинного обучения на Python
Примечания к машинному обучению: сводка по логистической регрессии
Логистическая регрессия серии базовых алгоритмов машинного обучения