Из того, что я планирую на всю свою карьеру, я хочу не только сделать некоторыеприложение высокого качества(с точки зрения разработки программного обеспечения) и хотите сделать некоторыеЗахватывающее приложение, поэтому я надеюсь пойти в направлении машинного обучения, хотя у меня есть некоторые поверхностные знания в колледже, но если вы хотите развивать машинное обучение как карьеру, до этого еще далеко, поэтому я начал писать эту серию статей.
Я надеюсь, что с помощью этой серии я смогу обобщить знания в области машинного обучения, поэтому в этой части машинного обучения моя цель — написатьстаршеклассники понимают.
предисловие
Продолжение предыдущей главыRe: Машинное обучение с нуля — Машинное обучение (1) Линейная регрессия, я буду продолжать следовать линии Стэнфорда, в этой главе речь пойдет о логистической регрессии.
Классификация
Подобно регрессии,КлассификацияПроблема (классификации) также является важной частью машинного обучения.
Проблема классификации — очень важная часть машинного обучения, цель которой — определить, к какому известному классу образцов принадлежит новый образец на основе определенных характеристик известных образцов.
На самом деле, есть много распространенных примеров, таких как оценка того, является ли электронное письмо спамом, прогнозирование заинтересованности пользователя в моих продуктах и классификация изображений при обработке изображений.
Проблемы классификации варьируются от простой бинарной классификации до множественной классификации.текст
Этот блог в основном ологистическая регрессия(Логистическая регрессия).
Логистическая регрессия LR (логистическая регрессия)
Когда вы видите название, вам может быть немного странно, почему оно явно называется логистической «регрессией», но используется в задачах классификации. Хотя название, кажется, что-то указывает, логистическая регрессия на самом деле является алгоритмом классификации. Я предполагаю, что он назван так, потому что он похож на линейную регрессию в своем методе обучения, но функции потерь и градиента выражаются по-разному. В частности, логистическая регрессия использует сигмовидную функцию вместо непрерывного вывода линейной регрессии. Мы узнаем больше, когда будем углубляться в реализацию.
Прежде всего, давайте отложим логистическую регрессию в сторону. Мы также сказали, что логистическая регрессия используется для решения задач классификации. Для задач классификации мы на самом деле надеемся получитьКлассификатор(Классификатор), когда данные вводятся, этот классификатор может предсказать, что данные принадлежат определенному классувероятность, то есть нам нуженвероятность.
Линейная регрессия, которую мы представили в предыдущем разделе, выводит прогнозируемое значение, котороеГипотетическая функция(Функция гипотезы) То есть функция, которая выводит предсказанное значение, выглядит так.
Логистическая регрессия предсказывает классвероятность, поэтому давайте предположим, что функция следующая Смысл этой функции в том,Вероятность вывода y=1, когда вход x, на самом деле вероятность чего-то в задаче бинарной классификации. Теперь у читателей могут возникнуть вопросы об этой функции, например, почему именно эта функция, о чем будет сказано позже.появился здесьУсловная возможность, на самом деле относится к вероятности возникновения события A при условии, что другое событие B уже произошло. Учащиеся старших классов могут составить эту часть или нет на данный момент
Мы называем эту функцию g(z) сигмовидной функцией, и очевидно, что областью действия этой функции является открытый интервал от 0 до 1. Далее мы подробно рассмотрим эту функцию.
Sigmoid
Функциональное выражение сигмовидной функции выглядит следующим образом
Почему сигмоид (факультативный)
Логистическая регрессия выбрала Sigmoid как по внутренним, так и по внешним причинам.Ууху. Call.com/question/35…
Сам сигмоид имеет очень хорошие характеристики
- Сигмовидная функция непрерывна и монотонно возрастает
- Сигмиодальная функция симметрична относительно (0, 0,5) центроидов.
- Вывод сигмовидной функции
Функция потери
Мы также говорили в предыдущем разделе, что для корректировки параметра Θ нам нужны средства для измерения того, насколько хорош текущий параметр Θ.функция потерь(Функция потерь) используется для измерения точности функции гипотезы (функция гипотезы).
Для логистической регрессии мы надеемся, что когда прогнозируемая вероятность близка к реальной ситуации (0 или 1), ошибка будет наименьшей, и мы не хотим, чтобы кривая была прямой линией, но чем меньше изменение для чем ближе к месту, и чем дальше, функционируют с большими вариациями.
Ниже представлена функция потерь для логистической регрессии.
Мы можем комбинировать функции.В конце концов, такая кусочная функция не очень удобна в обращении.На самом деле она похожа на рисунок ниже, который также легко понять.Ведь двухкатегориальные обучающие данные y имеют только два значения 0 и 1.
Это позволяет вычислить погрешность результата, полученного по текущему параметру Θ в обучающей выборке.
векторизованное программирование
На самом деле мы уже использовали векторизованное программирование в реальном бою в предыдущем разделе.
# 计算损失,用了矢量化编程而不是for循环
def computeLoss(X, y, theta):
inner = np.power(((X * theta.T) - y), 2)
return np.sum(inner) / (2 * len(X))
Векторизованное программирование — эффективный способ увеличить скорость алгоритмов. Исследователи численных и параллельных вычислений десятилетиями работали над повышением скорости некоторых числовых операций, таких как умножение матриц, сложение матриц, умножение матрицы на вектор и т. д. Идея векторного программирования состоит в том, чтобы максимально использовать эти высокооптимизированные числовые операции для реализации нашего алгоритма обучения.
Другими словами, старайтесь максимально избегать использования циклов for, ведь сценарий матричного умножения очень подходит для параллельных вычислений, а прирост производительности очень очевиден перед лицом огромных объемов данных.
Если функция потерь только что представлена идеей векторизованного программирования
Если я не понимаю это какое-то время, позвольте мне сначала объяснить.Давайте предположим, что всего m данных, и в этой модели есть n переменных. Тогда матрица h представляет собой матрицу (m, n) X (n, 1), которая является матрицей (m, 1), а значение матрицы h представляет собой прогнозируемое значение m данных.Транспонирование y в функции потерь равно (1, м). После умножения получается (1, 1), что является значением. Смысл умножения этих двух матриц таков:Соответствующее прогнозируемое значениеУмножить на логарифмСоответствующее фактическое значение, и добавьте их вместе в конце.
(m,n) представляет собой матрицу размером m строк и n столбцов.Если вы изучали умножение матриц, то должны знать, что матрица, полученная путем умножения матриц (m, n) X (n, k), равна (m, k )
вогнутая функция
Градиентный спуск для логистической регрессии
Что касается метода градиентного спуска, я уже сделал более подробное описание в предыдущем разделе, если вы его забудете, вы можете вернуться и поискать его. Мы только что узнали, как оценить текущий параметр Θ, теперь нам нужно использовать градиентный спуск для настройки параметров.
Это по-прежнему частная производная функции потерь, не забывайте, что α — это значение скорости обучения. Векторное представлениеПроцесс решения частной производной функции потерь (необязательно)
проблема переобучения
Для обучающего набора данных, визуализированного, как показано ниже.
У нас есть разные названия для трех случаев границ, проведенных тремя разными классификаторами.Первый, классификация очень неточная, мы называем этот виднедооснащение(underfitting)Во-вторых, классификация в самый раз, специального названия для этого вида нет.
В-третьих, классификация слишком хорошо согласуется с обучающими данными. это мы называемпереоснащение(overfitting)
Проблема, вызванная переобучением, также очевидна. Она слишком подходит для обучающей выборки. Для нас нужна вторая кривая. Результат переобучения слишком подходит для обучающих данных. Неожиданно низкий.
Существует два основных способа решения проблемы переобучения.
уменьшить количество функций, это легко понять, больше функций означает, что разделенная кривая функции может быть более сложной. Это может быть продлено на более поздний срокразработка функций(Feature Engineering)
Использовать регуляризатор, сохраните все признаки, но гарантируйте, что параметр θj не станет огромным. Условия регуляризации хороши, когда у нас есть много полезных функций.
Регулятор
срок регуляризациина самом деле называетсяштрафной пункт(член наказания), его функция состоит в том, чтобы замедлить задачу переобучения. Фактически, это добавить член, содержащий каждый Θ после функции потерь. Цель этого состоит в том, чтобы позволить Θ также участвовать в вычислении функции потерь, так что, поскольку нам нужно запросить потерю минимального значения функции, этот термин будет ограничивать размер Θ.
Целью этого проекта регуляризации на самом деле являетсякомпромисс, мы надеемся, что параметр Θ может работать лучше на обучающем наборе данных, и мы не хотим, чтобы параметр Θ имел очень большое значение, обученное для получения каких-то странных кривых деления, как показано на рисунке ниже.
упражняться
В этой статье мы меняем цель с прогнозирования непрерывнозначныхпроблема регрессииПерейти к классификации результатовпроблема классификации.
данные доступны в моемРепозиторий GitHubСкачать в.
окрестности
Если вы не хотите, чтобы вас раздражала среда настройки, я действительно рекомендую установитьAnaconda
, в дополнение скажу, что я использую Python3.x.
задний план
Реальная борьба с этой статьей в основном использует логистическую регрессию, чтобы помочь приемным комиссиям проверять абитуриентов. Предположим, вы хотите предсказать, будет ли принят каждый абитуриент на основе результатов двух экзаменов. У вас есть исторические данные о предыдущих абитуриентах, включая баллы по обоим экзаменам и информацию о том, были ли они приняты в конце. С этой целью мы будем использовать логистическую регрессию для построения модели классификации на основе результатов тестов для оценки вероятности поступления.
код и комментарии
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 读入训练数据
# windows用户路径可能需要修改下,后期有时间可能会做统一
def loadData(path):
trainingData = pd.read_csv(path, header=None, names=['Exam 1', 'Exam 2', 'Admitted'])
trainingData.head()
trainingData.describe()
positive = trainingData[trainingData['Admitted'].isin([1])]
negative = trainingData[trainingData['Admitted'].isin([0])]
fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted')
ax.legend()
ax.set_xlabel('Exam 1 Score')
ax.set_ylabel('Exam 2 Score')
# plt.show()
return trainingData
# 计算损失,用了矢量化编程而不是for循环,公式在博客中有详细描述和证明。
def computeLoss(X, y, theta):
theta = np.copy(theta)
X = np.copy(X)
y = np.copy(y)
m = X.shape[0]
h = sigmoid(np.matmul(X, theta.T))
first = np.matmul(-(y.T), np.log(h))
second = np.matmul((1 - y).T, np.log(1 - h))
return np.sum(first - second) / m
# 梯度下降部分
def gradientDescent(X, y, theta, alpha, iters):
m = X.shape[0] # 数据项数m
temp = np.matrix(np.zeros(theta.shape))
# parameters = 1
cost = np.zeros(iters)
for i in range(iters):
error = sigmoid(np.matmul(X, theta.T)) - y
theta = theta - ((alpha/m) * np.matmul(X.T, error)).T
cost[i] = computeLoss(X, y, theta)
return theta, cost
def predict(theta, X):
probability = sigmoid(np.matmul(X, theta.T))
return [1 if x >= 0.5 else 0 for x in probability]
trainingData = loadData(os.getcwd() + '/../../data/ex2data1.txt')
# 插入常数项
trainingData.insert(0, 'Ones', 1)
cols = trainingData.shape[1]
X = trainingData.iloc[:,0:cols-1]
y = trainingData.iloc[:,cols-1:cols]
# 初始化X、Y以及theta矩阵
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.zeros(3))
# 计算训练前的损失值
computeLoss(X, y, theta)
# 使用梯度下降得到模型参数
alpha = 0.001
iters = 20000
theta_fin, loss = gradientDescent(X, y, theta, alpha, iters)
# 计算训练后的参数的损失值 (不优化)
computeLoss(X, y, theta_fin) #
# 损失随着迭代次数的变化 (不优化)
# fig, ax = plt.subplots(figsize=(12,8))
# ax.plot(np.arange(iters), loss, 'r')
# ax.set_xlabel('Iterations')
# ax.set_ylabel('Cost')
# ax.set_title('Error vs. Training Epoch')
# plt.show()
# 不理解为什么不优化的会这么低,是学习速率没动态变化么?
predictions = predict(theta_fin, X)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
print('accuracy 1 = {0}%'.format(accuracy)) # 60%
# 使用scipy的optimize来做优化
import scipy.optimize as opt
# 换了下参数位置让其符合fmin_tnc
def gradient(theta, X, y):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
parameters = int(theta.ravel().shape[1])
grad = np.zeros(parameters)
error = sigmoid(X * theta.T) - y
for i in range(parameters):
term = np.multiply(error, X[:,i])
grad[i] = np.sum(term) / len(X)
return grad
# 换了下参数位置让其符合fmin_tnc
def computeLoss2(theta, X, y):
theta = np.copy(theta)
X = np.copy(X)
y = np.copy(y)
m = X.shape[0]
h = sigmoid(np.matmul(X, theta.T))
first = np.matmul(-(y.T), np.log(h))
second = np.matmul((1 - y).T, np.log(1 - h))
return np.sum(first - second) / m
result = opt.fmin_tnc(func=computeLoss2, x0=theta, fprime=gradient, args=(X, y))
predictions = predict(np.matrix(result[0]), X)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
print('accuracy 2 = {0}%'.format(accuracy)) # 89%
Объяснение на самом деле относительно ясно в комментариях, поэтому я не буду вдаваться в подробности.
результат
сомневаться
В коде используются два метода: один — обновить тета-значение с помощью ручного градиентного спуска, как в предыдущей главе, а другой — использовать метод оптимизации scipy fmin_tnc. Окончательная точность сильно отличается, и я не знаю, почему.
Автор этой статьи - Лян Ван (lwio, lwyj123)
основная ссылкаСтэнфордский курс машинного обучения johnwittenauer