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

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

Время признания: я должен признать, что этот метод поиска вин с высокими оценками сработал для меня, хотя он и немного субъективен. Но есть одна загвоздка: я рассматриваю только те вина, которые получили рейтинг. Из-за этого недостатка мне хотелось бы попробовать фантастические вина из мест, которые не получили отзывов модных (и дорогих) критиков.

Это заставило меня задуматься: существует ли способ более систематично оценивать вина? Возможно ли создать автоматизированный метод оценки вин?

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

Набор данных и функции

Набор данных, использованный в этом исследовании, был получен из репозитория машинного обучения UCI [ссылка]. Набор данных включает вина из Минью, Португалия, с особым упором на два различных варианта: красные и белые вина Виньо Верде. Набор данных состоит из двух подмножеств, каждое из которых относится к одному из вариантов. В этих подмножествах имеется одиннадцать переменных, охватывающих как физико-химические характеристики (описанные в таблице ниже), так и показатель сенсорного качества, который оценивается по шкале от 0 до 10. Примечательно, что набор данных не включает информацию о типах винограда, марках вина. , или цены продажи вина.

Я провел исследовательский анализ данных (EDA) и вот что обнаружил:

Одним из примечательных результатов является то, что атрибутом, наиболее сильно коррелирующим с целевой переменной «качество», является «алкоголь», имеющий коэффициент корреляции 0,48.

Была выявлена ​​заметная положительная корреляция со значениями 0,23 для «лимонной кислоты», 0,25 для «сульфатов» и 0,12 для «фиксированной кислотности». Это говорит о том, что вина с повышенным уровнем фиксированной кислотности часто соответствуют повышенному уровню лимонной кислоты и сульфатов.

И наоборот, наиболее существенная отрицательная корреляция -0,39 была выявлена ​​​​с «летучей кислотностью», тогда как корреляция -0,19 характерна для «общего диоксида серы». Это указывает на то, что вина, характеризующиеся более высоким уровнем фиксированной кислотности, имеют тенденцию демонстрировать более низкие значения летучей кислотности и общего диоксида серы.

Диаграмма рассеяния, изображающая взаимосвязь между «фиксированной кислотностью» и «лимонной кислотой», дает ценную информацию о том, как эти два атрибута взаимодействуют в наборе данных.

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

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

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

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

Модели машинного обучения

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

- K-ближайшие соседи (KNN): 99,4%
- Логистическая регрессия (LR): 99,4%
- Наивный байесовский метод (NB): 96,6%
- Классификатор повышения градиента (GBC): 99,4 %
- Классификатор опорных векторов (SVC): 99,6%
- Классификатор случайного леса (RFC): 99,5%
- Классификатор дерева решений (DT): 98,0%

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

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

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

Модель глубокой нейронной сети

Я разработал и построил собственную модель глубокой нейронной сети (DNN), специально разработанную для этого набора данных. Кроме того, я настроил скорость обучения, чтобы она лучше подходила для этого конкретного набора данных. Визуальное представление кривой скорости обучения показывает, что минимальная точка кривой приходится на значение 10e-2.

def create_uncompiled_model(input_shape, num_classes):
    model = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=(input_shape,)),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dropout(0.3),
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])

    return model

def adjust_learning_rate(dataset, num_classes, epochs=100):
    x_train_wm_sc, y_train_wm_cat = dataset

    input_shape = x_train_wm_sc.shape[1]
    model = create_uncompiled_model(input_shape, num_classes)

    lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-6 * 10**(epoch / 20))

    optimizer = tf.keras.optimizers.Adam()

    model.compile(loss=tf.keras.losses.CategoricalCrossentropy(),
                  optimizer=optimizer,
                  metrics=["accuracy"])

    callbacks = [lr_schedule]

    history = model.fit(x_train_wm_sc, y_train_wm_cat, epochs=epochs, callbacks=callbacks)

    return history

# Define your dataset and num_classes
dataset = (x_train_wm_sc, y_train_wm_cat)
num_classes = 10

# Run the training with dynamic LR
lr_history = adjust_learning_rate(dataset, num_classes)

# Plot Learning Curve
learning_rates = lr_history.history['lr']
loss = lr_history.history['loss']

plt.semilogx(learning_rates, loss)
plt.xlabel('Learning Rate')
plt.ylabel('Loss')
plt.title('Learning Rate vs. Loss')
plt.grid()
plt.show()

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

# Define learning rate
learning_rates = [1e-2]
epochs_ = 70

lr_values = []
loss_values = []

for lr in learning_rates:
    nn_model = tf.keras.Sequential([
        tf.keras.layers.Input(shape=(x_train_wm_sc.shape[1],)),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dropout(0.3),
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])
    
    nn_model.compile(loss=tf.keras.losses.CategoricalCrossentropy(), 
                    optimizer=tf.keras.optimizers.Adam(learning_rate = lr),
                    metrics=['accuracy'])
    lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-6 * 10**(epoch / 20))
    history_wm = nn_model.fit(x_train_wm_sc, 
                           y_train_wm_cat, 
                           epochs=epochs_, 
                           verbose=0,
                           validation_data=(x_test_wm_sc, y_test_wm_cat), 
                           callbacks=[lr_schedule])
    
    lr_values.append(lr)
    loss_values.append(history_wm.history['loss'][-1])
    loss, accuracy = nn_model.evaluate(x_test_wm_sc, y_test_wm_cat, verbose=0)
    final_train_accuracy_wm = history_wm.history['accuracy'][-1]
    final_val_accuracy_wm = history_wm.history['val_accuracy'][-1]
    print(f"Training Accuracy: {final_train_accuracy_wm:.4f}")
    print(f"Validation Accuracy: {final_val_accuracy_wm:.4f}")

def plot_training_history_loss(history):
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model Loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend(['Train', 'Validation'], loc='upper right')
    plt.show()

# Plot
plot_training_history_loss(history_wm)

def plot_training_history_accuracy(history):
    # Plot training & validation accuracy values
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('Model Accuracy')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend(['Train', 'Validation'], loc='lower right')
    plt.show()

plot_training_history_accuracy(history_wm)

Точность обучения: 0,5350

Точность проверки: 0,5316

Ниже приведен код для набора данных Red Wine.

history_rm = nn_model.fit(x_train_rm_sc, 
                            y_train_rm_cat, 
                            epochs=epochs_, 
                            verbose=0,
                            validation_data=(x_test_rm_sc, y_test_rm_cat), 
                            callbacks=[lr_schedule])

final_train_accuracy_rm = history_rm .history['accuracy'][-1]
final_val_accuracy_rm = history_rm .history['val_accuracy'][-1]
print(f"Training Accuracy: {final_train_accuracy_rm:.4f}")
print(f"Validation Accuracy: {final_val_accuracy_rm:.4f}")
plot_training_history_loss(history_rm)
plot_training_history_accuracy(history_rm)

Точность обучения: 0,6036

Точность проверки: 0,5875

Сводка

Оценка превосходства вина: исследование, прогнозирование и внедрение

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

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

Время признания: я должен признать, что этот метод поиска вин с высокими оценками сработал для меня, хотя он и немного субъективен. Но есть одна загвоздка: я рассматриваю только те вина, которые получили рейтинг. Из-за этого недостатка мне хотелось бы попробовать фантастические вина из мест, которые не получили отзывов модных (и дорогих) критиков.

Это заставило меня задуматься: существует ли способ более систематично оценивать вина? Возможно ли создать автоматизированный метод оценки вин?

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

Набор данных и функции

Набор данных, использованный в этом исследовании, был получен из репозитория машинного обучения UCI [ссылка]. Набор данных включает вина из Минью, Португалия, с особым упором на два различных варианта: красные и белые вина Виньо Верде. Набор данных состоит из двух подмножеств, каждое из которых относится к одному из вариантов. В этих подмножествах имеется одиннадцать переменных, охватывающих как физико-химические характеристики (описанные в таблице ниже), так и показатель сенсорного качества, который оценивается по шкале от 0 до 10. Примечательно, что набор данных не включает информацию о типах винограда, марках вина. , или цены продажи вина.

Я провел исследовательский анализ данных (EDA) и вот что обнаружил:

Одним из примечательных результатов является то, что атрибутом, наиболее сильно коррелирующим с целевой переменной «качество», является «алкоголь», имеющий коэффициент корреляции 0,48.

Была выявлена ​​заметная положительная корреляция со значениями 0,23 для «лимонной кислоты», 0,25 для «сульфатов» и 0,12 для «фиксированной кислотности». Это говорит о том, что вина с повышенным уровнем фиксированной кислотности часто соответствуют повышенному уровню лимонной кислоты и сульфатов.

И наоборот, наиболее существенная отрицательная корреляция -0,39 была выявлена ​​​​с «летучей кислотностью», тогда как корреляция -0,19 характерна для «общего диоксида серы». Это указывает на то, что вина, характеризующиеся более высоким уровнем фиксированной кислотности, имеют тенденцию демонстрировать более низкие значения летучей кислотности и общего диоксида серы.

Диаграмма рассеяния, изображающая взаимосвязь между «фиксированной кислотностью» и «лимонной кислотой», дает ценную информацию о том, как эти два атрибута взаимодействуют в наборе данных.

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

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

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

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

Модели машинного обучения

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

- K-ближайшие соседи (KNN): 99,4%
- Логистическая регрессия (LR): 99,4%
- Наивный байесовский метод (NB): 96,6%
- Классификатор повышения градиента (GBC): 99,4 %
- Классификатор опорных векторов (SVC): 99,6%
- Классификатор случайного леса (RFC): 99,5%
- Классификатор дерева решений (DT): 98,0%

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

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

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

Модель глубокой нейронной сети

Я разработал и построил собственную модель глубокой нейронной сети (DNN), специально разработанную для этого набора данных. Кроме того, я настроил скорость обучения, чтобы она лучше подходила для этого конкретного набора данных. Визуальное представление кривой скорости обучения показывает, что минимальная точка кривой приходится на значение 10e-2.

def create_uncompiled_model(input_shape, num_classes):
    model = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=(input_shape,)),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dropout(0.3),
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])
    return model
def adjust_learning_rate(dataset, num_classes, epochs=100):
    x_train_wm_sc, y_train_wm_cat = dataset
    input_shape = x_train_wm_sc.shape[1]
    model = create_uncompiled_model(input_shape, num_classes)
    lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-6 * 10**(epoch / 20))
    optimizer = tf.keras.optimizers.Adam()
    model.compile(loss=tf.keras.losses.CategoricalCrossentropy(),
                  optimizer=optimizer,
                  metrics=["accuracy"])
    callbacks = [lr_schedule]
    history = model.fit(x_train_wm_sc, y_train_wm_cat, epochs=epochs, callbacks=callbacks)
    return history
# Define your dataset and num_classes
dataset = (x_train_wm_sc, y_train_wm_cat)
num_classes = 10
# Run the training with dynamic LR
lr_history = adjust_learning_rate(dataset, num_classes)
# Plot Learning Curve
learning_rates = lr_history.history['lr']
loss = lr_history.history['loss']
plt.semilogx(learning_rates, loss)
plt.xlabel('Learning Rate')
plt.ylabel('Loss')
plt.title('Learning Rate vs. Loss')
plt.grid()
plt.show()

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

# Define learning rate
learning_rates = [1e-2]
epochs_ = 70
lr_values = []
loss_values = []
for lr in learning_rates:
    nn_model = tf.keras.Sequential([
        tf.keras.layers.Input(shape=(x_train_wm_sc.shape[1],)),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(32, activation='relu'),
        tf.keras.layers.Dropout(0.3),
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])
    
    nn_model.compile(loss=tf.keras.losses.CategoricalCrossentropy(), 
                    optimizer=tf.keras.optimizers.Adam(learning_rate = lr),
                    metrics=['accuracy'])
    lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-6 * 10**(epoch / 20))
    history_wm = nn_model.fit(x_train_wm_sc, 
                           y_train_wm_cat, 
                           epochs=epochs_, 
                           verbose=0,
                           validation_data=(x_test_wm_sc, y_test_wm_cat), 
                           callbacks=[lr_schedule])
    
    lr_values.append(lr)
    loss_values.append(history_wm.history['loss'][-1])
    loss, accuracy = nn_model.evaluate(x_test_wm_sc, y_test_wm_cat, verbose=0)
    final_train_accuracy_wm = history_wm.history['accuracy'][-1]
    final_val_accuracy_wm = history_wm.history['val_accuracy'][-1]
    print(f"Training Accuracy: {final_train_accuracy_wm:.4f}")
    print(f"Validation Accuracy: {final_val_accuracy_wm:.4f}")
def plot_training_history_loss(history):
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model Loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend(['Train', 'Validation'], loc='upper right')
    plt.show()
# Plot
plot_training_history_loss(history_wm)
def plot_training_history_accuracy(history):
    # Plot training & validation accuracy values
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('Model Accuracy')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend(['Train', 'Validation'], loc='lower right')
    plt.show()
plot_training_history_accuracy(history_wm)

Точность обучения: 0,5350

Точность проверки: 0,5316

Ниже приведен код для набора данных Red Wine.

history_rm = nn_model.fit(x_train_rm_sc, 
                            y_train_rm_cat, 
                            epochs=epochs_, 
                            verbose=0,
                            validation_data=(x_test_rm_sc, y_test_rm_cat), 
                            callbacks=[lr_schedule])
final_train_accuracy_rm = history_rm .history['accuracy'][-1]
final_val_accuracy_rm = history_rm .history['val_accuracy'][-1]
print(f"Training Accuracy: {final_train_accuracy_rm:.4f}")
print(f"Validation Accuracy: {final_val_accuracy_rm:.4f}")
plot_training_history_loss(history_rm)
plot_training_history_accuracy(history_rm)

Точность обучения: 0,6036

Точность проверки: 0,5875

Сводка

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

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

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

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

Если вам интересно просмотреть код, он доступен в репозитории GitHub: sedeba19

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

Спасибо, что посвятили свое время прочтению этого.