AIM-PIbd-31-Yakovlev-M-G/lab_2/lab_2.ipynb

33 KiB
Raw Permalink Blame History

Lab2 PIbd-31 Yakovlev

Загрузим три датасета

In [124]:
import pandas as pd

df = pd.read_csv("datasets/laptop.csv")
df2 = pd.read_csv("datasets/coffee.csv")
df3 = pd.read_csv("datasets/car_price_prediction.csv")
df.info()
df2.info()
df3.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 532 entries, 0 to 531
Data columns (total 18 columns):
 #   Column               Non-Null Count  Dtype  
---  ------               --------------  -----  
 0   brand_name           532 non-null    object 
 1   price                532 non-null    int64  
 2   rating               532 non-null    int64  
 3   processor_gen        520 non-null    object 
 4   processor_brand      532 non-null    object 
 5   processor_segment    528 non-null    object 
 6   CPU_mark             532 non-null    object 
 7   CPU_performance      532 non-null    object 
 8   Graphic_card_memory  530 non-null    object 
 9   graphic_card_name    530 non-null    object 
 10  graphic_card_num     532 non-null    object 
 11  Core                 530 non-null    float64
 12  threads              514 non-null    float64
 13  display_inches       532 non-null    object 
 14  ram_storage          532 non-null    int64  
 15  ram_type             532 non-null    object 
 16  operating_system     502 non-null    float64
 17  SSD_storage          532 non-null    object 
dtypes: float64(3), int64(3), object(12)
memory usage: 74.9+ KB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8036 entries, 0 to 8035
Data columns (total 7 columns):
 #   Column     Non-Null Count  Dtype  
---  ------     --------------  -----  
 0   Date       8036 non-null   object 
 1   Open       8036 non-null   float64
 2   High       8036 non-null   float64
 3   Low        8036 non-null   float64
 4   Close      8036 non-null   float64
 5   Adj Close  8036 non-null   float64
 6   Volume     8036 non-null   int64  
dtypes: float64(5), int64(1), object(1)
memory usage: 439.6+ KB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 19237 entries, 0 to 19236
Data columns (total 18 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   ID                19237 non-null  int64  
 1   Price             19237 non-null  int64  
 2   Levy              19237 non-null  object 
 3   Manufacturer      19237 non-null  object 
 4   Model             19237 non-null  object 
 5   Prod. year        19237 non-null  int64  
 6   Category          19237 non-null  object 
 7   Leather interior  19237 non-null  object 
 8   Fuel type         19237 non-null  object 
 9   Engine volume     19237 non-null  object 
 10  Mileage           19237 non-null  object 
 11  Cylinders         19237 non-null  float64
 12  Gear box type     19237 non-null  object 
 13  Drive wheels      19237 non-null  object 
 14  Doors             19237 non-null  object 
 15  Wheel             19237 non-null  object 
 16  Color             19237 non-null  object 
 17  Airbags           19237 non-null  int64  
dtypes: float64(1), int64(4), object(13)
memory usage: 2.6+ MB

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

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

Анализ набора данных

Объекты наблюдения - игровые ноутбуки, акции, машины Атрибуты -

  1. Имя бренда, цена, рейтинг, поколение процессора, марка процессора, сегмент процессора, специальная метка, производительность процессора, видеокарта, видеопамять, номер видеокарты, кол-во потоков видеокарты, размер дисплея, оперативная память, тип оперативной памяти, ОС, SSD.
  2. Дата, начальная цена за день, максимальная цена, минимальная цена, цена на момент закрытия продаж, скорректированая цена на момент закрытия, объем торговли акций за день.
  3. Цена обслуживания, производитель, модель, год выпуска, категория, кожанный салон, тип топлива, объем двигателя. Связи между объектами - нет

Бизнес-цели

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

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

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

  1. Рейтинг ноутбука
  2. Максимальная цена за день
  3. Цена обслуживания

Проблемы набора данных и их решения

  1. Возможны устаревшие данные. Для решения данной проблемы требуется удаление самых старых записей, и добавление более новых.
  2. Возможны выбросы. Решить эту проблему помогает удаление таких выбросов. В маленькой выборке не рекомендуется удалять выбросы. В большой выборке выбросы усредняются.

Качество набора данных

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

Поиск аномалий

In [125]:
print(df.describe())
print(df2.describe())
print(df3.describe())
               price      rating        Core     threads  ram_storage  \
count     532.000000  532.000000  530.000000  514.000000   532.000000   
mean   107684.492481   67.781955    9.035849   15.089494    15.676692   
std     80187.648965    8.161356    4.413487    5.216162     8.901257   
min     30999.000000   43.000000    2.000000    4.000000     4.000000   
25%     62371.750000   63.000000    6.000000   12.000000     8.000000   
50%     83745.000000   66.000000    8.000000   16.000000    16.000000   
75%    114040.000000   72.000000   10.000000   16.000000    16.000000   
max    599990.000000   98.000000   24.000000   32.000000    64.000000   

       operating_system  
count        502.000000  
mean          10.842629  
std            0.364513  
min           10.000000  
25%           11.000000  
50%           11.000000  
75%           11.000000  
max           11.000000  
              Open         High          Low        Close    Adj Close  \
count  8036.000000  8036.000000  8036.000000  8036.000000  8036.000000   
mean     30.054280    30.351487    29.751322    30.058857    26.674025   
std      33.615577    33.906613    33.314569    33.615911    31.728090   
min       0.328125     0.347656     0.320313     0.335938     0.260703   
25%       4.392031     4.531250     4.304922     4.399610     3.414300   
50%      13.325000    13.493750    13.150000    13.330000    10.352452   
75%      55.250000    55.722501    54.852499    55.267499    47.464829   
max     126.080002   126.320000   124.809998   126.059998   118.010414   

             Volume  
count  8.036000e+03  
mean   1.470459e+07  
std    1.340021e+07  
min    1.504000e+06  
25%    7.817750e+06  
50%    1.169815e+07  
75%    1.778795e+07  
max    5.855088e+08  
                 ID         Price    Prod. year     Cylinders       Airbags
count  1.923700e+04  1.923700e+04  19237.000000  19237.000000  19237.000000
mean   4.557654e+07  1.855593e+04   2010.912824      4.582991      6.582627
std    9.365914e+05  1.905813e+05      5.668673      1.199933      4.320168
min    2.074688e+07  1.000000e+00   1939.000000      1.000000      0.000000
25%    4.569837e+07  5.331000e+03   2009.000000      4.000000      4.000000
50%    4.577231e+07  1.317200e+04   2012.000000      4.000000      6.000000
75%    4.580204e+07  2.207500e+04   2015.000000      4.000000     12.000000
max    4.581665e+07  2.630750e+07   2020.000000     16.000000     16.000000

При просмотре вывода не было замечено аномалий в столбцах датасетов.

Проблема пропущенных данных

In [126]:
print("DATASET 1")
for i in df.columns:
    null_rate = df[i].isnull().sum() / len(df)*100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
print("DATASET 2")
for i in df2.columns:
    null_rate = df2[i].isnull().sum() / len(df2)*100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
print("DATASET 3")
for i in df3.columns:
    null_rate = df3[i].isnull().sum() / len(df3)*100
    if null_rate > 0:
        print(f"{i} процент пустых значений: %{null_rate:.2f}")
DATASET 1
processor_gen процент пустых значений: %2.26
processor_segment процент пустых значений: %0.75
Graphic_card_memory процент пустых значений: %0.38
graphic_card_name процент пустых значений: %0.38
Core процент пустых значений: %0.38
threads процент пустых значений: %3.38
operating_system процент пустых значений: %5.64
DATASET 2
DATASET 3

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

In [127]:
df = df.fillna(0) #Замена пустых значений на 0
print(df.isnull().any())
df.tail()
brand_name             False
price                  False
rating                 False
processor_gen          False
processor_brand        False
processor_segment      False
CPU_mark               False
CPU_performance        False
Graphic_card_memory    False
graphic_card_name      False
graphic_card_num       False
Core                   False
threads                False
display_inches         False
ram_storage            False
ram_type               False
operating_system       False
SSD_storage            False
dtype: bool
Out[127]:
brand_name price rating processor_gen processor_brand processor_segment CPU_mark CPU_performance Graphic_card_memory graphic_card_name graphic_card_num Core threads display_inches ram_storage ram_type operating_system SSD_storage
527 dell 75500 63 4th amd 5 4600H maximum performance 6GB amd radeon other 6.0 12.0 15.6 8 DDR4 10.0 512GB SSD
528 lenovo 151990 75 10th intel i7 10875H maximum performance 8GB nvidia geforce other 8.0 16.0 15.6 16 DDR4 10.0 1TB SSD
529 lenovo 46500 48 8th intel i5 8250U ultra-low power Integrated Intel Integrated other 4.0 8.0 other 4 DDR4 0.0 other
530 msi 109990 61 9th intel i7 9750H maximum performance 6GB nvidia geforce other 6.0 12.0 other 8 other 0.0 other
531 hp 95800 70 9th intel i7 9750H maximum performance 4GB nvidia geforce 1650 6.0 12.0 15.6 8 DDR4 0.0 other

Разбиение на выборки

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

In [128]:
#У первого дата сета добавим новый столбец с рейтингом от 1 до 5 на основе столбца от 1 до 100.

df['new_rating'] = pd.cut(df['rating'], bins=[0,20,40,60,80,100], labels=[1,2,3,4,5], include_lowest=True)

#У второго добавим столбец с наибольшей ценой от 1 до 10, на основе столбца от 1 до 127.

df2['new_high'] = pd.cut(df2['High'], bins=[0,13,26,39,52,65,78,91,104,117,130], labels=[1,2,3,4,5,6,7,8,9,10], include_lowest=True)

#У третьего удалим слишком большие значения обслуживания и слишком маленькие и добавим новый столбец с категориями цен от 1 до 5.

df3_filtered = df3[df3['Price'] >= 10000]
df3_filtered = df3_filtered[df3_filtered['Price'] <= 100000]
df3_filtered['new_price'] = pd.cut(df3_filtered['Price'], bins=[10000,28000,46000,64000,82000,100000], labels=[1,2,3,4,5], include_lowest=True)
In [129]:
from sklearn.model_selection import train_test_split

def split_stratified_into_train_val_test(
    df_input,
    stratify_colname="y",
    frac_train=0.6,
    frac_val=0.15,
    frac_test=0.25,
    random_state=None,
):
    if frac_train + frac_val + frac_test != 1.0:
        raise ValueError(
            "fractions %f, %f, %f do not add up to 1.0"
            % (frac_train, frac_val, frac_test)
        )

    if stratify_colname not in df_input.columns:
        raise ValueError("%s is not a column in the dataframe" % (stratify_colname))

    X = df_input  # Contains all columns.
    y = df_input[
        [stratify_colname]
    ]  # Dataframe of just the column on which to stratify.

    # Split original dataframe into train and temp dataframes.
    df_train, df_temp, y_train, y_temp = train_test_split(
        X, y, stratify=y, test_size=(1.0 - frac_train), random_state=random_state
    )

    # Split the temp dataframe into val and test dataframes.
    relative_frac_test = frac_test / (frac_val + frac_test)
    df_val, df_test, y_val, y_test = train_test_split(
        df_temp,
        y_temp,
        stratify=y_temp,
        test_size=relative_frac_test,
        random_state=random_state,
    )

    assert len(df_input) == len(df_train) + len(df_val) + len(df_test)

    return df_train, df_val, df_test

Выборки датасетов

In [130]:
df_train1, df_val1, df_test1 = split_stratified_into_train_val_test(
    df, stratify_colname="new_rating", frac_train=0.60, frac_val=0.20, frac_test=0.20
)

df_train2, df_val2, df_test2 = split_stratified_into_train_val_test(
    df2, stratify_colname="new_high", frac_train=0.60, frac_val=0.20, frac_test=0.20
)

df_train3, df_val3, df_test3 = split_stratified_into_train_val_test(
    df3_filtered, stratify_colname="new_price", frac_train=0.60, frac_val=0.20, frac_test=0.20
)

print(f"train df: {df_train1.shape}, Val df: {df_val1.shape}, Test df:{df_test1.shape}")
print(f"train df2: {df_train2.shape}, Val df2: {df_val2.shape}, Test df2:{df_test2.shape}")
print(f"train df3_filtered: {df_train3.shape}, Val df3_filtered: {df_val3.shape}, Test df3_filtered:{df_test3.shape}")
train df: (319, 19), Val df: (106, 19), Test df:(107, 19)
train df2: (4821, 8), Val df2: (1607, 8), Test df2:(1608, 8)
train df3_filtered: (6931, 19), Val df3_filtered: (2310, 19), Test df3_filtered:(2311, 19)

Было сделано разбиение на три выборки: 60%, 20% и 20% при помощи библиотеки scikit-learn и функции train_test_split. На взгляд сбалансированные

Приращение методами выборки с избытком (oversampling) и выборки с недостатком (undersampling)

In [131]:
from imblearn.over_sampling import ADASYN
from imblearn.under_sampling import RandomUnderSampler

df_train1 = df_train1[['price', 'rating', 'threads', 'ram_storage', 'operating_system', 'new_rating']].copy()

ada = ADASYN()
undersampler = RandomUnderSampler(random_state=42)

print("Выборка до oversampling и undersampling:", df_train1.shape)
print(df_train1.new_rating.value_counts())

X_resampled, y_resampled = ada.fit_resample(df_train1, df_train1['new_rating'])
df_train1_adasyn = pd.DataFrame(X_resampled)

print("Выборка после oversampling: ", df_train1_adasyn.shape)
print(df_train1_adasyn.new_rating.value_counts())

X_resampled_under, y_resampled_under = undersampler.fit_resample(df_train1, df_train1['new_rating'])

print("Выборка после undersampling: ", pd.DataFrame(X_resampled_under).shape)
print(pd.DataFrame(X_resampled_under).new_rating.value_counts())
Выборка до oversampling и undersampling: (319, 6)
new_rating
4    249
3     44
5     26
1      0
2      0
Name: count, dtype: int64
Выборка после oversampling:  (750, 6)
new_rating
5    251
3    250
4    249
1      0
2      0
Name: count, dtype: int64
Выборка после undersampling:  (78, 6)
new_rating
3    26
5    26
4    26
1     0
2     0
Name: count, dtype: int64
In [132]:
df_train2 = df_train2[['Open', 'High', 'new_high', 'Low', 'Close', 'Adj Close', 'Volume']].copy()

print("Выборка до oversampling и undersampling:", df_train2.shape)
print(df_train2.new_high.value_counts())

X_resampled, y_resampled = ada.fit_resample(df_train2, df_train2['new_high'])
df_train2_adasyn = pd.DataFrame(X_resampled)

print("Выборка после oversampling: ", df_train2_adasyn.shape)
print(df_train2_adasyn.new_high.value_counts())

X_resampled_under2, y_resampled_under2 = undersampler.fit_resample(df_train2, df_train2['new_high'])

print("Выборка после undersampling: ", pd.DataFrame(X_resampled_under2).shape)
print(pd.DataFrame(X_resampled_under2).new_high.value_counts())
Выборка до oversampling и undersampling: (4821, 7)
new_high
1     2326
2      704
5      519
3      299
8      242
7      222
9      181
4      151
6      146
10      31
Name: count, dtype: int64
Выборка после oversampling:  (23144, 7)
new_high
8     2374
6     2368
2     2351
4     2335
1     2326
9     2317
10    2312
5     2256
7     2256
3     2249
Name: count, dtype: int64
Выборка после undersampling:  (310, 7)
new_high
1     31
2     31
3     31
4     31
5     31
6     31
7     31
8     31
9     31
10    31
Name: count, dtype: int64
In [133]:
from imblearn.over_sampling import SMOTE

df_train3 = df_train3[['Price', 'new_price','Prod. year' ,'Cylinders' ,'Airbags']].copy()

smote = SMOTE(random_state=42)

print("Выборка до oversampling и undersampling:", df_train3.shape)
print(df_train3.new_price.value_counts())

X_resampled, y_resampled = smote.fit_resample(df_train3, df_train3['new_price'])
df_train3_smote = pd.DataFrame(X_resampled)

print("Выборка после oversampling: ", df_train3_smote.shape)
print(df_train3_smote.new_price.value_counts())

X_resampled_under3, y_resampled_under3 = undersampler.fit_resample(df_train3, df_train3['new_price'])

print("Выборка после undersampling: ", pd.DataFrame(X_resampled_under3).shape)
print(pd.DataFrame(X_resampled_under3).new_price.value_counts())
Выборка до oversampling и undersampling: (6931, 5)
new_price
1    5008
2    1281
3     449
4     136
5      57
Name: count, dtype: int64
Выборка после oversampling:  (25040, 5)
new_price
1    5008
2    5008
3    5008
4    5008
5    5008
Name: count, dtype: int64
Выборка после undersampling:  (285, 5)
new_price
1    57
2    57
3    57
4    57
5    57
Name: count, dtype: int64