Прогнозирование цены бриллианта с помощью scikit-learn на основе данных, доступных на Kaggle.

Бриллианты всегда высоко ценились и пользовались спросом у членов королевской семьи и простых людей. От украшения корон и тиар до применения в промышленности бриллианты являются универсальными объектами. Так как же оценивается такой универсальный товар?

Цена бриллианта в основном сводится к нескольким характеристикам: карат, огранка, цвет, чистота, глубина и таблица. Все эти факторы в конечном итоге определяют, как бриллиант будет преломлять свет. Чем эффектнее бриллиант преломляет свет, тем больше нам придется раскошелиться.

Возвращаясь к характеристикам, карат бриллианта относится к весу бриллианта. Больше лучше. Огранка бриллианта относится к форме и симметрии бриллианта. Симметричный бриллиант будет более блестящим на свету. Плоская вершина алмаза, через которую проходит свет, называется площадкой, а глубина алмаза определяет, как преломляется проникающий свет. Чистота бриллианта выражает недостатки и дефекты бриллианта.

Данный набор данных на Kaggle имеет все вышеописанные характеристики примерно для 53 тысяч бриллиантов. Мы попытаемся построить модель машинного обучения для прогнозирования цен на бриллианты на основе этого набора данных с помощью scikit-learn.

Загрузка и чтение набора данных

import numpy as np
import pandas as pd
df=pd.read_csv('diamondscsv.csv')

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

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

df.head()

Приведенный выше код возвращает первые несколько записей.

Далее мы воспользуемся методом Pandas описать(), чтобы получить краткую сводку только что загруженного фрейма данных.

df.describe()

Чтобы получить список столбцов в фрейме данных, мы будем использовать атрибут columns.

df.columns

Приведенный выше список возвращаемых столбцов показывает особенность. Существует столбец с именем Безымянный: 0.Это затрудняет будущие манипуляции с фреймом данных. Поэтому давайте переименуем его в более удобное имя, такое как ID.

df.rename(columns={'Unnamed: 0':'ID'},inplace=True)

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

import seaborn as sns
sns.pairplot(df,kind='scatter')

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

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

corr_cols=['carat', 'cut', 'color', 'clarity', 'depth', 'table',
       'price', 'x', 'y', 'z']
x = sns.heatmap(df[corr_cols].corr(method="pearson"), annot=True)

В этой корреляционной матрице есть явная особенность: параметры x, y и z сильно взаимосвязаны. Мы будем помнить об этом при выборе признаков для построения нашей модели.

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

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

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

Предварительная обработка

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

from sklearn.preprocessing import LabelEncoder
for i in cat_col:
    df[i]=LabelEncoder().fit_transform(df[i])
print(df.head())

Давайте начнем с построения модели, создав простую модель линейной регрессии для набора данных.

y1=df['price'] #Dependent variable
X1=df[['carat','color','clarity', 'cut','x', 'table', 'depth']]
## using only x instead of x,y,z to prevent overfitting of model due to high correlation between the three variables

x_train1, x_test1, y_train1, y_test1=train_test_split(X1,y1,test_size=0.33)


lr1=LinearRegression(normalize=True) 
lr1.fit(x_train1, y_train1)

pred1=lr1.predict(x_test1)
lr_rsquare=metrics.r2_score(y_test1, pred1)
print('Mean Square Error:',metrics.mean_absolute_error(y_test1, pred1))
print('Mean Square Error:',metrics.mean_squared_error(y_test1, pred1))
print('Root Mean Square Error:',np.sqrt(metrics.mean_squared_error(y_test1, pred1)))
print('R Square:', metrics.r2_score(y_test1,pred1))

О, нет! Результаты ужасно ошибочны! Наши прогнозы на тестовом наборе отличаются почти на тысячу долларов. Это неприемлемо. Давайте копнем глубже.

Давайте построим цены и посмотрим распределение.

df["price"].plot(kind="hist")

Как видим, цены завышены. Это то, что, кажется, мешает нашим прогнозам. Мы должны сделать так, чтобы цены распределялись более равномерно. Для этого можно взять журнал цен, предложенный Preeti Madan.

Давайте теперь попробуем создать модель линейной регрессии для этого обновленного набора данных.

df["log_price"]=np.log2(df["price"]+1)
df["log_price"].plot(kind="hist")\

y=df['log_price'] 
X=df[['carat','color','clarity', 'cut','x', 'table', 'depth']] 

x_train, x_test, y_train, y_test=train_test_split(X,y,test_size=0.33) 

from sklearn.linear_model import LinearRegression
lr=LinearRegression(normalize=True) 
lr.fit(x_train, y_train)
pred=lr.predict(x_test)

lr_rsquare=metrics.r2_score(y_test, pred)
print('Mean Square Error:',metrics.mean_absolute_error(y_test, pred))
print('Mean Square Error:',metrics.mean_squared_error(y_test, pred))
print('Root Mean Square Error:',np.sqrt(metrics.mean_squared_error(y_test, pred)))
print('R Square:', metrics.r2_score(y_test,pred))

Измененный набор данных лучше подходит для создания моделей. Мы будем использовать это для всех будущих целей.

Построение модели

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

from sklearn.metrics import *
def perform_eval(predictions,model):
    '''
    prints the values of various performance metrics for the given model
    '''
    model_name = type(model).__name__
    print('\033[1m',model_name,"summary \033[1m \n")
    print('Mean Square Error:',mean_absolute_error(y_test, predictions))
    print('Mean Square Error:',mean_squared_error(y_test, predictions))
    print('Root Mean Square Error:',np.sqrt(mean_squared_error(y_test, predictions)))
    print('R Square:', r2_score(y_test,predictions))

Эта функция perform_eval возвращает показатели оценки для данной модели.

def model_train(model,x_train):
    '''
    Function to train and call evaluation method for given model
    '''
    model.fit(x_train,y_train)
    model_preds=model.predict(x_test)
    perform_eval(model_preds,model)

Функция model_train предназначена для обучения данной модели на обучающих данных. Он также вызывает функцию perform_eval, которая возвращает оценку набора тестов.

Давайте теперь создадим несколько моделей, используя определенные выше функции.

Модель лассо:

from sklearn import linear_model
lass=linear_model.Lasso(random_state=77,max_iter=3000)
model_train(lass,x_train)

Регрессор дерева решений

from sklearn import ensemble
from sklearn.tree import DecisionTreeRegressor
dec_tree=DecisionTreeRegressor(max_depth=8,min_samples_leaf=10)
model_train(dec_tree,x_train)

Случайный лесной регрессор

from sklearn.ensemble import RandomForestRegressor
rand_for=ensemble.RandomForestRegressor(n_estimators=100,max_depth=10,criterion='mse')
model_train(rand_for,x_train)

Спасибо за прочтение! Это первое из многих руководств по использованию scikit-learn и TensorFlow. Я буду размещать больше статей, подобных этой, объясняющих мои блокноты. Предложения и конструктивная критика всегда приветствуются!