Как упаковать приложение python в .exe файл?

У меня есть приложение, написанное с помощью PyQt5, которое прогнозирует урожайность. Я использую уже готовые модели машинного обучения и некоторые библиотеки. Мне нужно всё это завернуть в один .exe файл. Как я могу это сделать? Я так понимаю, что мне нужно каким-то образом подгрузить мои модели и библиотеки, но вот как это сделать, я не пойму.

Вот код:

import sys
import numpy as np
import joblib
from PyQt5.QtWidgets import (QApplication, QWidget, QLabel, QComboBox, 
                             QLineEdit, QPushButton, QVBoxLayout, QMessageBox)

# Загрузка модели
model_path = 'model/random_forest_model.pkl'
model_path2 = 'model/xgb_model.pkl'
rf_model = joblib.load(model_path)
rf_model2 = joblib.load(model_path2)

# Пример данных для выпадающих списков
countries = ['Albania', 'Country2', 'Country3']  
items = ['Maize', 'Wheat', 'Crops']

class CropYieldApp(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Прогнозирование урожайности с использованием машинного обучения')
        
        # Создание виджетов
        self.country_label = QLabel('Выберите страну:')
        self.country_combo = QComboBox()
        self.country_combo.addItems(countries)

        self.item_label = QLabel('Выберите растение:')
        self.item_combo = QComboBox()
        self.item_combo.addItems(items)

        self.pesticides_label = QLabel('Количество пестицидов:')
        self.pesticides_input = QLineEdit()

        self.avg_temp_label = QLabel('Средняя температура:')
        self.avg_temp_input = QLineEdit()

        self.rainfall_label = QLabel('Осадки:')
        self.rainfall_input = QLineEdit()

        self.predict_button = QPushButton('Получить прогноз')
        self.predict_button.clicked.connect(self.get_prediction)

        # Установка компоновки
        layout = QVBoxLayout()
        layout.addWidget(self.country_label)
        layout.addWidget(self.country_combo)
        layout.addWidget(self.item_label)
        layout.addWidget(self.item_combo)
        layout.addWidget(self.pesticides_label)
        layout.addWidget(self.pesticides_input)
        layout.addWidget(self.avg_temp_label)
        layout.addWidget(self.avg_temp_input)
        layout.addWidget(self.rainfall_label)
        layout.addWidget(self.rainfall_input)
        layout.addWidget(self.predict_button)

        self.setLayout(layout)

    def get_prediction(self):
        try:
            # Получение входных данных
            country = self.country_combo.currentText()
            item = self.item_combo.currentText()
            pesticides = float(self.pesticides_input.text())
            avg_temp = float(self.avg_temp_input.text())
            rainfall = float(self.rainfall_input.text())

            # Кодирование категориальных переменных 
            country_encoded = countries.index(country)
            item_encoded = items.index(item)

            # Подготовка входных данных
            input_data = np.array([[country_encoded, item_encoded, pesticides, avg_temp, rainfall]])

            # Прогноз
            prediction_rf = round((rf_model.predict(input_data)[0]) / 10000, 2)
            prediction_xgb = round((rf_model2.predict(input_data)[0]) / 10000, 2)

            # Отображение результата
            result_message = f"Прогноз (Random Forest): {prediction_rf} \n Прогноз (XGBoost): {prediction_xgb}"
            QMessageBox.information(self, 'Результаты прогноза', result_message)

        except ValueError:
            QMessageBox.warning(self, 'Ошибка ввода', 'Пожалуйста, введите корректные числовые значения.')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CropYieldApp()
    window.show()
    sys.exit(app.exec_())

В случае с моделями я использовал:

pyinstaller --onefile --windowed --add-data "model/random_forest_model.pkl;model" --add-data "model/xgb_model.pkl;model" my_app.py

Но после запуска ехе'шника вылезла такая ошибка:

Traceback (most recent call last):

      File "my_app.py", line 20, in <module>
      File "joblib\numpy_pickle.py", line 658, in load
      File "joblib\numpy_pickle.py", line 577, in _unpickle
      File "pickle.py", line 1213, in load
      File "pickle.py", line 1538, in load_stack_global
      File "pickle.py", line 1580, in find_class
      ModuleNotFoundError: No module named 'sklearn'

Ответы (1 шт):

Автор решения: erL1x

Проверьте my_app.py, к тому же, как сказал @Fox Fox, в PyQt5 вообще нет такого предмета как sklearn, поэтому советую найти его в коде, и заменить его на что либо, так как ModuleNotFoundError пишет, что в коде впринципе нет значения для модуля sklearn. Поэтому проверьте, установили ли вы значение для sklearn, если нет, то попробуйте проверить my_app.py

→ Ссылка