<jupyter_start><jupyter_text>Содержание1&nbsp;&nbsp;Описание проекта2&nbsp;&nbsp;Импортирование необходимых библиотек3&nbsp;&nbsp;Подготовка данных3.1&nbsp;&nbsp;Проверим корректность расчета параметра recovery3.1.1&nbsp;&nbsp;Вывод3.2&nbsp;&nbsp;Найдем все столбцы, которые есть в тренировочной выборке, но нет в тестовой3.2.1&nbsp;&nbsp;Более подробно изучим найденные столбцы3.2.2&nbsp;&nbsp;Выводы3.3&nbsp;&nbsp;Проверим возможность восстановления  параметра recovery3.4&nbsp;&nbsp;Обработаем пропуски4&nbsp;&nbsp;Анализ данных4.1&nbsp;&nbsp;Расчет концентрации металлов на разных этапах4.2&nbsp;&nbsp;График распределения размера гранул4.3&nbsp;&nbsp;Расчет суммарной концентрации4.4&nbsp;&nbsp;Удаление выбросов4.5&nbsp;&nbsp;График суммарной концентрации после удаления выбросов5&nbsp;&nbsp;Модель5.1&nbsp;&nbsp;Метрики5.2&nbsp;&nbsp;Инициализация pipeline5.3&nbsp;&nbsp;Обучение5.4&nbsp;&nbsp;Лучшие результаты на тренировочной выборке5.5&nbsp;&nbsp;Финальная ошибка на тестовой выборке5.6&nbsp;&nbsp;Инициализируем и обучим константную модель5.7&nbsp;&nbsp;Вывод после сравнения результатов6&nbsp;&nbsp;Вывод  Описание проектаПодготовьте прототип модели машинного обучения для «Цифры». Компания разрабатывает решения для эффективной работы промышленных предприятий.Модель должна предсказать коэффициент восстановления золота из золотосодержащей руды. В вашем распоряжении данные с параметрами добычи и очистки. Модель поможет оптимизировать производство, чтобы не запускать предприятие с убыточными характеристиками.Вам нужно:1. Подготовить данные;2. Провести исследовательский анализ данных;3. Построить и обучить модель.Чтобы выполнить проект, обращайтесь к библиотекам *pandas*, *matplotlib* и *sklearn.* Вам поможет их документация.  Импортирование необходимых библиотек<jupyter_code>import numpy as np
import pandas as pd

from sklearn.metrics import mean_absolute_error as MAE
from sklearn.pipeline import  make_pipeline
from sklearn.impute import KNNImputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
from sklearn.metrics import make_scorer
from sklearn.dummy import DummyRegressor
import seaborn as sns

import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)<jupyter_output><empty_output><jupyter_text>Подготовка данных<jupyter_code>test_frame = pd.read_csv("gold_recovery_test.csv")
train_frame = pd.read_csv("gold_recovery_train.csv")
full_frame = pd.read_csv("gold_recovery_full.csv")
train_frame = train_frame.replace(float("-inf"),np.nan)
test_frame = test_frame.replace(float("-inf"),np.nan)
train_frame.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 16860 entries, 0 to 16859
Data columns (total 87 columns):
 #   Column                                              Non-Null Count  Dtype  
---  ------                                              --------------  -----  
 0   date                                                16860 non-null  object 
 1   final.output.concentrate_ag                         16788 non-null  float64
 2   final.output.concentrate_pb                         16788 non-null  float64
 3   final.output.concentrate_sol                        16490 non-null  float64
 4   final.output.concentrate_au                         16789 non-null  float64
 5   final.output.recovery                               15339 non-null  float64
 6   final.output.tail_ag                                16794 non-null  float64
 7   final.output.tail_pb                                16677 non-null  float64
 8   final.output.tail_sol                               16715 non-null  float64
[...]<jupyter_text>Проверим корректность расчета параметра recovery<jupyter_code>def apply_recovery(row):
    (input_au,
     output_au,
     output_tail) = (row["rougher.input.feed_au"],
                     row["rougher.output.concentrate_au"],
                     row["rougher.output.tail_au"])
    recovery_metric = (((output_au) * ((input_au) - (output_tail)))/
                       (((input_au) * ((output_au) - (output_tail))))) * 100
    return recovery_metric
test = train_frame.dropna(subset = ["rougher.input.feed_au",
                                    "rougher.output.concentrate_au",
                                    "rougher.output.tail_au",
                                    "rougher.output.recovery"],axis = 0).apply(
                                                                        apply_recovery,axis = 1)
MAE(train_frame.dropna(subset = ["rougher.input.feed_au",
                                    "rougher.output.concentrate_au",
                                    "rougher.output.tail_au",
                                    "rougher.output.recovery"])["rougher.output.recovery"],
                       test)<jupyter_output><empty_output><jupyter_text>ВыводПараметр recovery в train рассчитаны верно   Найдем все столбцы, которые есть в тренировочной выборке, но нет в тестовой<jupyter_code>import collections
step = collections.Counter()
type_step = collections.Counter()
data = collections.Counter()
list_columns = [i for i in train_frame.columns if i not in test_frame.columns]
for i in list_columns:
    words = list(map(str,i.split(".")))
    step[words[0]] += 1
    type_step[words[1]] += 1
    data[words[2]] += 1
    
list_columns<jupyter_output><empty_output><jupyter_text>Более подробно изучим найденные столбцы<jupyter_code>step,"\n",type_step,"\n",data<jupyter_output><empty_output><jupyter_text>Выводы Заметим, что из 34 пропущенных признака 30 относятся к параметрам продукта и только 4 к расчетным характеристикам  1. 9 пропущенных признаков этапа final, 8 primary_cleaner, 9 rougher, 4 secondary_cleaner относятся к параметрам продукта1. 4 пропущенных признака этапа rougher относятся к расчетным характеристикам1. На всех этапах отсутствует информация о хвостовых частях1. Во всех этапах, кроме повторной очистки отсутствует информация о доле металлов 1. У финального этапа и этапа флотации отсутствуют признаки обогащения1. Так же отсутствуют данные о некоторых реагентах на этапе флотации  Проверим возможность восстановления  параметра recovery<jupyter_code>train_frame = train_frame.dropna(subset=["rougher.output.recovery","final.output.recovery"],axis = 0)<jupyter_output><empty_output><jupyter_text>Обработаем пропуски<jupyter_code>imputer = KNNImputer()
without_nan = pd.DataFrame(data = imputer.fit_transform(train_frame.drop(['date'],axis = 1)),
             columns= train_frame.drop(['date'],axis = 1).columns,
             index = train_frame.index)
test_frame = test_frame.dropna(subset= ['date'],axis = 0)
test_frame_for_target = test_frame.merge(full_frame.loc[:,['date',"rougher.output.recovery","final.output.recovery"]],on = 'date')
test_frame_for_target = test_frame_for_target.dropna(subset=["rougher.output.recovery","final.output.recovery"],axis = 0)
test_frame = test_frame_for_target.loc[:,test_frame.columns]
target_test_rougher = test_frame_for_target["rougher.output.recovery"]
target_test_final = test_frame_for_target["final.output.recovery"]
test_frame = test_frame.drop("date",axis =1)
imputer_test = KNNImputer()
test_without_nan = pd.DataFrame(data = imputer_test.fit_transform(test_frame),
             columns= test_frame.columns,
             index = test_frame.index)<jupyter_output><empty_output><jupyter_text>Анализ данных  Расчет концентрации металлов на разных этапах<jupyter_code>print("Концентрация до флотации")
print("Концентрация Серебра:{: 0.2f},Свинца:{: 0.2f},Золота:{: 0.2f}".
format(without_nan["rougher.input.feed_ag"].mean(),
without_nan["rougher.input.feed_pb"].mean(),
without_nan["rougher.input.feed_au"].mean()))
print()
print("Концентрация после флотации")
print("Коцентрация Серебра:{: 0.2f},Свинца:{: 0.2f},Золота:{: 0.2f}".
format(without_nan["rougher.output.concentrate_ag"].mean(),
without_nan["rougher.output.concentrate_pb"].mean(),
without_nan["rougher.output.concentrate_au"].mean()))
print()
print("Концентрация после первичной очистки")
print("Концентрация Серебра:{: 0.2f},Свинца:{: 0.2f},Золота:{: 0.2f}".
format(without_nan["primary_cleaner.output.concentrate_ag"].mean(),
without_nan["primary_cleaner.output.concentrate_pb"].mean(),
without_nan["primary_cleaner.output.concentrate_au"].mean()))
print()
print("Концентрация поле вторичной очистки")
print("Концентрация Серебра:{: 0.2f},Свинца:{: 0.2f},Золота:{: 0.2f}".
format(without_nan["final.output.concentrate_ag"].mean(),
without_nan["final.output.concentrate_pb"].mean(),
without_nan["final.output.concentrate_au"].mean()))<jupyter_output>Концентрация до флотации
Концентрация Серебра: 8.58,Свинца: 3.52,Золота: 7.87

Концентрация после флотации
Коцентрация Серебра: 11.78,Свинца: 7.66,Золота: 19.44

Концентрация после первичной очистки
Концентрация Серебра: 8.20,Свинца: 9.58,Золота: 32.39

Концентрация поле вторичной очистки
Концентрация Серебра: 5.14,Свинца: 10.13,Золота: 44.00<jupyter_text>По представленным выше данным отчетливо видно, что с каждым этапом увеличивается концентрация золата и свинца, так же можно заметить уменьшение концентрации серебра  График распределения размера гранул<jupyter_code>for frame,name in zip([without_nan,test_without_nan],
                       ["train","test"]):
    subset = frame["rougher.input.feed_size"]

    sns.distplot(subset, hist = False, kde = True,
                 label = name)
plt.legend(prop={'size': 10}, title = 'Frame')
plt.title('Размер гранул')<jupyter_output><empty_output><jupyter_text>Мы можем видеть, что распределения немного отличаются. В тренировочной выборке преобладают значения около порога 50 и выше, в то же время как в тестовой выборке достаточно большое количество объектов сконцентрированы до порога 50. Так же это заметно и на средних значениях, среднее значение тренировочной выборки на 3 пункта больше среднего по тестовой выборке  Расчет суммарной концентрации<jupyter_code>def summary_of_concentarution(row):
    list_of_steps = ["rougher","primary_cleaner","final"]
    input_feed_au = row["rougher.input.feed_au"]
    input_feed_ag = row["rougher.input.feed_ag"]
    input_feed_pb = row["rougher.input.feed_pb"]
    input_feed_sol = row["rougher.input.feed_sol"]
    out_rougher = []
    out_primary_cleaner = []
    out_final = []
    list_of_arrays =[out_rougher,out_primary_cleaner,out_final]
    for step,array in zip(list_of_steps,list_of_arrays):
        array.append(row[step+".output.concentrate_au"])
        array.append(row[step+".output.concentrate_ag"])
        array.append(row[step+".output.concentrate_pb"])
        array.append(row[step+".output.concentrate_sol"])
    sum_before_steps = input_feed_ag+input_feed_au+input_feed_pb+input_feed_sol
    sum_rougher = sum(out_rougher)
    sum_primary = sum(out_primary_cleaner)
    sum_final = sum(out_final)
    return pd.Series([sum_before_steps,sum_rougher,sum_primary,sum_final])
    
sum_values = without_nan.apply(summary_of_concentarution,axis = 1)
sum_values.columns = ["before_rougher","rougher","primary_cleaner","final"]
sum_values
fig,ax = plt.subplots(4,1,figsize = (20,30))

ax[0].hist(sum_values["before_rougher"],bins = 40)
ax[1].hist(sum_values["rougher"],bins = 40)
ax[2].hist(sum_values["primary_cleaner"],bins = 40)
ax[3].hist(sum_values["final"],bins = 40)
ax[0].set_xlabel("Сумма долей компонентов")
ax[1].set_xlabel("Сумма долей компонентов")
ax[2].set_xlabel("Сумма долей компонентов")
ax[3].set_xlabel("Сумма долей компонентов")
ax[0].set_title("Концентрация компонентов до флотации")
ax[1].set_title("Концентрация компонентов после флотации")
ax[2].set_title("Концентрация компонентов после первичной очистки")
ax[3].set_title("Концентрация компонентов после финального этапа")
plt.show()<jupyter_output><empty_output><jupyter_text>Можно заметить, что во всех распределениях присутствует пик около нулевого значения. Он очень далек от общего распределения, его следует удалить. Так же это стоит проделать и в тестовой выборке, так они носят характер выбросов   Удаление выбросов<jupyter_code>without_nan = without_nan.drop(index = without_nan[without_nan["rougher.input.feed_au"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.input.feed_ag"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.input.feed_pb"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.input.feed_sol"] < 1].index,
                               axis = 0)


without_nan = without_nan.drop(index = without_nan[without_nan["rougher.output.concentrate_au"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.output.concentrate_ag"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.output.concentrate_pb"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["rougher.output.concentrate_sol"] < 1].index,
                               axis = 0)

without_nan = without_nan.drop(index = without_nan[without_nan["primary_cleaner.output.concentrate_au"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["primary_cleaner.output.concentrate_ag"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["primary_cleaner.output.concentrate_pb"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["primary_cleaner.output.concentrate_sol"] < 1].index,
                               axis = 0)

without_nan = without_nan.drop(index = without_nan[without_nan["final.output.concentrate_au"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["final.output.concentrate_ag"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["final.output.concentrate_pb"] < 1].index,
                               axis = 0)
without_nan = without_nan.drop(index = without_nan[without_nan["final.output.concentrate_sol"] < 1].index,
                               axis = 0)<jupyter_output><empty_output><jupyter_text>График суммарной концентрации после удаления выбросов<jupyter_code>fig,ax = plt.subplots(4,1,figsize = (20,30))

ax[0].hist(sum_values["before_rougher"],bins = 40)
ax[1].hist(sum_values["rougher"],bins = 40)
ax[2].hist(sum_values["primary_cleaner"],bins = 40)
ax[3].hist(sum_values["final"],bins = 40)
ax[0].set_xlabel("Сумма долей компонентов")
ax[1].set_xlabel("Сумма долей компонентов")
ax[2].set_xlabel("Сумма долей компонентов")
ax[3].set_xlabel("Сумма долей компонентов")
ax[0].set_title("Концентрация компонентов до флотации")
ax[1].set_title("Концентрация компонентов после флотации")
ax[2].set_title("Концентрация компонентов после первичной очистки")
ax[3].set_title("Концентрация компонентов после финального этапа")
plt.show()
test_frame = test_frame.drop(index = test_frame[test_frame["rougher.input.feed_au"] < 1].index,
                               axis = 0)
test_frame = test_frame.drop(index = test_frame[test_frame["rougher.input.feed_ag"] < 1].index,
                               axis = 0)
test_frame = test_frame.drop(index = test_frame[test_frame["rougher.input.feed_pb"] < 1].index,
                               axis = 0)
test_frame = test_frame.drop(index = test_frame[test_frame["rougher.input.feed_sol"] < 1].index,
                               axis = 0)

train_features_dataset_rougher = without_nan.loc[:,test_frame.columns]
train_target_dataset_rougher = without_nan['rougher.output.recovery']
train_features_dataset_final = train_features_dataset_rougher 
train_target_dataset_final = without_nan['final.output.recovery']<jupyter_output><empty_output><jupyter_text>Модель  Метрики<jupyter_code>def sMAPE(y_true,y_pred):
    error = np.mean(abs(y_true - y_pred)/((abs(y_true)+abs(y_pred))/2))*100
    return error
def final_sMAPE(sMAPE_rougher,sMAPE_final):
    return (0.25*sMAPE_rougher + 0.75*sMAPE_final)
custom_score = make_scorer(sMAPE,greater_is_better=False)<jupyter_output><empty_output><jupyter_text>Инициализация pipeline<jupyter_code>model = make_pipeline(StandardScaler(),RandomForestRegressor())
model2 = make_pipeline(StandardScaler(),DecisionTreeRegressor())


# Инициализация параметров для GridSearchCV
params_RF = {"randomforestregressor__n_estimators":[5,100],
             "randomforestregressor__max_depth":[1,10]}
params_DT= {"decisiontreeregressor__max_depth":[1,10]}
grid_rougher = GridSearchCV(model,param_grid = params_RF,scoring=custom_score)
grid_final = GridSearchCV(model,param_grid = params_RF,scoring=custom_score)
grid_rougher_DT = GridSearchCV(model2,param_grid = params_DT,scoring=custom_score)
grid_final_DT = GridSearchCV(model2,param_grid = params_DT,scoring=custom_score)<jupyter_output><empty_output><jupyter_text>Обучение<jupyter_code>grid_rougher.fit(train_features_dataset_rougher,train_target_dataset_rougher)
grid_final.fit(train_features_dataset_final,train_target_dataset_final)
grid_rougher_DT.fit(train_features_dataset_rougher,train_target_dataset_rougher)
grid_final_DT.fit(train_features_dataset_final,train_target_dataset_final)
print("Лучшие модели")
print(grid_rougher.best_estimator_)
print(grid_rougher.best_estimator_)
print(grid_rougher_DT.best_estimator_)
print(grid_final_DT.best_estimator_)
best_score_rougher = grid_rougher.best_score_
best_score_final = grid_final.best_score_
best_score_rougher_DT = grid_rougher_DT.best_score_
best_score_final_DT = grid_final_DT.best_score_<jupyter_output><empty_output><jupyter_text>Определим лучшую модель для каждого целевого признака<jupyter_code>print("rougher")
print("RandomForest",best_score_rougher,"DecisionTree",best_score_rougher_DT)
print("final")
print("RandomForest",best_score_final,"DecisionTree",best_score_final_DT)<jupyter_output>rougher
RandomForest -6.532688829277843 DecisionTree -7.962795330896381
final
RandomForest -9.362622857762606 DecisionTree -9.50283445513263<jupyter_text>Видно, что лучше всего справляется RandomForest, так что как лучшую модель возьмем именно его  Лучшие результаты на тренировочной выборке Финальный sMAPE рандомного леса<jupyter_code>final_sMAPE(best_score_rougher,best_score_final)<jupyter_output><empty_output><jupyter_text>Финальный sMAPE решающего дерева<jupyter_code>final_sMAPE(best_score_rougher_DT,best_score_final_DT)<jupyter_output><empty_output><jupyter_text>Наименьшую ошибку мы получили при использовании рандомного леса<jupyter_code>rogher_test = grid_rougher.predict(test_without_nan)
final_test = grid_final.predict(test_without_nan)<jupyter_output><empty_output><jupyter_text>Финальная ошибка на тестовой выборке<jupyter_code>final_sMAPE(sMAPE(target_test_rougher,rogher_test),sMAPE(target_test_final,final_test))<jupyter_output><empty_output><jupyter_text>Инициализируем и обучим константную модель<jupyter_code>base = DummyRegressor(strategy="median")
base_final = DummyRegressor(strategy="median")
base.fit(train_features_dataset_rougher,train_target_dataset_rougher)
base_final.fit(train_features_dataset_final,train_target_dataset_final)<jupyter_output><empty_output><jupyter_text>Предскажем метки<jupyter_code>base_rougher = base.predict(test_without_nan)
base_final_pred = base_final.predict(test_without_nan)
final_sMAPE(sMAPE(target_test_rougher,base_rougher),sMAPE(target_test_final,base_final_pred))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10624749298034497, 'fraction_numerical': 0.020908543922984357, 'mean_word_length': 4.821657910099241, 'pattern_counts': {'":': 3, '<': 107, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '22', 'dir': 'jupyter-structured-clean-dedup', 'id': '459115', 'license': 'MIT', 'n_tokens_mistral': 7406, 'n_tokens_neox': 7663, 'n_words': 1096, 'path': 'gold_recovery.ipynb', 'repo_name': 'Stuksus/Gold-recovery', 'size': '19944'}