AIM-PIbd-31-Yaruskin-S-A/lab_2/laba2.ipynb
2024-11-01 21:16:02 +04:00

986 KiB
Raw Blame History

  1. Продажи домов
  2. Данные о населении
  3. Набор данных для анализа и прогнозирования сердечного приступа

Продажа домов

In [262]:
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split


df = pd.read_csv("..//static//csv//House.csv", index_col="id")

print(df.columns, "\n")
Index(['date', 'price', 'bedrooms', 'bathrooms', 'sqft_living', 'sqft_lot',
       'floors', 'waterfront', 'view', 'condition', 'grade', 'sqft_above',
       'sqft_basement', 'yr_built', 'yr_renovated', 'zipcode', 'lat', 'long',
       'sqft_living15', 'sqft_lot15'],
      dtype='object') 

Столбцы для русских:

id: Идентификатор объекта
date: Дата продажи
price: Цена недвижимости
bedrooms: Количество спален
bathrooms: Количество ванных комнат
sqft_living: Жилая площадь
sqft_lot: Площадь участка
floors: Количество этажей
waterfront: Признак наличия вида на водоем
view: Оценка вида
condition: Состояние дома
grade: Оценка конструкции
sqft_above: Площадь надземных помещений
sqft_basement: Площадь подвала
yr_built: Год постройки
yr_renovated: Год последнего ремонта
zipcode: Почтовый индекс
lat: Широта
long: Долгота
sqft_living15: Жилая площадь соседних домов
sqft_lot15: Площадь участка соседних домов

Проблемная область: Прогнозирование стоимости недвижимости в зависимости от характеристик дома.

In [263]:
print(df.info, "\n")
<bound method DataFrame.info of                        date     price  bedrooms  bathrooms  sqft_living  \
id                                                                        
7129300520  20141013T000000  221900.0         3       1.00         1180   
6414100192  20141209T000000  538000.0         3       2.25         2570   
5631500400  20150225T000000  180000.0         2       1.00          770   
2487200875  20141209T000000  604000.0         4       3.00         1960   
1954400510  20150218T000000  510000.0         3       2.00         1680   
...                     ...       ...       ...        ...          ...   
263000018   20140521T000000  360000.0         3       2.50         1530   
6600060120  20150223T000000  400000.0         4       2.50         2310   
1523300141  20140623T000000  402101.0         2       0.75         1020   
291310100   20150116T000000  400000.0         3       2.50         1600   
1523300157  20141015T000000  325000.0         2       0.75         1020   

            sqft_lot  floors  waterfront  view  condition  grade  sqft_above  \
id                                                                             
7129300520      5650     1.0           0     0          3      7        1180   
6414100192      7242     2.0           0     0          3      7        2170   
5631500400     10000     1.0           0     0          3      6         770   
2487200875      5000     1.0           0     0          5      7        1050   
1954400510      8080     1.0           0     0          3      8        1680   
...              ...     ...         ...   ...        ...    ...         ...   
263000018       1131     3.0           0     0          3      8        1530   
6600060120      5813     2.0           0     0          3      8        2310   
1523300141      1350     2.0           0     0          3      7        1020   
291310100       2388     2.0           0     0          3      8        1600   
1523300157      1076     2.0           0     0          3      7        1020   

            sqft_basement  yr_built  yr_renovated  zipcode      lat     long  \
id                                                                             
7129300520              0      1955             0    98178  47.5112 -122.257   
6414100192            400      1951          1991    98125  47.7210 -122.319   
5631500400              0      1933             0    98028  47.7379 -122.233   
2487200875            910      1965             0    98136  47.5208 -122.393   
1954400510              0      1987             0    98074  47.6168 -122.045   
...                   ...       ...           ...      ...      ...      ...   
263000018               0      2009             0    98103  47.6993 -122.346   
6600060120              0      2014             0    98146  47.5107 -122.362   
1523300141              0      2009             0    98144  47.5944 -122.299   
291310100               0      2004             0    98027  47.5345 -122.069   
1523300157              0      2008             0    98144  47.5941 -122.299   

            sqft_living15  sqft_lot15  
id                                     
7129300520           1340        5650  
6414100192           1690        7639  
5631500400           2720        8062  
2487200875           1360        5000  
1954400510           1800        7503  
...                   ...         ...  
263000018            1530        1509  
6600060120           1830        7200  
1523300141           1020        2007  
291310100            1410        1287  
1523300157           1020        1357  

[21613 rows x 20 columns]> 

Объектом наблюдения является - Недвижимость
Атрибуты - содержит набор информации о продаже дома, такие как:
цену продажи, дата продажи, количество спален, ванных комнат, общую площадь дома, площадь участка, местоположение.

In [264]:
plt.figure(figsize=(10, 6))

plt.scatter(df['sqft_living'], df['price'], c=df['price'], alpha=0.6)
plt.colorbar(label='Price')

plt.title("Номер 1")
plt.ylabel("Price")
plt.xlabel("Living Area")
plt.grid(visible='true')

plt.show()
No description has been provided for this image
In [265]:
year_condition = df.groupby('yr_built')['condition'].mean().reset_index()

plt.figure(figsize=(12, 6))

plt.plot(year_condition['yr_built'], year_condition['condition'], marker='.')

plt.title("Номер 2")
plt.xlabel("Year Built")
plt.ylabel("Condition")


plt.show()
No description has been provided for this image

Связь между объектами есть. Цена связана почти со всеми характиристиками дома.
Например на графике номер один показана зависимоость между ценой и размером дома.
А на графике номер 2 показа зависимость состояния домов с годами.

Примеры бизнес целей

  1. Прогнозирование стоимости недвижимости на основе характиристик дома.
  2. Наблюдение за изменениями характиристик дома с годами.

Эффект для бизнеса: Оценка и оптимизация цен, Оценка и планирование затрат, выявление тенденции на рынке, стратегия планирования.

Цели технического проекта

    Для первой цели:
  • Вход: Характеристики недвижимости
  • Целевой признак: Цена.
    • Для второй цели:
  • Вход: оценка конструкции, Состояние дома
  • Целевой признак: Год постройки
  • Код ниже нужен для определения проблем данных

    In [266]:
    max_value = df.max(axis=0)
    
    columns_with_zero = df.columns[(df == 0).any()]
    
    numeric_data = df.select_dtypes(include='number')
    shum = numeric_data.var()
    low_dispers = 0.1
    low_var_columns = shum[shum < low_dispers]
    
    
    year = df['yr_built']
    
    print(max_value, "\n")
    print(columns_with_zero, "\n")
    print("Признаки с низкой дисперсией:\n", low_var_columns, "\n")
    print(year)
    
    date             20150527T000000
    price                  7700000.0
    bedrooms                      33
    bathrooms                    8.0
    sqft_living                13540
    sqft_lot                 1651359
    floors                       3.5
    waterfront                     1
    view                           4
    condition                      5
    grade                         13
    sqft_above                  9410
    sqft_basement               4820
    yr_built                    2015
    yr_renovated                2015
    zipcode                    98199
    lat                      47.7776
    long                    -121.315
    sqft_living15               6210
    sqft_lot15                871200
    dtype: object 
    
    Index(['bedrooms', 'bathrooms', 'waterfront', 'view', 'sqft_basement',
           'yr_renovated'],
          dtype='object') 
    
    Признаки с низкой дисперсией:
     waterfront    0.007485
    lat           0.019200
    long          0.019833
    dtype: float64 
    
    id
    7129300520    1955
    6414100192    1951
    5631500400    1933
    2487200875    1965
    1954400510    1987
                  ... 
    263000018     2009
    6600060120    2014
    1523300141    2009
    291310100     2004
    1523300157    2008
    Name: yr_built, Length: 21613, dtype: int64
    

      Из полученных данных выяснилось:

  • признаки bedrooms, bathrooms, waterfront, view, sqft_basement и yr_renovated имеют в себе нулевые поля, что может создать смещение если искать по этим полям
  • признаки bedrooms, bathrooms и price имеют аномально высокие значения, и это указывает на наличие выбросов
  • признаки waterfront, view, condition имеют низкие значения дисперсии, что может привести к снижению значимости этих признаков
  • признак yr_built варьируется от 1900 до 2015. Это может быть актуальной информацией для анализа старых зданий, но актуальность данных по ремонту и реконструкции (это призгак yr_renovated) может быть ниже, так как 0 указывает на отсутствие ремонта
    1. Примеры решения проблем для набора данных

  • Удаление выбросов на основе значения или bathrooms > 5
  • Замена 0 на год постройки (это признак yr_built), если дом не подвергался ремонту
  • Оценка качества данных

    1. Информативность. Набор данных предоставляет достаточную информацию для анализа цен на недвижимость. 2. Степень покрытия. Набор данных затрагивает только один райно, не включая информацию о других райнов. 3. Соответствие реальным данным. Данные вполне кажутся реальными, не считая некоторых редких выбросов. 4. Согласованность меток. Метки состояние и оценка вида, имеют четкие значения.

    Разбиение данных на обучающую, контрольную и тестовую выборки

    In [267]:
    df_numeric = df.select_dtypes(include='number')
    
    x = df_numeric.drop(['price'], axis=1)
    y = df_numeric['price']
    
    x_train, x_temp, y_train, y_temp = train_test_split(x, y, test_size=0.3, random_state=14)
    
    x_val, x_test, y_val, y_test = train_test_split(x_temp, y_temp, test_size=0.5, random_state=14)
    
    print(f"Исходный размер строк: {df_numeric.shape[0]} строк")
    print(f"Размер обучающей выборки: {x_train.shape[0]} строк")
    print(f"Размер валидационной выборки: {x_val.shape[0]} строк")
    print(f"Размер тестовой выборки: {x_test.shape[0]} строк")
    
    Исходный размер строк: 21613 строк
    Размер обучающей выборки: 15129 строк
    Размер валидационной выборки: 3242 строк
    Размер тестовой выборки: 3242 строк
    
    In [268]:
    import seaborn as sns
    
    df['price_log'] = np.log(df['price'])
    
    X = df.drop(['price', 'price_log'], axis=1)
    y = df['price_log']
    
    X = X.select_dtypes(include='number')
    
    X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3, random_state=42)
    
    X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
    def plot_distribution(data, title):
        """Построение гистограммы распределения целевого признака"""
        plt.figure(figsize=(10, 6))
        sns.histplot(data, kde=True, bins=30, color='skyblue')
        plt.title(title)
        plt.xlabel('Logarithm of Price')
        plt.ylabel('Count')
        plt.grid(True)
        plt.show()
    
    plot_distribution(y_train, 'Распределение логарифма цены в обучающей выборке')
    plot_distribution(y_val, 'Распределение логарифма цены в валидационной выборке')
    plot_distribution(y_test, 'Распределение логарифма цены в тестовой выборке')
    
    def get_statistics(df, name):
        print(f"Статистические показатели для {name} выборки:")
        print(f"Среднее значение: {df.mean():.2f}")
        print(f"Стандартное отклонение: {df.std():.2f}")
        print(f"Минимальное значение: {df.min():.2f}")
        print(f"Максимальное значение: {df.max():.2f}")
        print(f"Количество наблюдений: {df.count()}\n")
    
    get_statistics(y_train, "обучающей")
    
    get_statistics(y_val, "валидационной")
    
    get_statistics(y_test, "тестовой")
    
    No description has been provided for this image
    No description has been provided for this image
    No description has been provided for this image
    Статистические показатели для обучающей выборки:
    Среднее значение: 13.05
    Стандартное отклонение: 0.52
    Минимальное значение: 11.23
    Максимальное значение: 15.86
    Количество наблюдений: 15129
    
    Статистические показатели для валидационной выборки:
    Среднее значение: 13.05
    Стандартное отклонение: 0.53
    Минимальное значение: 11.26
    Максимальное значение: 15.49
    Количество наблюдений: 3242
    
    Статистические показатели для тестовой выборки:
    Среднее значение: 13.06
    Стандартное отклонение: 0.54
    Минимальное значение: 11.35
    Максимальное значение: 15.53
    Количество наблюдений: 3242
    
    

    Oversampling и undersampling

    In [269]:
    from imblearn.over_sampling import SMOTE
    from imblearn.under_sampling import RandomUnderSampler
    
    
    if 'date' in df.columns:
        df['year'] = pd.to_datetime(df['date'], errors='coerce').dt.year
        df = df.drop(['date'], axis=1)
    
    df['price_log'] = np.log(df['price'])
    
    df['price_category'] = pd.qcut(df['price_log'], q=5, labels=[0, 1, 2, 3, 4])
    
    X = df.drop(['price', 'price_log', 'price_category'], axis=1)
    y = df['price_category']
    
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
    
    smote = SMOTE(random_state=42)
    X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
    
    print("Распределение классов после SMOTE (oversampling):")
    print(pd.Series(y_train_smote).value_counts())
    
    undersampler = RandomUnderSampler(random_state=42)
    X_train_under, y_train_under = undersampler.fit_resample(X_train, y_train)
    
    print("Распределение классов после RandomUnderSampler (undersampling):")
    print(pd.Series(y_train_under).value_counts())
    
    Распределение классов после SMOTE (oversampling):
    price_category
    0    3054
    1    3054
    2    3054
    3    3054
    4    3054
    Name: count, dtype: int64
    Распределение классов после RandomUnderSampler (undersampling):
    price_category
    0    2993
    1    2993
    2    2993
    3    2993
    4    2993
    Name: count, dtype: int64
    

    Оценка сбалансированности выборок

    Оценка необходимости аугментации данных

    In [1]:
    def check_augmentation_need(data, name):
        """Проверка необходимости аугментации данных"""
        quantiles = data.quantile([0.25, 0.5, 0.75])
        mean = data.mean()
        std = data.std()
        
        print(f"Проверка необходимости аугментации для {name} выборки:")
        print(f"Среднее значение: {mean:.2f}, Стандартное отклонение: {std:.2f}")
        print(f"25-й квантиль: {quantiles[0.25]:.2f}")
        print(f"50-й квантиль (медиана): {quantiles[0.5]:.2f}")
        print(f"75-й квантиль: {quantiles[0.75]:.2f}")
        
        if std > mean * 0.5:
            print(f"Выборка {name} несбалансирована, рекомендуется аугментация.\n")
        else:
            print(f"Выборка {name} сбалансирована, аугментация не требуется.\n")
    
    check_augmentation_need(y_train, "обучающей")
    check_augmentation_need(y_val, "валидационной")
    check_augmentation_need(y_test, "тестовой")
    
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    Cell In[1], line 18
         15     else:
         16         print(f"Выборка {name} сбалансирована, аугментация не требуется.\n")
    ---> 18 check_augmentation_need(y_train, "обучающей")
         19 check_augmentation_need(y_val, "валидационной")
         20 check_augmentation_need(y_test, "тестовой")
    
    NameError: name 'y_train' is not defined

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

    In [192]:
    if 'condition' in df.columns:
        X_train, X_temp, y_train, y_temp = train_test_split(df.drop(['price'], axis=1), df['condition'], test_size=0.3, random_state=42)
        X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
    
        def analyze_condition_distribution(data, name):
            """Проверка и визуализация распределения признака 'condition'"""
            condition_counts = data.value_counts()
            print(f"Распределение 'condition' в {name} выборке:\n", condition_counts)
            
            plt.figure(figsize=(8, 6))
            sns.barplot(x=condition_counts.index, y=condition_counts.values, palette='viridis')
            plt.title(f"Распределение признака 'condition' в {name} выборке")
            plt.xlabel('Condition')
            plt.ylabel('Count')
            plt.grid(True)
            plt.show()
    
        analyze_condition_distribution(y_train, 'обучающей')
        analyze_condition_distribution(y_val, 'валидационной')
        analyze_condition_distribution(y_test, 'тестовой')
    
        def check_condition_augmentation(data, name):
            print(f"Проверка необходимости аугментации для признака 'condition' в {name} выборке:")
            min_count = data.value_counts().min()
            max_count = data.value_counts().max()
            print(f"Минимальное количество наблюдений в классе: {min_count}")
            print(f"Максимальное количество наблюдений в классе: {max_count}")
            
            if max_count > min_count * 1.5:
                print(f"Выборка '{name}' несбалансирована, рекомендуется аугментация.\n")
            else:
                print(f"Выборка '{name}' сбалансирована, аугментация не требуется.\n")
    
        check_condition_augmentation(y_train, 'обучающей')
        check_condition_augmentation(y_val, 'валидационной')
        check_condition_augmentation(y_test, 'тестовой')
    else:
        print("Признак 'condition' отсутствует в данных.")
    
    smote = SMOTE(random_state=42)
    X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
    
    print("Распределение классов после SMOTE (oversampling):")
    print(pd.Series(y_train_smote).value_counts())
    
    undersampler = RandomUnderSampler(random_state=42)
    X_train_under, y_train_under = undersampler.fit_resample(X_train, y_train)
    
    print("Распределение классов после RandomUnderSampler (undersampling):")
    print(pd.Series(y_train_under).value_counts())
    
    Распределение 'condition' в обучающей выборке:
     condition
    3    9837
    4    3958
    5    1189
    2     121
    1      24
    Name: count, dtype: int64
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_8140\3337968062.py:11: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
    
      sns.barplot(x=condition_counts.index, y=condition_counts.values, palette='viridis')
    
    No description has been provided for this image
    Распределение 'condition' в валидационной выборке:
     condition
    3    2125
    4     830
    5     256
    2      27
    1       4
    Name: count, dtype: int64
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_8140\3337968062.py:11: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
    
      sns.barplot(x=condition_counts.index, y=condition_counts.values, palette='viridis')
    
    No description has been provided for this image
    Распределение 'condition' в тестовой выборке:
     condition
    3    2069
    4     891
    5     256
    2      24
    1       2
    Name: count, dtype: int64
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_8140\3337968062.py:11: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
    
      sns.barplot(x=condition_counts.index, y=condition_counts.values, palette='viridis')
    
    No description has been provided for this image
    Проверка необходимости аугментации для признака 'condition' в обучающей выборке:
    Минимальное количество наблюдений в классе: 24
    Максимальное количество наблюдений в классе: 9837
    Выборка 'обучающей' несбалансирована, рекомендуется аугментация.
    
    Проверка необходимости аугментации для признака 'condition' в валидационной выборке:
    Минимальное количество наблюдений в классе: 4
    Максимальное количество наблюдений в классе: 2125
    Выборка 'валидационной' несбалансирована, рекомендуется аугментация.
    
    Проверка необходимости аугментации для признака 'condition' в тестовой выборке:
    Минимальное количество наблюдений в классе: 2
    Максимальное количество наблюдений в классе: 2069
    Выборка 'тестовой' несбалансирована, рекомендуется аугментация.
    
    Распределение классов после SMOTE (oversampling):
    condition
    3    9837
    5    9837
    4    9837
    2    9837
    1    9837
    Name: count, dtype: int64
    Распределение классов после RandomUnderSampler (undersampling):
    condition
    1    24
    2    24
    3    24
    4    24
    5    24
    Name: count, dtype: int64
    

    В этом исследование данные не сбалансированы, поэтому требуется аугментация.

    Данные о населении

    In [71]:
    import numpy as np
    import pandas as pd 
    import matplotlib.pyplot as plt
    from sklearn.model_selection import train_test_split
    
    df2 = pd.read_csv("..//static//csv//WorldPopulation.csv", index_col="no")
    
    print(df2.head(), "\n")
    print(*list(df2.columns), sep='\n')
    
       Country (or dependency) Population 2020 Yearly Change  Net Change  \
    no                                                                     
    1                    China   1,439,323,776         0.39%   5,540,090   
    2                    India   1,380,004,385         0.99%  13,586,631   
    3            United States     331,002,651         0.59%   1,937,734   
    4                Indonesia     273,523,615         1.07%   2,898,047   
    5                 Pakistan     220,892,340         2.00%   4,327,022   
    
       Density  (P/Km²) Land Area (Km²) Migrants (net) Fert. Rate Med. Age  \
    no                                                                       
    1               153       9,388,211       -348,399        1.7       38   
    2               464       2,973,190       -532,687        2.2       28   
    3                36       9,147,420        954,806        1.8       38   
    4               151       1,811,570        -98,955        2.3       30   
    5               287         770,880       -233,379        3.6       23   
    
       Urban Pop % World Share  
    no                          
    1          61%      18.47%  
    2          35%      17.70%  
    3          83%       4.25%  
    4          56%       3.51%  
    5          35%       2.83%   
    
    Country (or dependency)
    Population 2020
    Yearly Change
    Net Change
    Density  (P/Km²)
    Land Area (Km²)
    Migrants (net)
    Fert. Rate
    Med. Age
    Urban Pop %
    World Share
    

    Объектом наблюдения является страны и информация о их наслении.
    Атрибуты объекта: Страна, Население, Годовое изменение, NetChange, Плотность, Площадь суши, Мигранты, Fert.Rate, Средний возраст, UrbanPop%, Доля в мире;
    Связь между объектами: имеется связь между атрибутами, например между Коэффициент фертильности и Плотностю населения.

    In [49]:
    df2['Fert. Rate'] = pd.to_numeric(df2['Fert. Rate'], errors='coerce')
    
    
    df2['Fert. Rate'] = pd.to_numeric(df2['Fert. Rate'], errors='coerce')
    
    df_clean = df2.dropna(subset=['Fert. Rate', 'Density  (P/Km²)'])
        
    ## correlation = df_clean[['Density  (P/Km²)', 'Fert. Rate']].corr().iloc[0, 1] ## использовать только один раз потом удалить
    
    df_clean['Density  (P/Km²)'] = pd.cut(df2['Density  (P/Km²)'], bins=range(0, 1000, 100))
    plt.figure(figsize=(10, 6))
    sns.boxplot(data=df_clean, x='Density  (P/Km²)', y='Fert. Rate')
    plt.title('Распределение уровня рождаемости по плотности населения')
    plt.xlabel('Плотность (чел./км²)')
    plt.ylabel('Уровень рождаемости')
    plt.xticks(rotation=45)
    plt.show()
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2445382032.py:10: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      df_clean['Density  (P/Km²)'] = pd.cut(df2['Density  (P/Km²)'], bins=range(0, 1000, 100))
    
    No description has been provided for this image

    В регионах с низкой плотностью населения рождаемость значительно варьируется, в то время как в регионах с плотностью более 400 чел./км² наблюдается более стабильная и высокая рождаемость.

    Бизнес-цели

    1. Бизнес-цель: Определение наилучших стран для выхода на рынок товаров и услуг, связанных с материнством и детством.
      Эффект для бизнеса: Возможность выбора стран с высоким уровнем рождаемости и значительным числом молодых семей для запуска маркетинговых кампаний и открытия новых филиалов.
    • Цели технического проекта:
      • Построить модель для определения стран с высоким потенциалом развития рынка товаров для детей и матерей.
      • Входные признаки: Плотность населения, Уровень рождаемости, Средний возраст, Доля городского населения.
      • Целевой признак: Страна с высоким или низким потенциалом для выхода на рынок.
    1. Бизнес-цель: Оптимизация стратегий миграционной политики. Эффект для бизнеса: Компании, предоставляющие услуги в области миграции, найма и адаптации, могут использовать эти данные для выбора мест, где их услуги будут наиболее востребованы.
    • Цели технического проекта:
      • Построить модель, определяющую страны с наибольшим оттоком мигрантов и прогнозировать влияние миграции на рынок труда.
      • Входные признаки: Годовое изменение населения, Плотность населения, Доля городского населения.
      • Целевой признак: Уровень чистой миграции.
    1. Бизнес-цель: Определение экономического потенциала стран на основе плотности населения и уровня урбанизации. Эффект для бизнеса: Компании могут определить страны с высоким уровнем урбанизации и значительной плотностью населения для открытия новых офисов, производств или филиалов.
    • Цели технического проекта:
      • Создать модель для ранжирования стран по их экономическому потенциалу на основе демографических данных.
      • Входные признаки: Плотность населения, Уровень урбанизации, Средний возраст, Доля городского населения.
      • Целевой признак: Оценка экономического потенциала.

    Поиск проблем

    In [145]:
    from scipy import stats
    
    missing_val = df2.isnull().sum()
    print("Количество пропущеных ячеек: \n", missing_val)
    
    df2['Population 2020'] = pd.to_numeric(df2['Population 2020'].astype(str).str.replace(',', ''), errors='coerce')
    df2['Density  (P/Km²)'] = pd.to_numeric(df2['Density  (P/Km²)'].astype(str).str.replace(',', ''), errors='coerce')
    df2['Fert. Rate'] = pd.to_numeric(df2['Fert. Rate'], errors='coerce')
    df2['Med. Age'] = pd.to_numeric(df2['Med. Age'], errors='coerce')
    df2['Urban Pop %'] = pd.to_numeric(df2['Urban Pop %'].astype(str).str.replace('%', ''), errors='coerce')
    df2['World Share'] = pd.to_numeric(df2['World Share'].astype(str).str.replace('%', ''), errors='coerce')
    
    # Удаление пропусков для корректного анализа
    data = df2.dropna()
    
    # 1. Визуализация распределения данных (помогает выявить выбросы)
    plt.figure(figsize=(12, 6))
    sns.boxplot(data=data[['Fert. Rate', 'Density  (P/Km²)', 'Med. Age']])
    plt.title('Поиск выбросов с помощью Boxplot')
    plt.show()
    
    z_scrore = np.abs(stats.zscore(data[['Fert. Rate', 'Density  (P/Km²)', 'Med. Age', 'Urban Pop %', 'World Share']]))
    outliers = np.where(z_scrore > 3)
    print(f"Количество выбросов (по Z-оценке): {len(outliers[0])}")
    
    # Построение корреляционной матрицы для поиска зашумленности
    corr_matrix = data[['Population 2020', 'Density  (P/Km²)', 'Fert. Rate', 'Med. Age', 'Urban Pop %', 'World Share']].corr()
    sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')
    plt.title('Корреляционная матрица')
    plt.show()
    
    Количество пропущеных ячеек: 
     Country (or dependency)     0
    Population 2020             0
    Yearly Change               0
    Net Change                  0
    Density  (P/Km²)           12
    Land Area (Km²)             0
    Migrants (net)             34
    Fert. Rate                 34
    Med. Age                   34
    Urban Pop %                13
    World Share                 0
    dtype: int64
    
    No description has been provided for this image
    Количество выбросов (по Z-оценке): 7
    
    No description has been provided for this image

    Из матрицы корреляции можно сделать выводы отностительно зависимости между атрибутами и выявит наиболее бесполезные их них. Признаки с низкими корреляциями, такие как Density (P/Km²), Population 2020, и World Share, могут содержать шум или не являться значимыми для текущей задачи демографического анализа. Это не обязательно означает, что эти переменные всегда шумны, но в контексте анализа они могут оказаться несущественными.

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

    По итогу вышло больше количество шумов

    In [96]:
    plt.figure(figsize=(12, 6))
    sns.histplot(data=data['Population 2020'], kde=True, bins=30)
    plt.title('Распределение населения по странам в 2020 году')
    plt.xlabel('Население')
    plt.ylabel('Количество стран')
    plt.show()
    
    mean_population = data['Population 2020'].mean()
    median_population = data['Population 2020'].median()
    print(f"Среднее значение населения: {mean_population}")
    print(f"Медиана населения: {median_population}")
    
    No description has been provided for this image
    Среднее значение населения: 39877695.56842105
    Медиана населения: 8976711.0
    

    Определяем смещение. Если разница между средним и медианным значениями существенна, это может указывать на смещение. В данном случаем имеется смещение.

    In [110]:
    # Приведение столбцов к числовым значениям
    data['Net Change'] = pd.to_numeric(data['Net Change'].astype(str).str.replace(',', ''), errors='coerce')
    data['Migrants (net)'] = pd.to_numeric(data['Migrants (net)'].astype(str).str.replace(',', ''), errors='coerce')
    data['Population 2020'] = pd.to_numeric(data['Population 2020'].astype(str).str.replace(',', ''), errors='coerce')
    
    invalid_net_change = data[data['Net Change'] > data['Population 2020']]
    invalid_migrants = data[data['Migrants (net)'] > data['Population 2020']]
    
    if not invalid_net_change.empty:
        print("Просачивание данных: Прирост населения превышает текущее население в следующих строках:")
        print(invalid_net_change)
    else:
        print("Просачивания данных в столбце 'Net Change' не обнаружено.")
    
    if not invalid_migrants.empty:
        print("Просачивание данных: Мигранты превышают текущее население в следующих строках:")
        print(invalid_migrants)
    else:
        print("Просачивания данных в столбце 'Migrants (net)' не обнаружено.")
    
    Просачивания данных в столбце 'Net Change' не обнаружено.
    Просачивания данных в столбце 'Migrants (net)' не обнаружено.
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2903715557.py:2: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data['Net Change'] = pd.to_numeric(data['Net Change'].astype(str).str.replace(',', ''), errors='coerce')
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2903715557.py:3: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data['Migrants (net)'] = pd.to_numeric(data['Migrants (net)'].astype(str).str.replace(',', ''), errors='coerce')
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2903715557.py:4: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data['Population 2020'] = pd.to_numeric(data['Population 2020'].astype(str).str.replace(',', ''), errors='coerce')
    

    Тут я хочу выявить просачивание данных. Для этого хочу сравнить прирост населения и количество мигрантов с численности населения в 2020 году. Логично, если они окажутся больше общий численности населения это окажется странным. В данном случае все оказалось нормально и не какие данные не просачились.

    In [155]:
    data_no_outliers = data[(z_scores < 3).all(axis=1)]
    print(f"Размер данных после удаления выбросов: {data_no_outliers.shape}")
    
    columns_to_check = ['Fert. Rate', 'Density  (P/Km²)', 'Med. Age', 'Urban Pop %', 'World Share']
    
    for column in columns_to_check:
        col_z_score = np.abs(stats.zscore(data[column]))
        
        median_value = data[column].median()
        
        print(f"Обрабатываем столбец: {column}, медианное значение: {median_value}")
        
        data[column] = np.where(col_z_score > 3, median_value, data[column])
    
    print("Выбросы заменены медианными значениями.")
    
    Размер данных после удаления выбросов: (183, 11)
    Обрабатываем столбец: Fert. Rate, медианное значение: 2.3
    Обрабатываем столбец: Density  (P/Km²), медианное значение: 83.0
    Обрабатываем столбец: Med. Age, медианное значение: 30.0
    Обрабатываем столбец: Urban Pop %, медианное значение: 60.0
    Обрабатываем столбец: World Share, медианное значение: 0.11499999999999999
    Выбросы заменены медианными значениями.
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\3365745342.py:18: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data[column] = np.where(col_z_score > 3, median_value, data[column])
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\3365745342.py:18: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data[column] = np.where(col_z_score > 3, median_value, data[column])
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\3365745342.py:18: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data[column] = np.where(col_z_score > 3, median_value, data[column])
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\3365745342.py:18: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data[column] = np.where(col_z_score > 3, median_value, data[column])
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\3365745342.py:18: SettingWithCopyWarning: 
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead
    
    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      data[column] = np.where(col_z_score > 3, median_value, data[column])
    

    Решили проблему с выбрасами

    Оценка качества набора данных:

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

    Степень покрытия: В наборе данных представлены 235 стран и зависимых территорий, что охватывает практически весь мир. Это достаточно полный охват для анализа глобального населения.

    Соответствие реальным данным: Данные взяты из показателей 2020 года.

    Согласованность меток: Имена колонок не всегда очевидны (например, "Density (P/Km²)", "World Share"). Также данные представлены в разных форматах, что требует предобработки, так как числовые значения сохранены как строки.

    Устранение проблемы пропущенных данных

    In [162]:
    data_filled_mean = data.copy()
    
    data_filled_mean["Migrants (net)"] = pd.to_numeric(data_filled_mean["Migrants (net)"], errors='coerce')
    
    mean_value = data_filled_mean["Migrants (net)"].mean()
    data_filled_mean["Migrants (net)"] = data_filled_mean["Migrants (net)"].fillna(mean_value)
    print(f"Данные после заполнения средним значением: {data_filled_mean['Migrants (net)'].isnull().sum()} пропущенных значений осталось")
    
    Данные после заполнения средним значением: 0 пропущенных значений осталось
    
    In [167]:
    columns_to_drop = ["Population 2020", "no", "Country (or dependency)"]
    columns_to_drop = [col for col in columns_to_drop if col in data_filled_mean.columns]
    
    X = data_filled_mean.drop(columns=columns_to_drop)
    y = data_filled_mean["Population 2020"]
    
    X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
    X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
    
    print(f"Обучающая выборка: {X_train.shape[0]} строк")
    print(f"Валидационная выборка: {X_val.shape[0]} строк")
    print(f"Тестовая выборка: {X_test.shape[0]} строк")
    
    Обучающая выборка: 114 строк
    Валидационная выборка: 38 строк
    Тестовая выборка: 38 строк
    
    In [168]:
    # Проверка распределения целевой переменной в обучающей, валидационной и тестовой выборках
    print("Распределение в обучающей выборке:\n", y_train.describe())
    print("Распределение в валидационной выборке:\n", y_val.describe())
    print("Распределение в тестовой выборке:\n", y_test.describe())
    
    Распределение в обучающей выборке:
     count    1.140000e+02
    mean     4.809021e+07
    std      1.880257e+08
    min      9.792900e+04
    25%      1.400362e+06
    50%      9.272022e+06
    75%      2.615868e+07
    max      1.439324e+09
    Name: Population 2020, dtype: float64
    Распределение в валидационной выборке:
     count    3.800000e+01
    mean     2.704393e+07
    std      4.201158e+07
    min      1.640930e+05
    25%      4.895855e+06
    50%      1.052552e+07
    75%      3.117359e+07
    max      2.125594e+08
    Name: Population 2020, dtype: float64
    Распределение в тестовой выборке:
     count    3.800000e+01
    mean     2.807392e+07
    std      5.746454e+07
    min      1.067660e+05
    25%      9.193338e+05
    50%      5.568913e+06
    75%      3.241794e+07
    max      3.310027e+08
    Name: Population 2020, dtype: float64
    

    Дисбаланс данных:

    В обучающей выборке среднее значение численности населения составляет около 48 миллионов, однако максимальное значение достигает 1.44 миллиарда, что указывает на значительный разброс данных. Стандартное отклонение в обучающей выборке очень велико (188 миллионов), что указывает на присутствие значительного числа стран с огромным населением (например, Китай и Индия), наряду с малонаселёнными странами. В валидационной и тестовой выборках также наблюдается высокий разброс, хотя их максимальные значения намного ниже (212 и 331 миллионов соответственно).

    Методы приращения данных могут быть полезный, поэтому я ими воспользуюсь

    In [172]:
    from imblearn.over_sampling import RandomOverSampler
    from imblearn.under_sampling import RandomUnderSampler
    
    # Oversampling (увеличение выборки) для обучающих данных
    ros = RandomOverSampler(random_state=42)
    X_train_res, y_train_res = ros.fit_resample(X_train, y_train)
    print(f"Размер обучающей выборки после Oversampling: {X_train_res.shape[0]} строк")
    
    # Undersampling (уменьшение выборки) для обучающих данных
    rus = RandomUnderSampler(random_state=42)
    X_train_res_under, y_train_res_under = rus.fit_resample(X_train, y_train)
    print(f"Размер обучающей выборки после Undersampling: {X_train_res_under.shape[0]} строк")
    
    Размер обучающей выборки после Oversampling: 114 строк
    Размер обучающей выборки после Undersampling: 114 строк
    

    3 Датасет - Данные о миллионерах

    In [189]:
    df3 = pd.read_csv("..//static//csv//Forbes Billionaires.csv", index_col="Rank ")
    
    print(df3.columns, "\n")
    
    Index(['Name', 'Networth', 'Age', 'Country', 'Source', 'Industry'], dtype='object') 
    
    

    Основные столбцы: Rank: Ранг миллиардера Name: Имя миллиардера Networth: Состояние миллиардера (в миллиардах долларов) Age: Возраст миллиардера Country: Страна проживания миллиардера Source: Основной источник дохода Industry: Отрасль, к которой относится основная деятельность миллиардера

    Проблемная область

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

    Анализ содержимого

    • Объекты наблюдения: Миллиардеры
    • Атрибуты объектов: Ранг, имя, состояние, возраст, страна, источник дохода, отрасль
    • Связи между объектами: Можно выявить связи между возрастом и состоянием, страной проживания и источником дохода, а также отраслью и уровнем благосостояния.
    In [206]:
    import seaborn as sns
    
    plt.figure(figsize=(10, 6))
    
    # Связь между возрастом и состоянием
    plt.subplot(2, 2, 1)
    sns.scatterplot(data=df3, x='Age', y='Networth')
    plt.title('Связь между возрастом и состоянием')
    plt.xlabel('Возраст')
    plt.ylabel('Состояние (млрд)')
    
    # Связь между страной проживания и состоянием (топ-10 стран)
    plt.subplot(2, 2, 2)
    top_countries = df3['Country'].value_counts().index[:10]
    sns.boxplot(data=df3[df3['Country'].isin(top_countries)], x='Country', y='Networth')
    plt.title('Связь между страной проживания и состоянием')
    plt.xticks(rotation=90)
    plt.xlabel('Страна')
    plt.ylabel('Состояние (млрд)')
    
    # Связь между источником дохода и состоянием (топ-10 источников дохода)
    plt.subplot(2, 2, 3)
    top_sources = df3['Source'].value_counts().index[:10]
    sns.boxplot(data=df3[df3['Source'].isin(top_sources)], x='Source', y='Networth')
    plt.title('Связь между источником дохода и состоянием')
    plt.xticks(rotation=90)
    plt.xlabel('Источник дохода')
    plt.ylabel('Состояние (млрд)')
    
    # Связь между отраслью и состоянием (топ-10 отраслей)
    plt.subplot(2, 2, 4)
    top_industries = df3['Industry'].value_counts().index[:10]
    sns.boxplot(data=df3[df3['Industry'].isin(top_industries)], x='Industry', y='Networth')
    plt.title('Связь между отраслью и состоянием')
    plt.xticks(rotation=90)
    plt.xlabel('Отрасль')
    plt.ylabel('Состояние (млрд)')
    
    plt.tight_layout()
    plt.show()
    
    No description has been provided for this image

    Тут для наглядности вывел графики зависимостей

    Примеры бизнес-целей

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

    Цели технического проекта

    1. Вход: Данные по состоянию и источникам доходов.
      Целевой признак: Отрасль, состояние.

    2. Вход: Данные по возрасту и состоянию.
      Целевой признак: Возраст, состояние.

    3. Вход: Данные по странам и состоянию.
      Целевой признак: Страна, состояние.

    Выявляем проблемы(и решаем их)

    In [225]:
    fig, axs = plt.subplots(1, 2, figsize=(15, 5))
    
    sns.boxplot(data=df3, x='Networth', ax=axs[0])
    axs[0].set_title("Выбросы по состоянию")
    
    sns.boxplot(data=df3, x='Age', ax=axs[1])
    axs[1].set_title("Выбросы по возрасту")
    
    plt.show()
    print("Размер данных до удаления выбросов: ", df3.shape)
    
    # Функция для удаления выбросов с помощью IQR
    def remove_outliers(df, column):
        Q1 = df[column].quantile(0.25)
        Q3 = df[column].quantile(0.75)
        IQR = Q3 - Q1
        return df[~((df[column] < (Q1 - 1.5 * IQR)) | (df[column] > (Q3 + 1.5 * IQR)))]
    
    df3_cleaned = remove_outliers(df3, 'Networth')
    df3_cleaned = remove_outliers(df3_cleaned, 'Age')
    
    print("Размер данных после удаления выбросов: ", df3_cleaned.shape)
    
    No description has been provided for this image
    Размер данных до удаления выбросов:  (2600, 6)
    Размер данных после удаления выбросов:  (2366, 6)
    
    In [241]:
    plt.figure(figsize=(10, 6))
    country_dist = df3['Country'].value_counts().head(10)  # Топ-10 стран
    sns.barplot(x=country_dist.values, y=country_dist.index, palette='coolwarm')
    plt.title('Распределение миллиардеров по странам (Топ-10)')
    plt.show()
    
    plt.figure(figsize=(10, 6))
    industry_dist = df3['Industry'].value_counts().head(10)  # Топ-10 отраслей
    sns.barplot(x=industry_dist.values, y=industry_dist.index, palette='coolwarm')
    plt.title('Распределение миллиардеров по отраслям (Топ-10)')
    plt.show()
    
    # Процентное распределение по странам и отраслям(для наглядности)
    country_percentage = df3['Country'].value_counts(normalize=True) * 100
    industry_percentage = df3['Industry'].value_counts(normalize=True) * 100
    
    country_percentage.head(10), industry_percentage.head(10)
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2893838167.py:3: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `y` variable to `hue` and set `legend=False` for the same effect.
    
      sns.barplot(x=country_dist.values, y=country_dist.index, palette='coolwarm')
    
    No description has been provided for this image
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\2893838167.py:9: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `y` variable to `hue` and set `legend=False` for the same effect.
    
      sns.barplot(x=industry_dist.values, y=industry_dist.index, palette='coolwarm')
    
    No description has been provided for this image
    Out[241]:
    (Country
     United States    27.653846
     China            19.807692
     India             6.192308
     Germany           5.000000
     Russia            3.115385
     Hong Kong         2.576923
     Canada            2.461538
     Brazil            2.307692
     Italy             2.000000
     Taiwan            1.961538
     Name: proportion, dtype: float64,
     Industry
     Finance & Investments     14.846154
     Technology                12.653846
     Manufacturing             12.384615
     Fashion & Retail           9.461538
     Healthcare                 8.153846
     Food & Beverage            7.730769
     Real Estate                7.269231
     diversified                6.846154
     Media & Entertainment      3.653846
     Energy                     3.576923
     Name: proportion, dtype: float64)

    Хотел проверить смещение. В данном случае имеется смещение по регионам или отраслям. Но думаю это особенность данного датасета, а не самих данных.

    In [246]:
    # 1. Проверим уникальность по ключевым столбцам
    unique_names = df3['Name'].nunique()
    unique_countries = df3['Country'].nunique()
    unique_industries = df3['Industry'].nunique()
    
    # 2. Проверка дубликатов
    duplicates_count = df3.duplicated().sum()
    
    unique_names, unique_countries, unique_industries, duplicates_count
    
    Out[246]:
    (2598, 75, 18, np.int64(0))

    Проверка оценки информативности. Тут все нормально

    In [248]:
    # Проверка на согласованность категорий
    unique_sources = df3['Source'].unique()
    unique_industries = df3['Industry'].unique()
    
    # Пример для визуального анализа
    plt.figure(figsize=(10, 5))
    sns.countplot(data=df3, y='Industry', order=df3['Industry'].value_counts().index, palette='coolwarm')
    plt.title('Распределение по отраслям')
    plt.show()
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\1549126591.py:7: FutureWarning: 
    
    Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `y` variable to `hue` and set `legend=False` for the same effect.
    
      sns.countplot(data=df3, y='Industry', order=df3['Industry'].value_counts().index, palette='coolwarm')
    
    No description has been provided for this image

    Для оценки покрытия мы смотрим на то, насколько разнообразны данные по странам, отраслям и возрастам.

    Устранение проблемы пропущенных данных

    In [249]:
    missing_values = df3.isnull().sum()
    
    df_dropna = df3.dropna()
    
    df_fillna_const = df3.fillna(0)
    
    df_fillna_mean = df3.copy()
    for column in df_fillna_mean.select_dtypes(include=['float64', 'int64']):
        df_fillna_mean[column].fillna(df_fillna_mean[column].mean(), inplace=True)
    
    missing_values, df_dropna.shape, df_fillna_const.shape, df_fillna_mean.shape
    
    C:\Users\salih\AppData\Local\Temp\ipykernel_13360\207427758.py:9: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.
    The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.
    
    For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.
    
    
      df_fillna_mean[column].fillna(df_fillna_mean[column].mean(), inplace=True)
    
    Out[249]:
    (Name        0
     Networth    0
     Age         0
     Country     0
     Source      0
     Industry    0
     dtype: int64,
     (2600, 6),
     (2600, 6),
     (2600, 6))

    Разбиение набора данных на обучающую, контрольную и тестовую выборки

    In [251]:
    from sklearn.model_selection import train_test_split
    
    # Разделим набор данных на признаки (X) и целевой признак (y)
    X = df3.drop(columns=['Networth'])
    y = df3['Networth']
    
    # Разделение на обучающую, контрольную и тестовую выборки
    X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
    X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
    
    # Проверка размера выборок
    (X_train.shape, X_val.shape, X_test.shape)
    
    Out[251]:
    ((1560, 5), (520, 5), (520, 5))

    Оценка сбалансированности выборок

    In [252]:
    # Проверка распределения целевого признака по выборкам
    train_dist = y_train.describe()
    val_dist = y_val.describe()
    test_dist = y_test.describe()
    
    train_dist, val_dist, test_dist
    
    Out[252]:
    (count    1560.000000
     mean        5.208173
     std        12.653032
     min         1.000000
     25%         1.500000
     50%         2.400000
     75%         4.300000
     max       219.000000
     Name: Networth, dtype: float64,
     count    520.000000
     mean       4.443654
     std        7.267615
     min        1.000000
     25%        1.500000
     50%        2.400000
     75%        4.825000
     max       91.400000
     Name: Networth, dtype: float64,
     count    520.000000
     mean       4.235577
     std        5.861496
     min        1.000000
     25%        1.600000
     50%        2.500000
     75%        4.500000
     max       60.000000
     Name: Networth, dtype: float64)
    In [273]:
    oversampler = RandomOverSampler(random_state=12)
    X_train_over, y_train_over = oversampler.fit_resample(X_train, y_train)
    
    undersampler = RandomUnderSampler(random_state=12)
    X_train_under, y_train_under = undersampler.fit_resample(X_train, y_train)
    
    print("Размеры после oversampling:", X_train_over.shape, y_train_over.shape)
    print("Размеры после undersampling:", X_train_under.shape, y_train_under.shape)
    
    Размеры после oversampling: (15270, 19) (15270,)
    Размеры после undersampling: (14965, 19) (14965,)