2024-11-22 20:35:31 +04:00

199 KiB
Raw Blame History

In [45]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.tree import DecisionTreeRegressor, DecisionTreeClassifier
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import mean_squared_error, f1_score, accuracy_score, roc_auc_score, confusion_matrix, classification_report
df = pd.read_csv("./static/csv/car_price_prediction.csv")
print(df.head())
print(df.columns)
         ID  Price  Levy Manufacturer    Model  Prod. year   Category  \
0  45654403  13328  1399        LEXUS   RX 450        2010       Jeep   
1  44731507  16621  1018    CHEVROLET  Equinox        2011       Jeep   
2  45774419   8467     -        HONDA      FIT        2006  Hatchback   
3  45769185   3607   862         FORD   Escape        2011       Jeep   
4  45809263  11726   446        HONDA      FIT        2014  Hatchback   

  Leather interior Fuel type Engine volume    Mileage  Cylinders  \
0              Yes    Hybrid           3.5  186005 km        6.0   
1               No    Petrol             3  192000 km        6.0   
2               No    Petrol           1.3  200000 km        4.0   
3              Yes    Hybrid           2.5  168966 km        4.0   
4              Yes    Petrol           1.3   91901 km        4.0   

  Gear box type Drive wheels   Doors             Wheel   Color  Airbags  
0     Automatic          4x4  04-May        Left wheel  Silver       12  
1     Tiptronic          4x4  04-May        Left wheel   Black        8  
2      Variator        Front  04-May  Right-hand drive   Black        2  
3     Automatic          4x4  04-May        Left wheel   White        0  
4     Automatic        Front  04-May        Left wheel  Silver        4  
Index(['ID', 'Price', 'Levy', 'Manufacturer', 'Model', 'Prod. year',
       'Category', 'Leather interior', 'Fuel type', 'Engine volume', 'Mileage',
       'Cylinders', 'Gear box type', 'Drive wheels', 'Doors', 'Wheel', 'Color',
       'Airbags'],
      dtype='object')

Предварительная обработка данных

Обработка пропущенных значений

In [46]:
# Очистка столбца 'Levy' от нечисловых значений
df['Levy'] = pd.to_numeric(df['Levy'], errors='coerce')
df['Levy'].fillna(df['Levy'].median(), inplace=True)


# Очистка столбца 'Mileage' от нечисловых значений
df['Mileage'] = df['Mileage'].str.replace(' km', '').astype(float)
df['Mileage'] = pd.to_numeric(df['Mileage'], errors='coerce')

# Проверка типа данных в столбце 'Engine volume'
print(df['Engine volume'].dtype)

# Если столбец 'Engine volume' не является строковым, преобразуем его в строку
if df['Engine volume'].dtype != 'object':
    df['Engine volume'] = df['Engine volume'].astype(str)

# Очистка столбца 'Engine volume' от нечисловых значений
df['Engine volume'] = df['Engine volume'].str.replace(r'[^0-9.]', '', regex=True).astype(float)

# Заполнение пропущенных значений
df['Mileage'].fillna(df['Mileage'].median(), inplace=True)
df['Engine volume'].fillna(df['Engine volume'].median(), inplace=True)

df['Mileage'].fillna(df['Mileage'].mean(), inplace=True)

# Проверка на наличие NaN после заполнения
print("Пропущенные значения после заполнения:")
print(df.isnull().sum())
object
Пропущенные значения после заполнения:
ID                  0
Price               0
Levy                0
Manufacturer        0
Model               0
Prod. year          0
Category            0
Leather interior    0
Fuel type           0
Engine volume       0
Mileage             0
Cylinders           0
Gear box type       0
Drive wheels        0
Doors               0
Wheel               0
Color               0
Airbags             0
dtype: int64
C:\Users\Egor\AppData\Local\Temp\ipykernel_21864\90121908.py:3: 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['Levy'].fillna(df['Levy'].median(), inplace=True)
C:\Users\Egor\AppData\Local\Temp\ipykernel_21864\90121908.py:21: 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['Mileage'].fillna(df['Mileage'].median(), inplace=True)
C:\Users\Egor\AppData\Local\Temp\ipykernel_21864\90121908.py:22: 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['Engine volume'].fillna(df['Engine volume'].median(), inplace=True)
C:\Users\Egor\AppData\Local\Temp\ipykernel_21864\90121908.py:24: 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['Mileage'].fillna(df['Mileage'].mean(), inplace=True)

Кодирование категориальных переменных

In [47]:
from sklearn.calibration import LabelEncoder

le = LabelEncoder()
categorical_cols = ['Manufacturer', 'Model', 'Category', 'Leather interior',
                    'Fuel type', 'Gear box type', 'Drive wheels', 'Doors',
                    'Wheel', 'Color']
for col in categorical_cols:
    df[col] = le.fit_transform(df[col].astype(str))

Масштабирование признаков

Понижение размерности - PCA

Визуализация PCA

Данные распределены вдоль оси X (Главный компонент 1) с некоторым разбросом вдоль оси Y (Главный компонент 2).

Большая часть дисперсии в данных объясняется первой главной компонентой.

Возможно, данные содержат несколько кластеров, которые можно идентифицировать с помощью кластерного анализа.

In [48]:
from pyexpat import features
from sklearn.decomposition import PCA

features = df.drop(['ID', 'Price'], axis=1)

# Масштабирование признаков
scaler = StandardScaler()
X_scaled = scaler.fit_transform(features)

# Проверка на наличие NaN после масштабирования
if np.isnan(X_scaled).any():
    raise ValueError("В масштабированных данных все еще присутствуют NaN.")

# Понижение размерности - PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# Визуализация PCA
plt.scatter(X_pca[:, 0], X_pca[:, 1])
plt.xlabel('Главный компонент 1')
plt.ylabel('Главный компонент 2')
plt.title('Визуализация данных после PCA')
plt.show()
No description has been provided for this image

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

График локтя

In [ ]:
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score


inertia = []
silhouette = []
for k in range(2, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(X_scaled)
    inertia.append(kmeans.inertia_)
    silhouette.append(silhouette_score(X_scaled, kmeans.labels_))

plt.plot(range(2, 11), inertia, marker='o')
plt.xlabel('Количество кластеров (k)')
plt.ylabel('Инерция')
plt.title('Метод локтя для оптимального k')
plt.show()
No description has been provided for this image

График силуэта

In [ ]:
plt.plot(range(2, 11), silhouette, marker='o')
plt.xlabel('Количество кластеров (k)')
plt.ylabel('Коэффициент силуэта')
plt.title('Коэффициент силуэта для оптимального k')
plt.show()
No description has been provided for this image

Предположим, что оптимальное k равно 3 на основе графиков

Иерархическая кластеризация

K-Means кластеризация

Оценка качества кластеризации

In [ ]:
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import davies_bouldin_score


agg_clustering = AgglomerativeClustering(n_clusters=3, linkage='ward')
labels_agg = agg_clustering.fit_predict(X_scaled)

kmeans = KMeans(n_clusters=3, random_state=42)
labels_kmeans = kmeans.fit_predict(X_scaled)


silhouette_agg = silhouette_score(X_scaled, labels_agg)
davies_bouldin_agg = davies_bouldin_score(X_scaled, labels_agg)

silhouette_kmeans = silhouette_score(X_scaled, labels_kmeans)
davies_bouldin_kmeans = davies_bouldin_score(X_scaled, labels_kmeans)

print(f"Коэффициент силуэта (Agg): {silhouette_agg}")
print(f"Индекс Дэвиса-Болдина (Agg): {davies_bouldin_agg}")
print(f"Коэффициент силуэта (KMeans): {silhouette_kmeans}")
print(f"Индекс Дэвиса-Болдина (KMeans): {davies_bouldin_kmeans}")
Коэффициент силуэта (Agg): 0.13306117230156736
Индекс Дэвиса-Болдина (Agg): 2.5089898754817166
Коэффициент силуэта (KMeans): 0.17159548190302554
Индекс Дэвиса-Болдина (KMeans): 2.23429912220393

Визуализация кластеров

In [ ]:
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels_kmeans)
plt.xlabel('Главный компонент 1')
plt.ylabel('Главный компонент 2')
plt.title('Визуализация кластеров (K-Means)')
plt.show()
No description has been provided for this image