Линейный регрессионный анализ с помощью scikit-learn

Python машинное обучение

Будет серия статей, объясняющих библиотеку машинного обучения Python: scikit-learn. Это первая статья, в которой мы познакомим вас с некоторыми основными понятиями и объясним, как использовать scikit-learn для выполнения линейного регрессионного анализа.

Введение в scikit-learn

scikit-learn — это программная библиотека машинного обучения для языка Python. Официальный адрес сайта здесь:scikit-learn.

scikit-learn имеет следующие особенности:

  • Он содержит простые и эффективные инструменты интеллектуального анализа и анализа данных.
  • Доступно для всех и в различных средах
  • На основе NumPy, SciPy и matplotlib
  • На основе BSD с открытым исходным кодом, поэтому как проекты с открытым исходным кодом, так и коммерческие проекты могут использовать

При программировании с помощью scikit-learn мы часто используем NumPy, pandas и 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 атрибутамиx = (x_{1};x_{2};…;x_{n})x_{i}является значением i-го атрибута.

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

Если мы используем векторx = (x_{1};x_{2};…;x_{n})а такжеw = (w_{1};w_{2};…;w_{n})Вместо этого указанную выше функцию можно записать так:

Цель обучения состоит в том, чтобы определить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, связанный с предсказанием классификации.

Быть в курсе.

Ссылки и рекомендуемая литература