Продолжение рассказа о прогнозировании цен на бриллианты с использованием машинного обучения

Этот пост является скорее продолжением истории Прогнозирование цены бриллиантов с помощью машинного обучения.



В первом посте заложены основы алгоритмов регрессии машинного обучения для прогнозирования цены дорогостоящего предмета с использованием общедоступной базы данных примерно из 54 000 бриллиантов на Kaggle.

В этом конкретном посте рассказывается о загрузке данных из PriceScope и CaratLane и их использовании для прогнозирования цен на бриллианты.

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

df = pd.read_csv("pricescope1.csv")
df.drop(’Unnamed: 0’, axis=1, inplace=True)
display(df.head(3))

p.s. все функции, вызываемые в коде, таком как convertfeatures2log() в этом посте, либо определены/описаны здесь, либо в моем предыдущем посте.

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

Теперь выполняем все необходимые действия по обработке данных, как и раньше.

Конвертировать цену в долларах в целые числа

Как мы видим, цены в наборе данных pricescope имеют тип данных currency, т.е. цены показаны в долларах с разделителями тысяч. Поскольку алгоритму машинного обучения нужны числовые данные, нам нужно будет преобразовать долларовые значения в целые числа. Способ делаем следующим образом.

  1. Замените $ пробелом, используя регулярное выражение
  2. Преобразовать в int с помощью astype()
  3. Преобразование массива/серии в фрейм данных с помощью pd.DataFrame
priceint=pd.DataFrame(df[’price’].replace(’[\$,]’, '’, regex=True).astype(int))
df.drop([’price’], axis=1, inplace=True)
df[’price’] = priceint[’price’].values

Проверьте, присутствуют ли нулевые значения — так же, как мы делали ранее.

df.isnull().sum()

Обратите внимание, что у Flouroscence пустые значения. Давайте посмотрим, сколько строк имеет пустой Flouroscence, и избавимся от этих данных, если пустые значения для строк меньше 0,5% от общего числа строк.

df[‘flr’].isnull().sum() / len(df[‘flr’]) *100

Выход: 0.4240282685512367

Мы видим, что нулевые значения относятся к менее чем 0,5% данных. Итак, давайте удалим эти строки.

indexnames = df[df[’flr’].isnull()].index
df.drop(axis=0,index=indexnames,inplace=True)

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

df.info()

Результат выглядит следующим образом:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 1409 entries, 6 to 1414
Data columns (total 12 columns):
carat      1409 non-null float64
cut        1409 non-null object
color      1409 non-null object
clarity    1409 non-null object
depth      1409 non-null object
table      1409 non-null object
lab        1409 non-null object
sym        1409 non-null object
pol        1409 non-null object
flr        1409 non-null object
hna        1409 non-null object
price      1409 non-null int32
dtypes: float64(1), int32(1), object(10)
memory usage: 137.6+ KB

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

lenT = len([x for x in df['table'] if not x.isnumeric()]) / len(df['table'])*100
print('Percent of non-numeric data in Table -->', lenT)
lenD = len([x for x in df['depth'] if not x.isnumeric()]) / len(df['depth'])*100
print('Percent of non-numeric data in Depth -->', lenD)

Процент нечисловых данных в таблице → 5,25195173882186
Процент нечисловых данных в глубине → 92,902767920511

Теперь давайте посмотрим, являются ли они числами с плавающей запятой, хранящимися в виде строк, или какими-то бессмысленными значениями.

Создайте функцию removenotnum() и вызовите ее, чтобы увидеть значения

Результат:

all rubish values --> {'-'}
Percent of identified rubbish data in Table --> 0.07097232079488999
all rubish values --> {'-'}
Percent of identified rubbish data in Depth --> 0.07097232079488999

Похоже, что только один тип ненужного символа «-» хранится в 0,5% данных. Поскольку это крошечная часть всего набора данных, мы можем сейчас безопасно удалить все эти строки. Удалите строки с мусорными значениями для таблицы и глубины.

indexnames = df[(df[‘table’] == ‘-’) | (df[‘depth’] == ‘-’)].index
df.drop(axis=0,index=indexnames,inplace=True)

Теперь преобразуйте тип данных объекта table и depth в число с плавающей запятой.

df[‘table’] = df[‘table’].astype(float)
df[‘depth’] = df[‘depth’].astype(float)

Затем мы строим парный график цены и 4 Cs.

sns.pairplot(df, x_vars=[‘carat’, ‘cut’, ‘clarity’, ‘color’], y_vars = [‘price’])
plt.show()

Теперь запустите convert_catg() function в наборе данных pricescope, чтобы преобразовать категориальные столбцы в числовые столбцы. Вывод будет следующим:

Теперь мы проверяем любые выбросы, вызывая функцию dfboxplot() для построения коробчатых диаграмм всех свойств. Мы снова удалим строки, содержащие данные о выбросах для любого свойства, если такие строки составляют менее 0,5% набора данных.

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

Как и ожидалось, мы видим, что выбросов нет.

Теперь мы преобразуем значения всех непрерывных признаков («карат», «глубина», «таблица», «цена») в логарифмические путем вызова convertfeatures2log()для лучшего использования алгоритмами машинного обучения.

Запуск алгоритмов машинного обучения

Сначала мы устанавливаем X и y, как и раньше.

X_df = df.drop([‘price’], axis=1)
y_df = df[[‘price’]]

Теперь мы видим корреляцию между ценой и всеми другими атрибутами следующим образом:

Снова Train Test Split:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_df, y_df, test_size=0.3, random_state=42)

Линейная модель

Сначала мы запускаем модель линейной регрессии.

from sklearn.linear_model import LinearRegression
reg_all = LinearRegression()
reg_all.fit(X_train,y_train)
y_pred=reg_all.predict(X_test)

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

Однако метрики говорят о другом:

MAE: 0.11652136924155168
MSE: 0.02292105733384392
RMSE: 0.15139701890672722

Случайный лес

Все знают, и мы только что проверили прогнозирование цен на бриллианты из набора данных Kaggle, что Random Forest — надежный алгоритм.

MAE: 0.06791631018129721
MSE: 0.010798208786551588
RMSE: 0.10391443011705154

Нейронная сеть

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

Обратите внимание, что мы предоставляем первому слою 11 входных объектов и 18 скрытых узлов. Для следующего слоя ожидается 12 выходных узлов. Я попробовал несколько комбинаций, и они оказались приемлемыми.

Результат для ANN после запуска функций KerasRegressor, KFold и cross_val_score, как мы делали ранее, немного лучше, чем линейная регрессия, но не так хорош, как случайный лес.

Чтобы рассчитать правильную цену бриллианта, который вы видите в алмазном районе, вы вызываете функцию прогнозирования этой модели следующим образом. Рассматриваемый бриллиант – это этот.

newdiamond = [‘0.3’, ‘Premium’, ‘ G’, ‘VS1’, 57, 516, ‘GIA’, ‘X’, ‘X’, ’N’, ‘N’]
rf.predict(newdiamond)

использованная литература

Для этого конкретного поста я сослался на несколько веб-сайтов, включая Beyond4Cs, Мастерство машинного обучения и другие несколько постов и веб-сайтов в Интернете.

Обо мне

Я работаю в области ИТ-проектов Инвестиционного банка. У меня есть 15-летний опыт создания готовых к производству приложений для фронт-офисной торговли и последние 3 года в области машинного обучения, NLP, NER, обнаружения аномалий и т. д.

За время своей карьеры в сфере искусственного интеллекта и машинного обучения я изучал различные посты в СМИ/хакернун/кднуггетс; проходил различные курсы на Coursera, Udemy, edX; просмотрел множество видеороликов на YouTube.
Я считаю, что получение всех этих знаний придаст вам уверенности в себе и подготовит к следующему жизненному вызову.

Однако даже за годы обучения и опыта (проектов) вряд ли можно знать хотя бы 1% об области AI ML.
Возможно, она столь же обширна, как Вселенная, постоянно развивается и исследуется людьми даже на уровень верхушки айсберга.

Не стесняйтесь связаться со мной в LinkedIn или подписаться на меня в Medium.