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

Давайте сначала импортируем все необходимые библиотеки и пакеты.

#import all the packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import Normalizer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
import sklearn.metrics
import statsmodels.api as sm
import plotly.express as px #for plotting the scatter plot
import seaborn as sns #For plotting the dataset in seaborn
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, r2_score 
import math
from math import sqrt
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import classification_report
sns.set(style='whitegrid')
import warnings
warnings.filterwarnings('ignore')

Исследовательский анализ данных (EDA)

Прочитайте CSV-файл.

#Read the excel file
data=pd.read_csv('/content/datafile (1).csv')
print(data.head(5))
print(data.describe())

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

Как объяснялось в части 1, нам нужны Чауса, Душери и Лангра в сортах манго. Цены на манго также меняются в зависимости от сезона/месяца, поэтому мы извлекаем месяц из даты прибытия.

data = data[data['variety'].isin(['Chausa','Dusheri','Langra'])]
data['arrival_date']=data['arrival_date'].apply(lambda x:int(x[3:5]))

Затем мы выполняем кодирование меток для штата, сорта, района и рынка. Мы также сохраняем эти закодированные сопоставления меток, создавая словари и выгружая их в файлы рассола. Это сделано для того, чтобы при интеграции были предоставлены одинаковые кодировки для входных значений от пользователя, так как модель ML построена на этих нумерациях. Например, если модель была обучена с Андхра-Прадеш как метка «0», то пользовательский ввод из Андхра-Прадеш также должен быть закодирован как «0», а не какое-либо другое значение.

lab = LabelEncoder()
data['state'] = lab.fit_transform(data['state'])
state_mapping = dict(zip(lab.classes_, lab.transform(lab.classes_)))

data['variety'] = lab.fit_transform(data['variety'])
variety_mapping = dict(zip(lab.classes_, lab.transform(lab.classes_)))

data['district'] = lab.fit_transform(data['district'])
district_mapping = dict(zip(lab.classes_, lab.transform(lab.classes_)))

data['market'] = lab.fit_transform(data['market'])
market_mapping = dict(zip(lab.classes_, lab.transform(lab.classes_)))

import pickle
pickle_out = open("state.pickle","wb")
pickle.dump(state_mapping, pickle_out)
pickle_out.close()

pickle_out = open("variety.pickle","wb")
pickle.dump(variety_mapping, pickle_out)
pickle_out.close()

pickle_out = open("district.pickle","wb")
pickle.dump(district_mapping, pickle_out)
pickle_out.close()

pickle_out = open("market.pickle","wb")
pickle.dump(market_mapping, pickle_out)
pickle_out.close()

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

print(data.columns)
data.isnull().any()
data['max_price']=data['max_price'].fillna(data['max_price'].mean())
data.isnull().any()

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

data.drop('commodity',axis=1,inplace=True)
data.head()

Затем мы выполняем удаление выбросов с помощью метода z-score. Значения за пределами графика можно рассматривать как выбросы.

plt.figure(figsize=(16,5))
plt.subplot(1,4,1)
sns.distplot(data['district'])
plt.subplot(1,4,2)
sns.distplot(data['market'])
plt.subplot(1,4,3)
sns.distplot(data['min_price'])
plt.subplot(1,4,4)
sns.distplot(data['max_price'])
plt.show()

Мы находим граничные значения и ограничиваем выбросы для всех столбцов, присутствующих в наборе данных. Базовая формула оценки z для выборки:
z = (x – μ) / σ

upper_limit={}
lower_limit={}
for column in data.columns:
  upper_limit[column]=data[column].mean() + 3*data[column].std()
  lower_limit[column]=data[column].mean() - 3*data[column].std()
#applying the capping:
for column in data.columns:
 data[column] = np.where(
  data[column]>upper_limit[column],
  upper_limit[column],
  np.where(
  data[column]<lower_limit[column],
  lower_limit[column],
  data[column]
)
)
data.describe()

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

Далее мы анализируем значения корреляции с помощью тепловой карты. На тепловой карте было замечено наличие мультиколлинеарности из-за min_price и max_price. Значения корреляции между этими независимыми переменными были высокими.

cor=data.corr()
hm1 = sns.heatmap(cor, annot = True)
hm1.set(xlabel='\nFeatures', ylabel='Features\t', title = "Correlation matrix of data\n")
plt.show()

Следовательно, мы удалили два столбца и определили modal_price как нашу последнюю зависимую переменную/переменную ответа. И выполняем разбиение датасета на обучение и тестирование.

data.drop(['max_price','min_price'],axis=1,inplace=True)
features=['state','variety','arrival_date','market','district']
x=data[features]# since these are the feature we take them as x
y = data['modal_price']# since price is the output or label we'll take it as y
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2,random_state=42)

Затем мы выполняем стандартное масштабирование. Стандартное масштабирование — это метод предварительной обработки, используемый в машинном обучении для преобразования числовых данных с нулевым средним значением и единичной дисперсией. Полученные данные имеют среднее значение 0 и стандартное отклонение 1, что упрощает сравнение и анализ данных, которые могут иметь разные масштабы и диапазоны. Поскольку наши переменные x — состояние, разнообразие, дата_прибытия и т. д. — имеют разные масштабы из-за количества присутствующих уникальных значений и применения кодирования меток, необходимо было выполнить метод стандартизации.

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
x_train = sc.fit_transform(x_train)
x_test = sc.transform(x_test)
model = open('standard_scaler.pkl', 'wb')
pickle.dump(sc,model)
model.close()

Регрессионные модели

Сначала мы применили множественную линейную регрессию, чтобы предсказать модальные_цены.

model = LinearRegression() #Create a linear regression model
model.fit(x_train,y_train) #Fit the data
#Predict the value of y based for the test data
y_prediction_regression = model.predict(x_test)
PricePredict = pd.DataFrame({'Actual price': y_test, 'Predicted price': y_prediction_regression})
print(PricePredict)
print(model.score(x_test,y_test))

Однако регрессионная модель работала плохо и дала оценку 25,21%. Это можно объяснить низкими значениями корреляции между независимыми переменными и зависимой переменной. Это видно на тепловой карте, нарисованной выше. Следовательно, нам нужно было найти модель прогнозирования, которая концептуально не зависела бы от предположения о корреляции в базовых данных.

# Fit the decision tree model
model = DecisionTreeRegressor(max_depth=8)
model.fit(x_train, y_train)
#predict
y_prediction_decision = model.predict(x_test)
#rsquare value
r2_score(y_test,y_prediction_decision)

Внедренная модель регрессора дерева решений также показала низкую оценку — 72,4 %. Затем мы попытались реализовать модель KNeighboursRegressor.

Модель регрессора k-ближайших соседей (KNN) — это тип алгоритма обучения с учителем, используемый для задач регрессии. Он работает, находя k ближайших точек данных в обучающем наборе к заданной точке тестовых данных, а затем используя среднее значение их целевых значений в качестве прогнозируемого целевого значения для контрольной точки.

Значение k в алгоритме KNN — это гиперпараметр, который необходимо указать перед обучением модели. Большее значение k приведет к более гладкой границе решения и большему обобщению, но это также может привести к недообучению. С другой стороны, меньшее значение k приведет к более сложной границе решения и большему переоснащению. Следовательно, мы пытаемся подобрать модель, предсказать и вычислить значения RMSE для диапазона значений k от 1 до 20.

rmse_val = [] #to store rmse values for different k
for K in range(20):
  K = K+1
  model = KNeighborsRegressor(n_neighbors = K)
  model.fit(x_train, y_train) #fit the model
  pred=model.predict(x_test) #make prediction on test set
  error = sqrt(mean_squared_error(y_test,pred)) #calculate rmse
  rmse_val.append(error) #store rmse values
  print('RMSE value for k= ' , K , 'is:', error)

#plotting the rmse values against k values
curve = pd.DataFrame(rmse_val)
curve.plot()

Из значений RMSE (среднеквадратичная ошибка) и графика этих значений мы выбираем k=4, который показал наименьшее RMSE 784,678.

Затем примените регрессию KNN с k = 4 и выполните тестирование, чтобы найти результат 0,760. Это был лучший результат из трех примененных моделей, поэтому мы дорабатываем его для прогноза цены.

#  KNN regression
knn = KNeighborsRegressor(n_neighbors=4)
# fit the model using the training data and training 
knn.fit(x_train, y_train)
y_prediction_knn=knn.predict(x_test)
print(knn.score(x_test, y_test))
print("______________________________________________________________________________________________")
PricePredict = pd.DataFrame({'Actual price': y_test, 'Predicted price': y_prediction_knn})
print(PricePredict)

Мы также проверили среднеквадратичную ошибку (MSE) и значения RMSE. Вывод ниже показывает значения и график для первых 100 прогнозируемых точек данных.

mse =mean_squared_error(y_test, y_prediction_knn)
print("Mean Squared Error:",mse)
 
rmse = math.sqrt(mse)
print("Root Mean Squared Error:", rmse)

#plot the predicted result.
x_ax=range(100)
y_test_range=y_test[:100]
y_prediction_knn_range=y_prediction_knn[:100]
plt.figure(figsize=(16,5))
plt.scatter(x_ax, y_test_range, s=5, color="blue", label="original")
plt.plot(x_ax, y_prediction_knn_range, lw=1.5, color="red", label="predicted")
plt.legend()
plt.show()

Наконец, мы сохраняем обученную модель регрессора KNN в файле рассола, который будет использоваться в части 3 этого проекта!

import pickle
model_regression = open('knn_regression_model.pkl', 'wb')
pickle.dump(knn,model_regression)
model_regression.close()

Это конец части 2 этого проекта. Надеюсь, вам понравилось! Ознакомьтесь с частью 1 для классификации и частью 3 для окончательной интеграции проекта!

part1 (классификация изображений сортов манго) — https://medium.com/@mitali.p.baj/price-prediction-with-classification-for-mango-variety-part-1-f4a76128d415
part3 ( Интеграция частей классификации и регрессии) — https://medium.com/@mitali.p.baj/price-prediction-with-classification-for-mango-variety-part-3-a3563d2350f3

Свяжитесь со мной для предложений и сотрудничества на mailId — [email protected], LinkedIn — https://www.linkedin.com/in/mitali-baj/