Будет серия статей, объясняющих библиотеку машинного обучения Python: scikit-learn. Это первая статья, в которой мы познакомим вас с некоторыми основными понятиями и объясним, как использовать scikit-learn для выполнения линейного регрессионного анализа.
Введение в scikit-learn
scikit-learn — это программная библиотека машинного обучения для языка Python. Официальный адрес сайта здесь:scikit-learn.
scikit-learn имеет следующие особенности:
- Он содержит простые и эффективные инструменты интеллектуального анализа и анализа данных.
- Доступно для всех и в различных средах
- На основе NumPy, SciPy и matplotlib
- На основе BSD с открытым исходным кодом, поэтому как проекты с открытым исходным кодом, так и коммерческие проекты могут использовать
При программировании с помощью scikit-learn мы часто используем NumPy, pandas и matplotlib, поэтому читателям рекомендуется иметь некоторое представление об этих библиотеках. Я также написал несколько статей по теме:
- Учебник NumPy по библиотеке машинного обучения Python
- Вводное руководство по библиотеке обработки данных Python pandas
- Расширенное руководство по библиотеке обработки данных Python для панд
- Начало работы с библиотекой графиков Python Matplotlib
Введение в машинное обучение
Как правило, машинное обучение включает в себя сбор выборочных данных. Цель обучения состоит в том, чтобы предсказывать неизвестные данные путем анализа известных данных.
Если каждая выборка содержит более одного числа, говорят, что данные имеют несколько атрибутов или характеристик.
Проблемы обучения можно классифицировать следующим образом:
-
контролируемое обучение(Контролируемое обучение): данные содержат дополнительные свойства, которые мы будем прогнозировать. Обучение с учителем можно разделить на:
- Классификация(Классификация): Образцы принадлежат к двум или более классам, и мы хотим узнать на основе размеченных данных, как предсказать класс неразмеченных данных. Примером задачи классификации является распознавание рукописных цифр, где цель состоит в том, чтобы присвоить каждому входному вектору один из конечного числа дискретных классов.
- вернуть(Регрессия): если прогнозируемый результат состоит из одной или нескольких непрерывных переменных, задача называется регрессией. Примером проблемы регрессии является прогнозирование длины животного по отношению к возрасту и весу.
- неконтролируемое обучение(Обучение без учителя): где обучающие данные состоят из набора входных векторов x без каких-либо соответствующих целевых значений. Цель этих задач может заключаться в обнаружении наборов подобных примеров в данных, что называется кластеризацией, или в определении распределения данных во входном пространстве, что называется оценкой плотности, или в проецировании данных из больших измерений для уменьшения пространство в 2D или 3D.
лабораторная среда
Код в этой статье тестируется в следующей среде:
- Apple OS X 10.13
- Python 3.6.3
- scikit-learn 0.19.1
- matplotlib 2.1.1
- numpy 1.13.3
Исходный код и тестовые данные для этой статьи можно найти здесь:sklearn_tutorial
Описание эксперимента
В этой статье мы будем делать прогнозы цен на жилье.
Используемые данные представляют собой набор файлов CSV, содержащих несколько сведений о ценах на жилье. Этот файл можно получить здесь:housing.csv.
Примечание:sklearn_tutorialЭтот файл данных также включен в исходный код проекта.
Мы можем прочитать этот файл с помощью следующего кода:
import pandas as pd
input_data = pd.read_csv("./housing.csv")
Примечание. В этой статье предполагается, что читатель имеет базовое представление о трех библиотеках NumPy, pandas и matplotlib.
понимать данные
Прежде чем мы получим данные, у нас обычно есть некоторое общее представление о данных.
Например это:
print("Describe Data:")
print(input_data.describe())
print("\nFirst 10 rows:")
print(input_data.head(10))
describe()
— это API, предоставляемый pandas, который выводит информацию о статистическом описании данных в целом, например следующее:
Describe Data:
longitude latitude housing_median_age total_rooms \
count 20640.000000 20640.000000 20640.000000 20640.000000
mean -119.569704 35.631861 28.639486 2635.763081
std 2.003532 2.135952 12.585558 2181.615252
min -124.350000 32.540000 1.000000 2.000000
25% -121.800000 33.930000 18.000000 1447.750000
50% -118.490000 34.260000 29.000000 2127.000000
75% -118.010000 37.710000 37.000000 3148.000000
max -114.310000 41.950000 52.000000 39320.000000
total_bedrooms population households median_income \
count 20433.000000 20640.000000 20640.000000 20640.000000
mean 537.870553 1425.476744 499.539680 3.870671
std 421.385070 1132.462122 382.329753 1.899822
min 1.000000 3.000000 1.000000 0.499900
25% 296.000000 787.000000 280.000000 2.563400
50% 435.000000 1166.000000 409.000000 3.534800
75% 647.000000 1725.000000 605.000000 4.743250
max 6445.000000 35682.000000 6082.000000 15.000100
median_house_value
count 20640.000000
mean 206855.816909
std 115395.615874
min 14999.000000
25% 119600.000000
50% 179700.000000
75% 264725.000000
max 500001.000000
а такжеinput_data.head(10)
Выводятся первые 10 строк данных.
First 10 rows:
longitude latitude housing_median_age total_rooms total_bedrooms \
0 -122.23 37.88 41.0 880.0 129.0
1 -122.22 37.86 21.0 7099.0 1106.0
2 -122.24 37.85 52.0 1467.0 190.0
3 -122.25 37.85 52.0 1274.0 235.0
4 -122.25 37.85 52.0 1627.0 280.0
5 -122.25 37.85 52.0 919.0 213.0
6 -122.25 37.84 52.0 2535.0 489.0
7 -122.25 37.84 52.0 3104.0 687.0
8 -122.26 37.84 42.0 2555.0 665.0
9 -122.25 37.84 52.0 3549.0 707.0
population households median_income median_house_value ocean_proximity
0 322.0 126.0 8.3252 452600.0 NEAR BAY
1 2401.0 1138.0 8.3014 358500.0 NEAR BAY
2 496.0 177.0 7.2574 352100.0 NEAR BAY
3 558.0 219.0 5.6431 341300.0 NEAR BAY
4 565.0 259.0 3.8462 342200.0 NEAR BAY
5 413.0 193.0 4.0368 269700.0 NEAR BAY
6 1094.0 514.0 3.6591 299200.0 NEAR BAY
7 1157.0 647.0 3.1200 241400.0 NEAR BAY
8 1206.0 595.0 2.0804 226700.0 NEAR BAY
9 1551.0 714.0 3.6912 261100.0 NEAR BAY
Из приведенного выше вывода мы знаем немного о данных:
- Этот набор данных содержит в общей сложности 20640 фрагментов данных..
- Данные делятся на долготу, широту, медианный_возраст жилья, общее количество комнат, общее количество спален, население, домохозяйства, медианный_доход, медианное_значение_дома, близость к океану.всего 10 столбцов.
- В некоторых данных отсутствует информация из столбца total_bedrooms., поэтому его общее количество действительных данных составляет всего 20433.
- Данные ocean_proximity имеют строковый тип., в то время как другие столбцы имеют числовой тип
- median_house_value представляет стоимость дома, котораяданные, которые мы хотим предсказать
Мы также можем отобразить результаты визуализации с помощью matplotlib.
Например это:
input_data.hist(bins=100, figsize=(20, 12))
plt.show()
Здесь на основе данных создается гистограмма, как показано ниже. Из этого графика мы можем видеть частоту появления данных.
или это:
input_data.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)
plt.show()
Здесь точки хеширования будут генерироваться в соответствии с широтой и долготой, и мы устанавливаем прозрачность на 0,1, чтобы мы могли видеть, насколько плотны данные в местоположении адреса.
предварительная обработка
На самом деле данные, которые мы можем получить, несовершенны и обычно содержат некоторые недопустимые значения или отсутствующие значения. В приведенных выше данных это именно так.
Прежде чем приступить к анализу данных, первый шаг, который мы должны сделать, — это предварительно обработать данные.
подогнать и трансформировать
scikit-learn предоставляет серию Transformers. Они используются для очистки, уменьшения, расширения и создания представлений функций. Эти классы будут иметь следующие три метода:
-
fit
Метод: этот метод изучает параметры модели (например, среднее значение и стандартное отклонение для нормализации) из обучающего набора. -
transform
Метод: этот метод выполняет преобразование модели данных. -
fit_transform
Метод: это комбинация двух предыдущих методов, которая более удобна и эффективна.
sklearn.preprocessingСодержит ряд инструментов для предварительной обработки данных.
Далее мы будем использовать эти API для предварительной обработки приведенной выше информации о цене дома.
обрабатывать строки
Данные содержат строки, которые не удобны для нашего анализа, поэтому нам сначала нужно преобразовать строковые данные в числовые данные.
мы можем использоватьLabelEncoder
Выполните этот процесс:
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
data["ocean_proximity"] = encoder.fit_transform(data["ocean_proximity"])
Этот столбец данных будет преобразован из строки в целое число и, наконец, преобразован в данные, такие как [0, 1, 2, 3...].
мы можем пройтиdescribe()
Взгляните на результат преобразования этого столбца данных:
ocean_proximity
count 20640.000000
mean 1.165843
std 1.420662
min 0.000000
25% 0.000000
50% 1.000000
75% 1.000000
max 4.000000
Обработка недопустимых значений
Ранее мы видели, что в столбце total_bedrooms есть неверные данные, а всего допустимых данных всего 20433.
Ячейки, содержащие недопустимые данные, можно либо отбросить, либо заполнить потенциально допустимыми значениями.
sklearn.preprocessing.ImputerОн используется для заполнения значений. Он предлагает следующие три стратегии:
- «mean»: заполните средним значением допустимых значений.
- «медиана»: заполнить медианой допустимых значений
- «most_frequent»: заполните наиболее частым значением допустимых значений.
Первая и третья стратегии всем хорошо понятны, но некоторые люди могут быть не знакомы с медианой.
Медиана — это собственный термин в статистике, который представляет значение в выборке, совокупности или распределении вероятностей, которое делит набор значений на равные верхнюю и нижнюю части.
Вот пример кода для получения среднего значения и медианы с использованием numpy:
import numpy as np
data = [1, 2, 3, 4, 5, 6, 7, 8, 95, 96, 97, 98, 100]
print("mean: {}".format(np.mean(data)))
print("median: {}".format(np.median(data)))
Как видно из вывода, среднее значение этих данных равно40.153
, а медиана7
.
Мы можем использовать следующий код для заполнения значений, которые изначально содержали недопустимые данные Тест для заполнения заключается в использовании медианы.
from sklearn.preprocessing import Imputer
imputer = Imputer(strategy="median")
X = imputer.fit_transform(data)
input_data = pd.DataFrame(X, columns=data.columns)
После завершения обработки мы можем просмотреть обработанные данные для подтверждения:
total_bedrooms
count 20640.000000
mean 536.838857
std 419.391878
min 1.000000
25% 297.000000
50% 435.000000
75% 643.250000
max 6445.000000
Масштабирование функций
Значения входных данных могут быть в различных диапазонах. Например, максимальное значение median_house_value равно 500001. А Housing_median_age можно описать двумя цифрами.
В некоторых случаях некоторые данные могут иметь очень большие значения. А при вычислениях легко переполниться. В этом случае мы обычно масштабируем данные. Например, для данных [100, 10000] мы масштабируем до [1, 100]. В случае сохранения пропорции данных это не влияет на результаты обработки данных.
MinMaxScaler
Используется для масштабирования данных путем указания диапазона данных. Например:
scalar = MinMaxScaler(feature_range=(0, 100), copy=False)
scalar.fit_transform(data)
Все данные будут масштабироваться в диапазоне [0, 100].
Мы можем показать, что данные до и после обработки сравнивались через интерфейс matplotlib:
plt.subplot(2, 1, 1)
plt.scatter(x=origin["longitude"], y=origin["latitude"],
c=origin["median_house_value"], cmap="viridis", alpha=0.1)
plt.subplot(2, 1, 2)
plt.scatter(x=scaled["longitude"], y=scaled["latitude"],
c=origin["median_house_value"], cmap="viridis", alpha=0.1)
plt.show()
Как видно из этой картинки, здесь мы просто корректируем масштаб значений и никак не влияем на распределение данных.
раздел данных
Чтобы получить прогностическую модель, нам нужно разделить полученные данные наОбучающий набора такжетестовый набордве части.
Первый используется для обучения модели данных, а второй — для тестирования и проверки модели. Обычно мы используем большую часть данных для обучения и небольшую часть данных для тестирования.
При разделении данных мы должны быть максимально «случайными». То есть и обучающая выборка, и тестовая выборка могут максимально отражать реальную модель данных.
permutation
permutation
это интерфейс, предоставляемый numpy. Он перемешивает целые числа в указанном диапазоне для генерации случайных чисел. Вот пример кода:
import numpy as np
data = np.arange(0, 100)
np.random.seed(59)
print(data[np.random.permutation(100)[90:]])
Здесь мы перемешиваем 100 случайных чисел в диапазоне [0, 100). пройти перед схваткойnp.random.seed(59)
Начальное значение случайного числа устанавливается для обеспечения стабильности сгенерированного случайного числа.
Наконец, мы распечатываем последние 10 перетасованных данных:
[64 67 0 57 53 79 23 77 44 49]
С этими зашифрованными целыми числами мы можем использовать их в качестве индекса для удаления обучающих и тестовых наборов из существующего набора данных. Например: [0, 90] в качестве тренировочного набора, [90:] в качестве тестового набора.
train_test_split
sklearn также предоставляет аналогичную функциональность. Эта функцияtrain_test_split
. Пример кода выглядит следующим образом:
import numpy as np
from sklearn.model_selection import train_test_split
data = np.arange(0, 100)
train_set, test_set = train_test_split(data, test_size=0.1, random_state=59)
print("test_set: \n {} \n".format(test_set))
здесьtest_size
указывает долю тестового набора,random_state
Указывает начальное число для случайного числа.
Эта функция вернетtrain_set
а такжеtest_set
два набора. На первое приходится 90% данных, на второе — 10%. Распечатываем результаты данных для тестового набора:
test_set:
[38 46 24 87 30 85 16 96 18 99]
Что касается данных о ценах на жилье, мы можем разделить их на две части: обучающий набор и тестовый набор:
train_set, test_set = train_test_split(input_data,
test_size=0.1, random_state=59)
show_data_summary(test_set)
Последняя строка выводит данные тестового набора, мы можем наблюдать, соответствуют ли результаты нашим ожиданиям:
Describe Data:
longitude latitude housing_median_age total_rooms \
count 2064.000000 2064.000000 2064.000000 2064.000000
mean 48.415061 32.276916 53.952918 6.692606
std 19.640685 22.608316 24.649983 5.817431
min 0.896414 0.000000 1.960784 0.022890
25% 27.863546 14.665250 33.333333 3.638919
50% 58.764940 17.959617 54.901961 5.348695
75% 63.346614 54.835282 70.588235 7.932118
max 96.613546 98.618491 100.000000 82.977262
total_bedrooms population households median_income \
count 2064.000000 2064.000000 2064.000000 2064.000000
mean 8.309936 4.013810 8.192199 22.725069
std 6.794665 3.581933 6.626166 12.800111
min 0.062073 0.028028 0.049334 0.000000
25% 4.527467 2.149724 4.534616 13.727052
50% 6.719429 3.188150 6.610755 20.242479
75% 9.970515 4.904846 9.965466 28.686501
max 100.000000 80.055495 100.000000 100.000000
median_house_value ocean_proximity
count 2064.000000 2064.000000
mean 38.343739 28.234012
std 23.628904 34.874180
min 1.546592 0.000000
25% 20.350638 0.000000
50% 32.412444 25.000000
75% 49.432992 25.000000
max 100.000000 100.000000
First 10 rows:
longitude latitude housing_median_age total_rooms total_bedrooms \
9878 24.800797 43.464400 70.588235 0.854570 1.675978
4356 59.661355 16.471838 72.549020 5.483494 9.016139
1434 23.107570 57.810840 84.313725 3.184292 3.895096
6422 63.247012 16.896918 45.098039 6.566967 8.054004
1624 22.011952 56.323061 45.098039 5.414823 5.307263
1423 22.908367 58.023379 29.411765 2.754464 3.351955
4853 60.258964 15.834219 70.588235 7.068010 11.871508
16893 19.621514 53.560043 100.000000 4.328806 3.491620
4232 60.258964 16.578108 70.588235 13.487461 30.710739
19083 18.625498 61.424017 80.392157 5.351239 8.255742
population households median_income median_house_value \
9878 0.639031 1.628022 14.009462 19.237240
4356 2.965330 9.472126 16.995628 70.164865
1434 1.387371 3.552047 20.366616 27.608340
6422 5.229967 8.255221 19.201114 31.340283
1624 2.441212 6.117415 35.413305 70.226721
1423 0.989378 3.798717 12.732928 12.371289
4853 7.239553 11.971715 9.355043 35.567070
16893 1.872250 3.979609 54.968207 100.000000
4232 10.908377 30.800855 10.808816 55.319566
19083 3.189551 7.301431 18.020441 27.690814
ocean_proximity
9878 0.0
4356 0.0
1434 75.0
6422 25.0
1624 75.0
1423 75.0
4853 0.0
16893 100.0
4232 0.0
19083 0.0
....
Линейная модель
Мы можем начать с набора данных, который содержит только одно значение атрибута, чтобы помочь нам понять линейные модели.
Теперь предположим, что мы хотим предсказать цену за единицу дома в данном районе. При прочих равных условиях мы предполагаем, что цены на жилье связаны только с возрастом.
Предположим, что ниже представлены существующие данные о ценах на жилье:
- 1999, 3800
- 2000, 3900
- 2001, 4000
- 2002, 4200
- 2003, 4500
- 2004, 5500
- 2005, 6500
- 2006, 7000
- 2007, 8000
- 2008, 8200
- 2009, 10000
- 2010, 14000
- 2011, 13850
- 2012, 13000
- 2013, 16000
- 2014, 18500
Мы можем отобразить эти данные через matplotlib:
# house_price.py
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data = pd.DataFrame({
"Year": [1999,2000,2001,2002,2003,2004,2005,2006,
2007,2008,2009,2010,2011,2012,2013,2014],
"Price": [3800,3900,4000,4200,4500,5500,6500,7000,
8000,8200,10000,14000,13850,13000,16000,18500]})
data.plot(kind="scatter", x="Year", y="Price", c="B", s=100)
plt.show()
Результат, полученный этим кодом, выглядит следующим образом:
И если мы хотим спрогнозировать цену дома в 2015 году и позже, нам нужно сделать следующее: найти линию, чтобы все существующие точки были как можно ближе к этой линии, в соответствии с трендом этой линии, мы может предсказать будущие цены на жилье. Например, все три строки ниже можно использовать как альтернативу.
Мы знаем, что уравнение прямой имеет вид:
И нам просто нужно быть увереннымw
а такжеb
, линия определена.
На самом деле, есть много факторов, которые определяют цены на жилье. Гораздо больше, чем возрастной фактор. В реальных проектах могут быть даже тысячи атрибутов данных. Поэтому нам нужно расширить приведенную выше модель на несколько свойств.
заданные данные описываются n атрибутами,вявляется значением i-го атрибута.
Линейные модели пытаются изучить функцию, которая делает прогнозы на основе линейной комбинации свойств, а именно:
Если мы используем вектора такжеВместо этого указанную выше функцию можно записать так:
Цель обучения состоит в том, чтобы определитьw
(вектор) иb
, так что модель может быть определена.
Возвращаясь к этому конкретному примеру, каждый фрагмент данных содержит десять значений, гдеmedian_house_value
результат, который мы хотим предсказать. Остальные 9 являются характеристиками данных. Наша цель состоит в том, чтобы найти модель, которая может предсказывать остальные 9 атрибутов.median_house_value
значение .
Напишите алгоритм определенияw
(вектор) иb
значение — непростая задача. К счастью, scikit-learn уже содержит соответствующий алгоритм, который поможет нам выполнить эту работу, нам просто нужно использовать его напрямую.
Во-первых, мы определяем функцию для отделения целевого значения, которое необходимо предсказать, от других 9 атрибутов:
def split_house_value(data):
value = data["median_house_value"].copy()
return data.drop(["median_house_value"], axis=1), value
Затем мы используем эту функцию для разделения обучающих и тестовых данных:
train_set, test_set = train_test_split(input_data,
test_size=0.1, random_state=59)
train_data, train_value = split_house_value(train_set)
test_data, test_value = split_house_value(test_set)
На следующем шаге мы можем обучить модель с помощью обучающего набора:
from sklearn.linear_model import LinearRegression
linear_reg = LinearRegression()
linear_reg.fit(train_data, train_value)
Да, обучение выполняется всего в трех строчках кода. С обученной моделью мы можем использовать ее для прогнозирования данных. Для этого также требуется только одна строка кода:
predict_value = linear_reg.predict(test_data)
Наконец, мы можем сравнить прогнозируемые результаты с фактическими результатами. Чтобы подтвердить, что наши прогнозы верны:
def show_predict_result(test_data, test_value, predict_value):
ax = plt.subplot(221)
plt.scatter(x=test_data["longitude"], y=test_data["latitude"],
s=test_value, c="dodgerblue", alpha=0.5)
plt.subplot(222)
plt.hist(test_value, color="dodgerblue")
plt.subplot(223)
plt.scatter(x=test_data["longitude"], y=test_data["latitude"],
s=predict_value, c="lightseagreen", alpha=0.5)
plt.subplot(224)
plt.hist(predict_value, color="lightseagreen")
plt.show()
В этой функции мы рисуем диаграмму рассеяния и гистограмму для фактических и прогнозируемых результатов. Фактический результат — синий, прогнозируемый — зеленый. Точки на точечной диаграмме представляют величину значения, а гистограмма показывает частоту значения.
Результат показан ниже:
показатели эффективности
Только что мы графически сравнили предсказанные и реальные результаты. Этот метод можно использовать только как вспомогательное средство в тренировочном процессе. Потому что этот результат должен быть «просмотрен» людьми, и результатом нашей оценки является очень субъективное суждение, такое как «хорошо» и «относительно плохо». Конечно, в реальных производственных или экспериментальных условиях необходимы более точные методы измерения.
среднеквадратическая ошибка
Наиболее часто используемые показатели производительности для задач регрессии:среднеквадратическая ошибка(среднеквадратичная ошибка, называемая MSE), метод ее расчета следующий:
Этот алгоритм вычитает прогнозируемое значение из фактического значения, возводит его в квадрат, а затем усредняет все возведенные в квадрат результаты.
С scikit-learn нам не нужно самим реализовывать этот алгоритм, мы просто вызываемmean_squared_error
Функция может быть:
from sklearn.metrics import mean_squared_error
mse = mean_squared_error(test_value, predict_value)
print("Diff: {}".format(np.sqrt(mse)))
Первый аргумент этой функции — фактический результат, а второй — прогнозируемый результат. Результат, полученный после возведения полученного значения в квадрат:
Diff: 14.127834130789983
Таким образом, мы знаем точный результат модели: ошибка предсказания в интервале между [0, 100] составляет около 14.
Перекрестная проверка
Алгоритмы перекрестной проверки также доступны в scikit-learn.
Этот алгоритм случайным образом делит обучающую выборку на n частей (называемых складками), а затем каждый раз выбирает одну из них в качестве результата, а остальные n-1 в качестве обучающей. Используйте это, чтобы вычислить оценку алгоритма. Таким образом, этот алгоритм в конечном итоге вернет n результатов. Каждый результат представляет собой оценку числового типа.
Пример кода выглядит следующим образом:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(linear_reg, train_data, train_value, cv=10)
print("cross_val_score: {}".format(scores))
Результат выглядит следующим образом:
cross_val_score: [0.65629302 0.67609342 0.60996658 0.64629956 0.64577402 0.64565816
0.62451489 0.57967974 0.62916854 0.60401622]
Если у нас есть несколько моделей, мы можем легко сравнить две модели, сравнив оценки.
Примечание. Подробное описание этой функции см. здесь:cross_val_score
заключительные замечания
На этом наша первая статья о линейной регрессии подошла к концу.
В этой статье содержится много контента, и его переваривание может занять некоторое время.
В следующей статье мы рассмотрим scikit-learn, связанный с предсказанием классификации.
Быть в курсе.