<jupyter_start><jupyter_text>Курсовой проект "Прогнозирование цен на недвижимость" Задание для курсового проектаДанные:https://www.kaggle.com/c/real-estate-price-prediction-moscow/leaderboardМой аккаунт:https://www.kaggle.com/alexartwwwМетрика:R2 - коэффициент детерминации (sklearn.metrics.r2_score)Сдача проекта:1. Сдать проект нужно в течение 7 дней после окончания последнего вебинара.2. Прислать в раздел Задания Урока 10 ("Вебинар. Консультация по итоговому проекту") ссылку на ноутбук в github или public kaggle notebook.3. Необходимо получить R2 > 0.6 на Private Leaderboard.4. Укажите свой ник на kaggle Примечание:Все файлы csv должны содержать названия полей (header - то есть "шапку"),разделитель - запятая. В файлах не должны содержаться индексы из датафрейма.____________Рекомендации для файла с кодом (ipynb):1. Файл должен содержать заголовки и комментарии2. Повторяющиеся операции лучше оформлять в виде функций3. По возможности добавлять графики, описывающие данные (около 3-5)4. Добавлять только лучшую модель, то есть не включать в код все варианты решения проекта5. Скрипт проекта должен отрабатывать от начала и до конца (от загрузки данных до выгрузки предсказаний)6. Весь проект должен быть в одном скрипте (файл ipynb).7. При использовании статистик (среднее, медиана и т.д.) в качестве признаков, лучше считать их на трейне, и потом на валидационных и тестовых данных не считать статистики заново, а брать их с трейна.8. Проект должен полностью отрабатывать за разумное время (не больше 10 минут), поэтому в финальный вариант лучше не включать GridSearch с перебором большого количества сочетаний параметров.  **План занятия*** [Загрузка данных](load)* [1. EDA](eda)* [2. Обработка выбросов](outlier)* [3. Обработка пропусков](nan)* [4. Построение новых признаков](feature)* [5. Отбор признаков](feature_selection)* [6. Разбиение на train и test](split)* [7. Построение модели](modeling)* [8. Прогнозирование на тестовом датасете](prediction) **Подключение библиотек и скриптов**<jupyter_code># This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('./input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
import numpy as np
import pandas as pd
import random

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score as r2
from sklearn.model_selection import KFold, GridSearchCV

from datetime import datetime

import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
matplotlib.rcParams.update({'font.size': 14})
def evaluate_preds(train_true_values, train_pred_values, test_true_values, test_pred_values):
    print("Train R2:\t" + str(round(r2(train_true_values, train_pred_values), 5)))
    print("Test R2:\t" + str(round(r2(test_true_values, test_pred_values), 5)))
    
    plt.figure(figsize=(18,10))
    
    plt.subplot(121)
    sns.scatterplot(x=train_pred_values, y=train_true_values)
    plt.xlabel('Predicted values')
    plt.ylabel('True values')
    plt.title('Train sample prediction')
    
    plt.subplot(122)
    sns.scatterplot(x=test_pred_values, y=test_true_values)
    plt.xlabel('Predicted values')
    plt.ylabel('True values')
    plt.title('Test sample prediction')

    plt.show()<jupyter_output><empty_output><jupyter_text>**Пути к директориям и файлам**<jupyter_code>TRAIN_DATASET_PATH = './input/real-estate-price-prediction-moscow/train.csv'
TEST_DATASET_PATH = './input/real-estate-price-prediction-moscow/test.csv'<jupyter_output><empty_output><jupyter_text>Загрузка данных  **Описание датасета*** **Id** - идентификационный номер квартиры* **DistrictId** - идентификационный номер района* **Rooms** - количество комнат* **Square** - площадь* **LifeSquare** - жилая площадь* **KitchenSquare** - площадь кухни* **Floor** - этаж* **HouseFloor** - количество этажей в доме* **HouseYear** - год постройки дома* **Ecology_1, Ecology_2, Ecology_3** - экологические показатели местности* **Social_1, Social_2, Social_3** - социальные показатели местности* **Healthcare_1, Helthcare_2** - показатели местности, связанные с охраной здоровья* **Shops_1, Shops_2** - показатели, связанные с наличием магазинов, торговых центров* **Price** - цена квартиры<jupyter_code>train_df = pd.read_csv(TRAIN_DATASET_PATH)
train_df.tail()
train_df.dtypes
test_df = pd.read_csv(TEST_DATASET_PATH)
test_df.tail()
print('Строк в трейне:', train_df.shape[0])
print('Строк в тесте', test_df.shape[0])
train_df.shape[1] - 1 == test_df.shape[1]<jupyter_output><empty_output><jupyter_text>Приведение типов<jupyter_code>train_df.dtypes
train_df['Id'] = train_df['Id'].astype(str)
train_df['DistrictId'] = train_df['DistrictId'].astype(str)<jupyter_output><empty_output><jupyter_text>1. EDA  Делаем EDA для:- Исправления выбросов- Заполнения NaN- Идей для генерации новых фич **Целевая переменная**<jupyter_code>plt.figure(figsize = (10, 5))

train_df['Price'].hist(bins=20)
plt.ylabel('Count')
plt.xlabel('Price')

plt.title('Target distribution')
plt.show()<jupyter_output><empty_output><jupyter_text>**Количественные переменные**<jupyter_code>train_df.describe()<jupyter_output><empty_output><jupyter_text>Анализ данных по колонкам== **Rooms**<jupyter_code>train_df['Rooms'].value_counts()<jupyter_output><empty_output><jupyter_text>* Заменяем 0 и NaN на 1* удаляем записи больше 6 комнат<jupyter_code>def fix_rooms(X):
    X.loc[(X['Rooms'] == 0) | (X['Rooms'].isna()), 'Rooms'] = 1
    X.drop(X.loc[(X['Rooms'] > 6)].index, inplace=True)
    return X

df = fix_rooms(train_df)
df['Rooms'].value_counts()<jupyter_output><empty_output><jupyter_text>**Square**<jupyter_code>train_df['Square'].describe()<jupyter_output><empty_output><jupyter_text>Видно, что есть проблемы, поэтому отрежем по 10% с начала и с конца распределения.NaN заменим средним<jupyter_code>def fix_square(X, cut_percent=0.1):
    min = X['Square'].quantile(cut_percent)
    max = X['Square'].quantile(1 - cut_percent)
    X.loc[(X['Square'].isna()), 'Square'] = X['Square'].mean()
    X.drop(X.loc[(X['Square'] < min) | (X['Square'] > max)].index, inplace=True)
    return X

df = fix_square(train_df)
df['Square'].describe()<jupyter_output><empty_output><jupyter_text>**LifeSquare**<jupyter_code>train_df['LifeSquare'].describe()<jupyter_output><empty_output><jupyter_text>Аналогично, есть проблемы. Отрезаем по 10%, NaN заменяем на среднее. Если жилая площадь больше общей - удаляем.<jupyter_code>def fix_life_square(X, cut_percent=0.1):
    min = X['LifeSquare'].quantile(cut_percent)
    max = X['LifeSquare'].quantile(1 - cut_percent)
    X.loc[(X['LifeSquare'].isna()), 'LifeSquare'] = X['LifeSquare'].mean()
    X.drop(X.loc[(X['LifeSquare'] < min) | (X['LifeSquare'] > max) | (X['LifeSquare'] > X['Square'])].index, inplace=True)
    return X

df = fix_life_square(train_df)
df['LifeSquare'].describe()<jupyter_output><empty_output><jupyter_text>**KitchenSquare**<jupyter_code>train_df['KitchenSquare'].describe()<jupyter_output><empty_output><jupyter_text>Заменяем меньше 6 на 6. Если жилая площадь больше общей - удаляем.<jupyter_code>def fix_kitchen_square(X, low_fix=6):
    X.loc[(X['KitchenSquare'].isna()) | (X['KitchenSquare'] < low_fix), 'KitchenSquare'] = low_fix
    X.drop(X.loc[(X['KitchenSquare'] > X['Square'])].index, inplace=True)
    return X

df = fix_kitchen_square(train_df)
df['KitchenSquare'].describe()<jupyter_output><empty_output><jupyter_text>**HouseFloor**<jupyter_code>train_df['HouseFloor'].describe()<jupyter_output><empty_output><jupyter_text>Есть проблема с нулевым этажом. Заменим его на самый популярный<jupyter_code>def fix_house_floor(X):
    X.loc[(X['HouseFloor'].isna()) | (X['HouseFloor'] < 1), 'HouseFloor'] = X['HouseFloor'].mode()
    return X

df = fix_house_floor(train_df)
df['HouseFloor'].describe()<jupyter_output><empty_output><jupyter_text>**Floor**<jupyter_code>train_df['Floor'].describe()<jupyter_output><empty_output><jupyter_text>Проблем вроде нет, но мы добавим фильтры на NaN, меньше 1 и больше чем этажей в доме с заменой на самый популярный<jupyter_code>def fix_floor(X):
    X.loc[(X['Floor'].isna()) | (X['Floor'] < 1) | (X['Floor'] > X['HouseFloor']), 'Floor'] = X['Floor'].mode()
    return X

df = fix_floor(train_df)
df['Floor'].describe()<jupyter_output><empty_output><jupyter_text>**HouseYear**<jupyter_code>train_df['HouseYear'].describe()<jupyter_output><empty_output><jupyter_text>Проблемы со значениями больше текущего года. Больше текущего года NaN заменим на самый популярный<jupyter_code>def fix_house_year(X):
    X.loc[(X['HouseYear'].isna()) | (X['HouseYear'] > datetime.today().year), 'HouseYear'] = X['HouseYear'].mode()
    return X

df = fix_house_year(train_df)
df['HouseYear'].describe()<jupyter_output><empty_output><jupyter_text>**Ecology_1**<jupyter_code>train_df['Ecology_1'].describe()<jupyter_output><empty_output><jupyter_text>На вид проблем нет, но если будут пропуски заменим на средние по району. Если в районе все NaN - просто на среднее.<jupyter_code>def fix_by_districts_mean(X, column):
    df = X.groupby('DistrictId')
    means = df[column].mean().to_dict()
    for DistrictId in means:
        X.loc[(X[column].isna()) & (X['DistrictId'] == DistrictId), column] = means[DistrictId] if not np.isnan(means[DistrictId]) else X[column].mode()
    return X

df = fix_by_districts_mean(df, 'Ecology_1')
df['Ecology_1'].describe()<jupyter_output><empty_output><jupyter_text>**Healthcare_1**<jupyter_code>train_df['Healthcare_1'].describe()<jupyter_output><empty_output><jupyter_text>То же что и Ecology_1<jupyter_code>df = fix_by_districts_mean(df, 'Healthcare_1')
df['Healthcare_1'].describe()<jupyter_output><empty_output><jupyter_text>**Ecology_2, Ecology_3, Shops_2** Просто автозамена по словарю<jupyter_code>def fix_by_dict(X, column, replace):
    X[column] = X[column].replace(replace)
    return X


# binary_to_numbers = {'A': 0, 'B': 1}

# df = fix_by_dict(train_df, 'Ecology_2', binary_to_numbers)
# df = fix_by_dict(df, 'Ecology_3', binary_to_numbers)
# df = fix_by_dict(df, 'Shops_2', binary_to_numbers)

# df['Shops_2'].value_counts()<jupyter_output><empty_output><jupyter_text>**Social_1, Social_2, Social_3, Helthcare_2, Shops_1**<jupyter_code>def fix_by_mode(X, column):
    X.loc[(X[column].isna()), column] = X[column].mode()
    return X

# df = fix_by_mode(train_df, 'Social_1')
# df = fix_by_mode(train_df, 'Social_2')
# df = fix_by_mode(train_df, 'Social_3')
# df = fix_by_mode(train_df, 'Helthcare_2')
# df = fix_by_mode(train_df, 'Shops_1')<jupyter_output><empty_output><jupyter_text>DataPreprocessing class==<jupyter_code>class DataDrop:
    def drop(self, X):
        X = self.drop_rooms(X)
        X = self.drop_square(X)
        X = self.drop_life_square(X)
        X = self.drop_kitchen_square(X)
        return X

    def drop_rooms(self, X):
        X.drop(X.loc[(X['Rooms'] > 6)].index, inplace=True)
        return X

    def drop_square(self, X, cut_percent=0.1):
        min = X['Square'].quantile(cut_percent)
        max = X['Square'].quantile(1 - cut_percent)
        X.drop(X.loc[(X['Square'] < min) | (X['Square'] > max)].index, inplace=True)
        return X

    def drop_life_square(self, X, cut_percent=0.1):
        min = X['LifeSquare'].quantile(cut_percent)
        max = X['LifeSquare'].quantile(1 - cut_percent)
        X.drop(X.loc[(X['LifeSquare'] < min) | (X['LifeSquare'] > max) | (X['LifeSquare'] > X['Square'])].index, inplace=True)
        return X

    def drop_kitchen_square(self, X):
        X.drop(X.loc[(X['KitchenSquare'] > X['Square'])].index, inplace=True)
        return X
class DataPreprocessing:
    """Подготовка исходных данных"""

    def __init__(self):
        """Параметры класса"""
        self.districts = None
        self.means = None
        self.modes = None
        self.districtMeans = None
        
    def fit(self, X):
        """Сохранение статистик"""
        self.means = X.mean()
        self.modes = {}
        for column in X.columns:
            self.modes[column] = X[column].mode()[0]
        self.districtMeans = {}
        self.districts = X['DistrictId'].unique()
        df = X.groupby('DistrictId')
        for column in ['Ecology_1', 'Healthcare_1']:
            self.districtMeans[column] = df[column].mean().to_dict()
        self.binary_to_numbers = {'A': 0, 'B': 1}

    def transform(self, X):
        """Трансформация данных"""

        X = self.fix_rooms(X)
        X = self.fix_square(X)
        X = self.fix_life_square(X)
        X = self.fix_kitchen_square(X)
        X = self.fix_house_floor(X)
        X = self.fix_floor(X)
        X = self.fix_house_year(X)
        X = self.fix_by_districts_mean(X, 'Ecology_1')
        X = self.fix_by_districts_mean(X, 'Healthcare_1')
        X = self.fix_by_dict(X, 'Ecology_2', self.binary_to_numbers)
        X = self.fix_by_dict(X, 'Ecology_3', self.binary_to_numbers)
        X = self.fix_by_dict(X, 'Shops_2', self.binary_to_numbers)
        X = self.fix_by_mode(X, 'Social_1')
        X = self.fix_by_mode(X, 'Social_2')
        X = self.fix_by_mode(X, 'Social_3')
        X = self.fix_by_mode(X, 'Helthcare_2')
        X = self.fix_by_mode(X, 'Shops_1')
        return X
  
    def fix_rooms(self, X):
        X.loc[(X['Rooms'] == 0) | (X['Rooms'].isna()), 'Rooms'] = 1
        return X

    def fix_square(self, X):
        X.loc[(X['Square'].isna()), 'Square'] = X['Square'].mean()
        return X

    def fix_life_square(self, X):
        X.loc[(X['LifeSquare'].isna()), 'LifeSquare'] = X['LifeSquare'].mean()
        return X

    def fix_kitchen_square(self, X, low_fix=6):
        X.loc[(X['KitchenSquare'].isna()) | (X['KitchenSquare'] < low_fix), 'KitchenSquare'] = low_fix
        return X

    def fix_house_floor(self, X):
        X.loc[(X['HouseFloor'].isna()) | (X['HouseFloor'] < 1), 'HouseFloor'] = X['HouseFloor'].mode()[0]
        return X

    def fix_floor(self, X):
        X.loc[(X['Floor'].isna()) | (X['Floor'] < 1) | (X['Floor'] > X['HouseFloor']), 'Floor'] = X['Floor'].mode()[0]
        return X

    def fix_house_year(self, X):
        X.loc[(X['HouseYear'].isna()) | (X['HouseYear'] > datetime.today().year), 'HouseYear'] = X['HouseYear'].mode()[0]
        return X

    def fix_by_districts_mean(self, X, column):
#         if column in self.districtMeans:
#             for DistrictId in self.districts:
#                 if DistrictId in self.districtMeans[column] and not np.isnan(self.districtMeans[column][DistrictId]):
#                     X.loc[(X[column].isna()) & (X['DistrictId'] == DistrictId), column] = self.districtMeans[column][DistrictId]
        X.loc[(X[column].isna()), column] = X[column].mean()
        return X

    def fix_by_dict(self, X, column, replace):
        X[column] = X[column].replace(replace)
        X.loc[(X[column].isna()), column] = X[column].mode()[0]
        return X

    def fix_by_mode(self, X, column):
        X.loc[(X[column].isna()), column] = X[column].mode()[0]
        return X<jupyter_output><empty_output><jupyter_text>4. Построение новых признаков<jupyter_code>class FeatureGenetator():
    """Генерация новых фич"""
    
    def __init__(self):
        self.DistrictId_counts = None
        self.med_price_by_district = None
        self.med_price_by_floor_year = None
        self.house_year_max = None
        self.floor_max = None
        self.district_size = None
        
    def fit(self, X, y=None):
        X = X.copy()
        # Target encoding
        ## District, Rooms
        df = X.copy()
        # DistrictID
        self.district_size = X['DistrictId'].value_counts().reset_index() \
                               .rename(columns={'index':'DistrictId', 'DistrictId':'DistrictSize'})
        if y is not None:
            df['Price'] = y.values
            
            self.med_price_by_district = df.groupby(['DistrictId', 'Rooms'], as_index=False).agg({'Price':'median'})\
                                            .rename(columns={'Price':'MedPriceByDistrict'})
            
            self.med_price_by_district_median = self.med_price_by_district['MedPriceByDistrict'].median()
            
        ## floor, year
        if y is not None:
            self.floor_max = df['Floor'].max()
            self.house_year_max = df['HouseYear'].max()
            df['Price'] = y.values
            df = self.floor_to_cat(df)
            df = self.year_to_cat(df)
            self.med_price_by_floor_year = df.groupby(['year_cat', 'floor_cat'], as_index=False).agg({'Price':'median'}).\
                                            rename(columns={'Price':'MedPriceByFloorYear'})
            self.med_price_by_floor_year_median = self.med_price_by_floor_year['MedPriceByFloorYear'].median()
        
    def transform(self, X):
        # DistrictId, IsDistrictLarge
        X = X.merge(self.district_size, on='DistrictId', how='left')
        
        X['new_district'] = 0
        X.loc[X['DistrictSize'].isna(), 'new_district'] = 1
        
        X['DistrictSize'].fillna(5, inplace=True)
        
        X['IsDistrictLarge'] = (X['DistrictSize'] > 100).astype(int)
        
        # More categorical features
        X = self.floor_to_cat(X)  # + столбец floor_cat
        X = self.floor_to_first_or_last(X)  # + столбец first_or_last
        X = self.year_to_cat(X)   # + столбец year_cat
        
        # Target encoding
        if self.med_price_by_district is not None:
            X = X.merge(self.med_price_by_district, on=['DistrictId', 'Rooms'], how='left')
            X['MedPriceByDistrict'].fillna(self.med_price_by_district_median, inplace=True)
            
        if self.med_price_by_floor_year is not None:
            X = X.merge(self.med_price_by_floor_year, on=['year_cat', 'floor_cat'], how='left')
            X['MedPriceByFloorYear'].fillna(self.med_price_by_floor_year_median, inplace=True)
        
        return X
    
    def floor_to_cat(self, X):
        bins = [0, 3, 5, 9, 15, self.floor_max]
        X['floor_cat'] = pd.cut(X['Floor'], bins=bins, labels=False)

        X['floor_cat'].fillna(-1, inplace=True) 
        return X

    def floor_to_first_or_last(self, X):
        X['floor_first_or_last'] = 0
        X.loc[(X['Floor'] == 1) | (X['Floor'] == X['HouseFloor']), 'floor_first_or_last'] = 1
        return X
     
    def year_to_cat(self, X):
        bins = [0, 1941, 1945, 1980, 2000, 2010, self.house_year_max]
        X['year_cat'] = pd.cut(X['HouseYear'], bins=bins, labels=False)

        X['year_cat'].fillna(-1, inplace=True)
        return X<jupyter_output><empty_output><jupyter_text>5. Отбор признаков<jupyter_code>feature_names = ['DistrictId', 'Rooms', 'Square', 'LifeSquare', 'KitchenSquare', 'Floor', 'HouseFloor', 'HouseYear',
                 'Ecology_1', 'Ecology_2', 'Ecology_3', 'Social_1', 'Social_2', 'Social_3',
                 'Healthcare_1', 'Helthcare_2', 'Shops_1', 'Shops_2']
new_feature_names = [
# Доп фичи все портят...
#                      'DistrictSize',
#                      'new_district',
#                      'IsDistrictLarge',
#                      #'MedPriceByDistrict',
#                      'MedPriceByFloorYear',
#                      'floor_cat',
#                      'floor_first_or_last',
#                      'year_cat'
                    ]

target_name = 'Price'<jupyter_output><empty_output><jupyter_text>6. Разбиение на train и test<jupyter_code>dropper = DataDrop()
train_df = pd.read_csv(TRAIN_DATASET_PATH)
# train_df = dropper.drop(train_df) # Дроппер все портит
test_df = pd.read_csv(TEST_DATASET_PATH)

X = train_df.drop(columns=target_name)
y = train_df[target_name]
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.33, shuffle=True, random_state=21)
preprocessor = DataPreprocessing()
preprocessor.fit(X_train)

X_train = preprocessor.transform(X_train)
X_valid = preprocessor.transform(X_valid)
test_df = preprocessor.transform(test_df)

X_train.shape, X_valid.shape, test_df.shape
features_gen = FeatureGenetator()
features_gen.fit(X_train, y_train)

X_train = features_gen.transform(X_train)
X_valid = features_gen.transform(X_valid)
test_df = features_gen.transform(test_df)

X_train.shape, X_valid.shape, test_df.shape
X_train = X_train[feature_names + new_feature_names]
X_valid = X_valid[feature_names + new_feature_names]
test_df = test_df[feature_names + new_feature_names]
X_train.isna().sum().sum(), X_valid.isna().sum().sum(), test_df.isna().sum().sum()
X_train.isna().sum()<jupyter_output><empty_output><jupyter_text>7. Построение модели    Подборка параметров<jupyter_code># x = [100,150,175,190,200,210,225,250,300,400,500]
# y = []
# for param in x:
#     rf_model = GradientBoostingRegressor(criterion='friedman_mse',
#                                             max_depth=4,
#                                             min_samples_leaf=0.0001,
#                                             random_state=42,
#                                             n_estimators=param)
#     rf_model.fit(X_train, y_train)
#     y_train_preds = rf_model.predict(X_train)
#     y_test_preds = rf_model.predict(X_valid)
#     y.append(r2(y_valid, y_test_preds))

# plt.plot(x, y)

# plt.show()<jupyter_output><empty_output><jupyter_text>**Обучение**<jupyter_code>rf_model_linear = LinearRegression()
rf_model_forest = RandomForestRegressor(
    random_state=21,
    criterion='mse',
    max_depth=None,
    min_samples_split = 2,
    min_samples_leaf = 1,
    min_weight_fraction_leaf = 0.0,
    max_features = 'auto',
    max_leaf_nodes = None,
    min_impurity_decrease = 0.0,
    bootstrap = True,
    oob_score = False,
    n_jobs = None,
    ccp_alpha = 0.0,
    max_samples = None
)
rf_model_gradient = GradientBoostingRegressor(criterion='friedman_mse',
                                        max_depth=4,
                                        min_samples_leaf=0.0001,
                                        random_state=42,
                                        n_estimators=190) # best for kaggle = 500
rf_model = rf_model_gradient # VotingRegressor(estimators=[('gb', rf_model_gradient), ('rf', rf_model_forest), ('lr', rf_model_linear)])
rf_model.fit(X_train, y_train)<jupyter_output><empty_output><jupyter_text>**Оценка модели**<jupyter_code>y_train_preds = rf_model.predict(X_train)
y_test_preds = rf_model.predict(X_valid)

evaluate_preds(y_train, y_train_preds, y_valid, y_test_preds)<jupyter_output><empty_output><jupyter_text>**Кросс-валидация**<jupyter_code>cv_score = cross_val_score(rf_model, X_train, y_train, scoring='r2', cv=KFold(n_splits=3, shuffle=True, random_state=21))
cv_score
cv_score.mean()<jupyter_output><empty_output><jupyter_text>**Важность признаков**<jupyter_code>feature_importances = pd.DataFrame(zip(X_train.columns, rf_model.feature_importances_), 
                                   columns=['feature_name', 'importance'])

feature_importances.sort_values(by='importance', ascending=False)<jupyter_output><empty_output><jupyter_text>8. Прогнозирование на тестовом датасете  1. Выполнить для тестового датасета те же этапы обработки и постронияния признаков2. Не потерять и не перемешать индексы от примеров при построении прогнозов3. Прогнозы должны быть для все примеров из тестового датасета (для всех строк)<jupyter_code>test_df.shape
test_df
submit = pd.read_csv('./input/real-estate-price-prediction-moscow/sample_submission.csv')
submit.head()
predictions = rf_model.predict(test_df)
predictions
submit['Price'] = predictions
submit.head()
submit.to_csv('rf_submit.csv', index=False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13753265839320705, 'fraction_numerical': 0.011757021554539516, 'mean_word_length': 4.007563368765331, 'pattern_counts': {'":': 0, '<': 155, '<?xml version=': 0, '>': 161, 'https://': 3, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '36', 'dir': 'jupyter-structured-clean-dedup', 'id': '192366', 'license': 'MIT', 'n_tokens_mistral': 9339, 'n_tokens_neox': 9342, 'n_words': 1619, 'path': 'lesson_10_final/lesson_10_final.ipynb', 'repo_name': 'alexartwww/geekbrains-py-for-ds', 'size': '24496'}