ПОДРОБНОЕ РУКОВОДСТВО ПО ПАНДАМ

Учебное пособие PANDAS (от А до Я)

В библиотеке Pandas есть множество удивительных техник. Кроме того, если вы заинтересованы в изучении машинного обучения, предварительная обработка данных является ключевым этапом разработки модели. Этот этап также требует глубокого понимания библиотеки pandas, которая используется для предварительной обработки данных, поскольку хорошие данные приводят к более точной модели машинного обучения.

Добавьте эту страницу в свой список избранного (в закладки), чтобы ее можно было быстро найти. Когда вам нужно, просто прокрутите вниз до раздела Содержание.

Что такое панды?

Pandas — это широко используемая библиотека Python с открытым исходным кодом для обработки данных, анализа данных и машинного обучения. Это инструмент для манипулирования данными на высоком уровне. Он основан на Numpy, популярной библиотеке, поддерживающей многомерные массивы. DataFrames — это тип структуры данных, который позволяет хранить и изменять табличные данные в виде строк наблюдений и столбцов переменных. Данные можно преобразовывать в различные форматы данных и анализировать с помощью обширных встроенных функций библиотеки pandas.

Pandas, как один из самых популярных инструментов обработки данных, обычно включается в каждый дистрибутив Python, начиная с тех, которые поставляются с вашей операционной системой.

История:

Уэс МакКинни, разработчик AQR Capital Management, начал работать над пандами в 2008 году в ответ на потребность в высокопроизводительном универсальном инструменте для проведения количественных исследований финансовых данных. Он смог убедить руководство AQR разрешить ему открыть исходный код библиотеки перед отъездом. Чанг Ше, еще один сотрудник AQR, присоединился к инициативе в 2012 году в качестве второго крупного вкладчика библиотеки. Pandas присоединился к NumFOCUS в качестве проекта, финансируемого из бюджета, в 2015 году.

С Pandas, что мы можем сделать с DataFrames?

Позвольте мне рассказать вам о DataFrames в следующем разделе. Многие трудоемкие повторяющиеся процессы, связанные с работой с данными, упрощаются с помощью Pandas, в том числе:

Очистка данных

• Заполнение данных

• Нормализация данных

• Объединение и объединение

• Визуализация данных

• Статистический анализ

• Проверка данных

• Загрузка и сохранение данных

• И многое другое.

На самом деле, вы можете сделать все, что делает Pandas лучшим доступным инструментом анализа и обработки данных, по мнению всемирно известных специалистов по данным.

Хватит прелюдии; давайте перейдем к сути дела.

Содержание:

-› Первые шаги
- Установить Pandas
- Импортировать Pandas
- Версия Pandas
- Версии зависимостей

-› Серии в Pandas
- Ярлыки
- Создать ярлыки
- Сериализация объектов ключ/значение
- Генерация рядов данных
- Использование функции для каждого отдельного элемента в последовательности

-› DataFrames
Читать файл CSV, Excel или JSON в DataFrame
Словарь как JSON
Преобразование 2D-списка в DataFrame
- Чтение данных и присвоение имен столбцам, как указано с любым разделителем

-› Анализ DataFrames
Просмотр данных
Именованные индексы
Найденные именованные индексы
Установка пользовательского индекса в DataFrame

-› Очистка данных
- Пустые ячейки
- Данные в неправильном формате
- Неверные данные
- Дубликаты

-› Корреляции данных
Идеальная корреляция
Хорошая корреляция
Плохая корреляция

-›ЗАКЛЮЧЕНИЕ

Первые ходы:

Установка Pandas.Pandas довольно просто установить, если на вашем компьютере уже установлены Python и PIP. Используйте следующую команду для его установки:

C:\Users\Your Name>pip install pandas

Если эта команда не работает, попробуйте Anaconda, Spyder или другой дистрибутив Python, в котором уже установлен Pandas.

Импорт Pandas. После установки Pandas импортируйте его в свои приложения, добавив ключевое слово import. Панды обычно импортируются под псевдонимом pd.

псевдоним. В Python псевдоним — это альтернативное имя для обозначения одного и того же объекта.

import pandas as pd

-›Проверка версии Pandas:

import pandas as pd
pd.__version__

->Проверьте зависимости версий:

pd.show_versions()

Серия в пандах:

Серия Pandas — это одномерный помеченный массив, который может содержать данные любого типа (целые числа, строки, числа с плавающей запятой, объекты Python и т. д.). На метки осей ссылаются как на индексы. Pandas Series — это просто столбец в электронной таблице Excel. Метки не обязательно должны быть уникальными, но они должны быть хешируемого типа. Объект поддерживает как целочисленное индексирование, так и индексирование на основе меток, а также предоставляет множество методов для выполнения операций с индексом.

a = [1, 7, 2]
myvar = pd.Series(a)
print(myvar)

Ярлыки: если ничего не указано, значения помечаются их порядковым номером. Первое значение имеет индекс 0, второе значение имеет индекс 1 и т. д. Эту метку можно использовать для доступа к указанному значению.

print(myvar[0])

Создание ярлыков. С помощью аргумента index вы можете присваивать имена своим ярлыкам. Вы можете обратиться к ярлыку, чтобы получить доступ к элементу после того, как вы сгенерировали ярлыки.

myvar = pd.Series(a, index = [“x”, “y”, “z”])
print(myvar)
print()
print(myvar["y"])

Сериализация объектов типа "ключ/значение". При создании серии вы также можете использовать объект типа "ключ/значение", например словарь. Метки создаются из ключей словаря. Вы можете использовать аргумент индекса и указать только те записи, которые вы хотите включить в серию, чтобы выбрать только некоторые элементы в словаре.

calories = {“day1”: 420, “day2”: 380, “day3”: 390}
myvar = pd.Series(calories)
print(myvar)
print()
myvar = pd.Series(calories, index = [“day1”, “day2”])
print(myvar)

Создание ряда дат. Мы можем сгенерировать ряд дат, используя общие функции в pandas, например, date_range.

date_series = pd.date_range(start = ‘05–01–2021’, end = ‘05–12–2021’)
print(date_series)

Использование функции для каждого отдельного элемента в последовательности:мы можем предоставить любую встроенную функцию, такую ​​как квадрат и логарифм, в качестве параметра для серии.

series = pd.Series([2, 4, 6, 8, 10])
print("pandas series initially")
print(series) 
print() 
print("pandas series after applying x/2 function")
modified_series = series.apply(lambda x:x/2)
print(modified_series)

кадры данных:

Наборы данных Pandas обычно представляют собой многомерные таблицы, известные как DataFrames. DataFrame — это целая таблица, а Series — это столбец.

data = {
‘Name’ :[‘Hema’, ‘John’, ‘Anna’],
‘calories’: [420, 380, 390],
‘duration’: [50, 40, 45]
       }
df = pd.DataFrame(data)
print(df)

Давайте построим DataFrame из этих двух серий.

data = {
 “calories”: [420, 380, 390],
 “duration”: [50, 40, 45]
       }
myvar = pd.DataFrame(data)
print(myvar)

Мы можем преобразовать словарь в эквивалентный DataFrame.

lists = [[2, ‘Vishal’, 22],
[3, ‘Kushal’, 25],
[1, ‘Aman’, 24]]
dataframe = pd.DataFrame(lists, columns = [‘id’, ‘name’, ‘age’])
print(dataframe)

Чтение файла CSV, Excel или JSON в DataFrame:

Чтение данных из файла CSV, файла Excel или файла JSON является одним из наиболее типичных действий, которые люди выполняют с Pandas.

Файлы CSV (файлы с разделителями-запятыми) — это простой способ хранения больших коллекций данных. Файлы CSV содержат обычный текст и являются широко известным форматом, который могут читать все, даже Pandas. Вы можете получить доступ к файлу CSV по этой ссылке — data.csv

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

JSON часто используется для хранения или извлечения больших наборов данных.
JSON – это обычный текст в объектном формате, хорошо известном в сообществе программистов, включая Pandas. Вы можете получить доступ к файлу по этой ссылке — data.json

Может быть рассмотрено любое содержимое данных в формате CSV, Excel и JSON.

#To read a CSV file:
df=pd.read_csv(‘data.csv’)
#To read the excel file:
df=pd.read_excel(‘data.xlsx’)
#To read the json file:
df=pd.read_json(‘data.json’)

Словарь в формате JSON: JSON = словарь Python

Объекты JSON имеют тот же формат, что и словари Python. Если ваш код JSON находится не в файле, а в словаре Python, вы можете напрямую загрузить его в DataFrame.

data = {
“Duration”:{
“0”:60,
“1”:60,
“2”:60,
“3”:45,
“4”:45,
“5”:60
},
“Pulse”:{
“0”:110,
“1”:117,
“2”:103,
“3”:109,
“4”:117,
“5”:102
},
“Maxpulse”:{
“0”:130,
“1”:145,
“2”:135,
“3”:175,
“4”:148,
“5”:127
},
“Calories”:{
“0”:409,
“1”:479,
“2”:340,
“3”:282,
“4”:406,
“5”:300
}
}
da = pd.DataFrame(data)
print(da)

Преобразование 2D-списка в фрейм данных: мы даже можем преобразовать 2-мерный массив в фрейм данных.

lists = [[2, ‘Vishal’, 22],
[3, ‘Kushal’, 25],
[1, ‘Aman’, 24]]
dataframe = pd.DataFrame(lists, columns = [‘id’, ‘name’, ‘age’])
print(dataframe)

Чтение данных и назначение имен столбцов, как указано с помощью любого разделителя: если DataFrame содержит данные, которые не содержат имен столбцов, или если они разделены с помощью разделителя, такого как «|» или «», панды могут способен справиться с такими случаями.

df=pd.read_csv(‘Automobile_data_without_col.csv’,sep=”|”,names[‘company’,’body-style’,’wheel-base’])
df.tail()

Анализ фреймов данных:

Просмотр данных: для печати DataFrame мы можем использовать функцию print(). Он печатает первые пять строк и последние пять строк вместе с подробными сведениями о количестве строк и столбцов. Мы даже можем использовать to_string для печати целых строк.

print(df)
print(df.to_string())

head(). Метод head является одним из наиболее часто используемых методов для получения быстрого обзора DataFrame. Начиная сверху, метод head() возвращает заголовки и указанное количество строк. . По умолчанию он возвращает содержимое первых пяти строк.

print(df.head(10))

tail(): как и head(), метод tail работает так же, но возвращается снизу.

print(df.tail())

info(): метод info возвращает следующую информацию из DataFrame.

df.info()

describe(): метод описания возвращает статистику данных в DataFrame, такую ​​как количество, среднее значение, стандартное отклонение и другие данные.

df.describe()

Именованные индексы. Вы можете назвать свои собственные индексы с помощью аргумента index.

df_named = pd.DataFrame(data, index = [“day1”, “day2”, “day3”])
print(df_named)

Мы можем удалить или удалить некоторые нужные столбцы, используя метод удаления.

df_named.drop([‘calories’],axis=1).head()

Для именованных индексов работает нарезка с использованием индексов по умолчанию. Однако использование функции loc для доступа к именованным индексам через индексы по умолчанию не работает.

df_named[1:3]

Найти именованные индексы. Чтобы вернуть указанные строки, используйте именованный индекс в атрибуте loc.

print(df.loc[["day2","day1"]])

Настройка пользовательского индекса в DataFrame. Мы даже можем изменить индекс DataFrame с индексов по умолчанию на определенный столбец с учетом фрейма данных.

lists = [[2, ‘Vishal’, 22],
[3, ‘Kushal’, 25],
[1, ‘Aman’, 24]]
dataframe = pd.DataFrame(lists, columns = [‘id’, ‘name’, ‘age’])
print(dataframe)
print()
dataframe_customindex = dataframe.set_index('id') print(dataframe_customindex)

Нарезка DataFrame:

Иногда создания простой серии недостаточно для достижения наших целей. Pandas предоставляет DataFrame Slicing, используя функции «loc» и «iloc» для более сложных операций. Давайте представим, что родители Бенджамина хотели больше узнать об успеваемости их сына в школе. Они хотят просмотреть лекции своего сына, его оценки, количество набранных кредитов и узнать, придется ли ему пересдавать экзамен. Мы можем легко разрезать DataFrame, созданный с помощью файлаgrades.csv, и получить нужные нам данные. Рассмотрим следующий сценарий:

Grades = 
Report_Card.loc[(Report_Card["Name"] == "Benjamin Duran"),  

               ["Lectures","Grades","Credits","Retake"]]

На первый взгляд это может показаться сложным, но на самом деле это довольно просто. В этой ситуации мы вызываем функцию loc[a,b] так же, как обычно разрезаем многомерный массив Python. Для значения «а» мы сравниваем содержимое столбца «Имя» в отчетной карточке с Бенджамином Дюраном, который создает объект серии логических значений. Мы можем индексировать DataFrame, используя серию с логическими значениями, при этом принимаются индексы «True», а индексы «False» игнорируются. Мы принимаем только имена столбцов, указанные для значения «b». В результате получаем следующий DataFrame.

Что ж, давайте разберемся с примером, упомянутым ниже.

data = {
“calories”: [420, 380, 390],
“duration”: [50, 40, 45]
}
df = pd.DataFrame(data)
print(df)

Найти строку: Pandas использует атрибут loc для возврата одной или нескольких указанных строк. В этом примере возвращается серия Pandas.

print(df.loc[0])

print(df.loc[[0, 1]])

Вы можете быть озадачены, почему я использую другой [] при доступе к нескольким индексам?

Потому что при использовании [] результатом является Pandas DataFrame.

Вы даже можете использовать iloc вместо loc.

Вы можете спросить меня, в чем тогда разница между loc и iloc.

loc против iloc?

loc получает строки (или столбцы) с определенными ярлыками из индекса. В то время как
iloc получает строки (или столбцы) в определенных позициях в индексе (поэтому принимает только целые числа).

#accessing data in specific column
df[‘calories’].head(3)
#the above can be done using iloc as shown below (slicing )
df.iloc[0:3][‘calories’]

Теперь давайте поиграем с loc и iloc. Рассмотрим приведенный ниже пример.

data = {
“calories”: [420,380,390,253,234,401,350,267,378,546,263,472],
“duration”: [50,40,45,45,55,50,35,30,40,50,45,40]
}
data=pd.DataFrame(data)

Нарезка от индекса 1 до 4 дает строки с 1 по 3 в приведенном ниже примере. Четвертая строка не будет выбрана.

data[0:4]

Получение значений из указанных столбцов с использованием индекса 1.

df.loc[[1],['calories','duration']]

Даже если индексы повторяются, особенно в именованных индексах, index.values ​​возвращает все значения индекса. На следующих шагах мы будем иметь дело с тем, чтобы они стали исключительно уникальными.

df.index.values

Итак, у вас есть это! Как и было обещано, мы можем получить уникальные значения любых столбцов, используя уникальный метод.

data = {
"calories": [420,380,380,253,234,401,350,253,378,546,253,401],
"duration": [50,40,45,45,55,50,35,30,40,50,45,40]
}
df_uni=pd.DataFrame(data)
df_uni['calories'].unique()

Количество уникальных значений задается nuunique (n означает число).

df_uni[‘calories’].nunique()

df_named = pd.DataFrame(data, index = [“day2”, “day2”, “day3”])
df_named.loc[[‘day2’],[‘calories’,’duration’]]

cols=df.columns
print(cols)

for i in cols:
print(i)

Метод value_counts(). Выдает количество различных значений в одном взятом столбце.

df_uni[‘calories’].value_counts()

Очистка данных:

Исправление неправильных данных в вашем наборе данных называется очисткой данных. Неверные данные могут быть:

  • Пустые ячейки
  • Данные в неправильном формате
  • Неверные данные
  • Дубликаты

Мы пойдем один за другим. Вы можете использовать приведенный ниже набор данных для выполнения операций.

      Duration          Date  Pulse  Maxpulse  Calories
  0         60  '2020/12/01'    110       130     409.1
  1         60  '2020/12/02'    117       145     479.0
  2         60  '2020/12/03'    103       135     340.0
  3         45  '2020/12/04'    109       175     282.4
  4         45  '2020/12/05'    117       148     406.0
  5         60  '2020/12/06'    102       127     300.0
  6         60  '2020/12/07'    110       136     374.0
  7        450  '2020/12/08'    104       134     253.3
  8         30  '2020/12/09'    109       133     195.1
  9         60  '2020/12/10'     98       124     269.0
  10        60  '2020/12/11'    103       147     329.3
  11        60  '2020/12/12'    100       120     250.7
  12        60  '2020/12/12'    100       120     250.7
  13        60  '2020/12/13'    106       128     345.3
  14        60  '2020/12/14'    104       132     379.3
  15        60  '2020/12/15'     98       123     275.0
  16        60  '2020/12/16'     98       120     215.2
  17        60  '2020/12/17'    100       120     300.0
  18        45  '2020/12/18'     90       112       NaN
  19        60  '2020/12/19'    103       123     323.0
  20        45  '2020/12/20'     97       125     243.0
  21        60  '2020/12/21'    108       131     364.2
  22        45           NaN    100       119     282.0
  23        60  '2020/12/23'    130       101     300.0
  24        45  '2020/12/24'    105       132     246.0
  25        60  '2020/12/25'    102       126     334.5
  26        60    2020/12/26    100       120     250.0
  27        60  '2020/12/27'     92       118     241.0
  28        60  '2020/12/28'    103       132       NaN
  29        60  '2020/12/29'    100       132     280.0
  30        60  '2020/12/30'    102       129     380.3
  31        60  '2020/12/31'     92       115     243.0

Некоторые ячейки в наборе данных пусты («Дата» в строке 22 и «Калории» в строках 18 и 28).
Набор данных имеет неверный формат («Дата» в строке 26).< br /> Набор данных содержит неверную информацию («Длительность» в строке 7).
В наборе данных есть дубликаты (строки 11 и 12).

Пустые ячейки
При анализе данных пустые ячейки могут привести к неправильному результату.

df = pd.read_csv(‘data.csv’)
new_df = df.dropna()
print(new_df.to_string())

df.dropna(inplace = True)
print(df.to_string())

Теперь вместо того, чтобы возвращать новый DataFrame, dropna(inplace = True) удалит все строки из исходного DataFrame, содержащие значения NULL.

Заменить пустые значения. Другой вариант – вставка нового значения в пустую ячейку. Таким образом вам не придется стирать целые строки из-за нескольких пустых ячеек. Мы можем использовать метод fillna() для замены пустых ячеек значением:

df = pd.read_csv(‘data.csv’)
df.fillna(130, inplace = True)
print(df.to_string())

Заменить только для указанных столбцов. В предыдущем примере заменяются все пустые ячейки во фрейме данных. Укажите имя столбца для DataFrame, чтобы просто заменить пустые значения для одного столбца. Здесь замените значения NULL в столбцах «Калории» на число 130:

df = pd.read_csv(‘data.csv’)
df[“Calories”].fillna(130, inplace = True)
print(df.to_string())

Подстановка среднего, медианы или режима. Вычисление среднего, медианного или модального значения столбца — это частый подход к замене пустых ячеек. Pandas вычисляет значения для данного столбца, используя методы mean(), median() и mode():

df = pd.read_csv(‘data.csv’)
x = df[“Calories”].mean()
df[“Calories”].fillna(x, inplace = True)

Среднее = среднее значение (сумма всех значений, деленная на количество значений)
Медиана = значение в середине после сортировки всех значений по возрастанию
Режим = значение, которое появляется чаще всего.

Вы можете использовать тот же код, что и в методе mean(), но заменить его на median(), чтобы заменить медиану.

мы немного проясним для режима(),

df = pd.DataFrame({‘Calories’:[1,1,2,2, 3,None]})
print (df)
x=df[“Calories”].mode()[0]
print(x)
print()
df[“Calories”].fillna(x, inplace = True)
print(df.to_string())

Данные в неправильном формате.
Ячейки с данными в неправильном формате могут затруднить анализ данных, если не сделать его невозможным. У вас есть два варианта исправить это: либо удалить строки, либо преобразовать все ячейки в столбцах в один и тот же формат.

Две ячейки в нашем фрейме данных имеют неправильный формат. В строках 22 и 26 должна быть строка, представляющая дату в столбце «Дата». Давайте посмотрим, сможем ли мы преобразовать каждую ячейку в столбце «Дата» в дату. Для этого в Pandas есть метод to date_time():

df = pd.read_csv(‘data.csv’)
df[‘Date’] = pd.to_datetime(df[‘Date’])
print(df.to_string())

Дата в строке 26 была фиксированной, но пустая дата в строке 22 получила значение NaT (не время) или пустое значение, как видно из результата. Пустые значения можно обработать, удалив всю строку с помощью метода dropna().

df.dropna(subset=[‘Date’], inplace = True)

Неправильные данные.
"Неверные данные" не обязательно должны быть "пустыми ячейками" или "неправильным форматом", они могут быть просто неверными, например, если кто-то ввел "199", а не " 1,99». Поскольку у вас есть представление о том, каким оно должно быть, иногда вы можете определить неверные данные, просмотрев набор данных. Если вы посмотрите на наш набор данных, вы заметите, что продолжительность в строке 7 составляет 450, но продолжительность в других строках находится между 30 и 60. Это не обязательно должно быть правильным, но учитывая, что это данные коллекции чьих-то тренировок, можно предположить, что этот человек не тренировался в течение 450 минут. Как это исправить?

Значения заменяются.Замена неверных значений чем-то другим – это один из способов устранения неполадок. Скорее всего, в нашем случае опечатка, и число должно быть «45» вместо «450», и мы могли бы просто вставить «45» в строку 7:

df = pd.read_csv(‘data.csv’)
df.loc[7,’Duration’] = 45
print(df.to_string())

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

Прокрутите все значения в столбце «Длительность». Если значение выше 120, установите его на 120:

for x in df.index:
 if df.loc[x, “Duration”] > 120:
 df.loc[x, “Duration”] = 120

Удаление строк. Еще один метод работы с неправильными данными — удаление содержащих их строк. Вам не придется выяснять, что делать вместо них, и есть большая вероятность, что они вам не понадобятся для выполнения вашего анализа.

Выявление дубликатов.
Строки, которые были зарегистрированы более одного раза, называются повторяющимися строками.
Мы определили, что строки 11 и 12 являются дубликатами на основе нашего тестового набора данных. Метод Duplicated() можно использовать для поиска дубликатов в больших наборах данных. Для каждой строки метод Duplicated() возвращает логическое значение. Возвращает True для каждой повторяющейся строки, иначе False:

print(df.duplicated())

Удаление дубликатов. Чтобы удалить дубликаты, используйте метод drop_duplicates().

df.drop_duplicates(inplace = True)

Корреляции данных:

Поиск взаимосвязей.Метод corr() — фантастическая функция модуля Pandas. Метод corr() определяет взаимосвязь между столбцами вашего набора данных. В примерах используется CSV-файл data.csv.

df = pd.read_csv(‘data.csv’)
print(df.corr())

Обратите внимание, что метод corr() игнорирует «нечисловые» столбцы.

Объяснение результата.
Метод corr() возвращает таблицу с большим количеством значений, которые показывают, насколько эффективно связаны два столбца. Значение может находиться в диапазоне от -1 до 1.
-›1 означает взаимосвязь один к одному (идеальная корреляция), и для этого набора данных каждый раз, когда значение в первом столбце увеличивается, значение в Второй столбец также увеличился.
->0,9 также является благоприятной ассоциацией, и увеличение одного значения почти наверняка увеличит другое.
->-0,9 было бы точно так же желательно, как 0,9, но если одно значение увеличивается, другое, вероятно, уменьшится.
-›0,2 указывает на плохую взаимосвязь, подразумевая, что только потому, что одно значение растет, это не означает, что другое значение будет таким же.

Идеальная корреляция. Мы видим, что «Продолжительность» и «Продолжительность» получили число 1.000000, что имеет смысл, поскольку каждый столбец всегда имеет идеальную связь сам с собой.

Хорошая корреляция."Продолжительность" и "Калории" имеют корреляцию 0.922721, что является очень хорошей корреляцией, и мы можем предсказать, что чем дольше вы тренируетесь, тем больше калорий вы сжигаете, и наоборот. вокруг: если вы сожгли много калорий, вы, вероятно, долго тренировались.

Плохая корреляция."Длительность" и "Максимальный пульс" имеют корреляцию 0.009403, что является очень плохой корреляцией, означающей, что мы не можем предсказать максимальный пульс, просто взглянув на продолжительность тренировки, и наоборот. наоборот

Вывод:

Я надеюсь, что эта статья расширит ваши знания. Продолжайте поддерживать и счастливого обучения. Вы можете подписаться на меня для дальнейших обновлений…