152 KiB
152 KiB
1-й Датасет: Mobile Phone Price Prediction¶
https://www.kaggle.com/datasets/dewangmoghe/mobile-phone-price-prediction?resource=download
- Из названия датасета(описания у Kaggle не было предсталвено) очевидно, что объектами иследования являются смартфоны.
- Атрибуты объектов: id, name, spec_score, no_of_sim, RAM, battery, display, camera, external_memory, android_version, price, company, inbuilt_memory, fast_charging, screen_resolution, processor, processor_name
- Очевидная цель этого датасета - научиться предсказывать цену смартфона.
In [6]:
import pandas as pd
df = pd.read_csv(".//static//csv//mppp.csv", sep=",")
print('количество колонок: ' + str(df.columns.size))
print('колонки: ' + ', '.join(df.columns))
df.info()
df.head()
Out[6]:
Получение сведений о пропущенных данных¶
Типы пропущенных данных:
- None - представление пустых данных в Python
- NaN - представление пустых данных в Pandas
- '' - пустая строка
In [7]:
# Количество пустых значений признаков
print(df.isnull().sum())
print()
# Есть ли пустые значения признаков
print(df.isnull().any())
print()
# Процент пустых значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f"{i} процент пустых значений: %{null_rate:.2f}")
Судя по статистике выше, пустые значения всё-таки присутствуют. Наиболее корректным решением будет заполнение пропущенных данных, потому что количество объектов с пропущенными значениями составляет практически половину объектов датасета. Так как все атрибуты имеют строковый тип данных, воспользуемся заполнением наиболее частым значением.
In [11]:
df['Inbuilt_memory'].fillna(df['Inbuilt_memory'].mode()[0], inplace=True)
df['Processor'].fillna(df['Processor'].mode()[0], inplace=True)
df['Android_version'].fillna(df['Android_version'].mode()[0], inplace=True)
df['fast_charging'].fillna(df['fast_charging'].mode()[0], inplace=True)
df['Screen_resolution'].fillna(df['Screen_resolution'].mode()[0], inplace=True)
# Количество пустых значений признаков
print(df.isnull().sum())
print()
# Есть ли пустые значения признаков
print(df.isnull().any())
print()
# Процент пустых значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f"{i} процент пустых значений: %{null_rate:.2f}")
Проверим выбросы и устраним их:
In [14]:
numeric_columns = ['Name', 'Rating', 'Spec_score', 'No_of_sim', 'Ram', 'Battery', 'Display', 'Camera', 'External_Memory', 'Android_version', 'Price', 'company', 'Inbuilt_memory', 'fast_charging', 'Screen_resolution', 'Processor', 'Processor_name']
for column in numeric_columns:
if pd.api.types.is_numeric_dtype(df[column]): # Проверяем, является ли колонка числовой
q1 = df[column].quantile(0.25) # Находим 1-й квартиль (Q1)
q3 = df[column].quantile(0.75) # Находим 3-й квартиль (Q3)
iqr = q3 - q1 # Вычисляем межквартильный размах (IQR)
# Определяем границы для выбросов
lower_bound = q1 - 1.5 * iqr # Нижняя граница
upper_bound = q3 + 1.5 * iqr # Верхняя граница
# Подсчитываем количество выбросов
outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
outlier_count = outliers.shape[0]
# Устраняем выбросы: заменяем значения ниже нижней границы на саму нижнюю границу, а выше верхней — на верхнюю
df[column] = df[column].apply(lambda x: lower_bound if x < lower_bound else upper_bound if x > upper_bound else x)
print(f"Колонка {column}:")
print(f" Есть выбросы: {'Да' if outlier_count > 0 else 'Нет'}")
print(f" Количество выбросов: {outlier_count}")
print(f" Минимальное значение: {df[column].min()}")
print(f" Максимальное значение: {df[column].max()}")
print(f" 1-й квартиль (Q1): {q1}")
print(f" 3-й квартиль (Q3): {q3}\n")
Постараемся выявить зависимости Outcome от остальных колонок:
In [28]:
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
# Сначала Label Encoding для упорядоченных категорий (если нужно)
label_encoder = LabelEncoder()
for column in df.columns:
if df[column].dtype == 'object': # Если тип данных - строка
if df[column].nunique() <= 10: # Если небольшое количество уникальных значений, применяем One-Hot Encoding
df = pd.get_dummies(df, columns=[column], drop_first=True)
else:
df[column] = label_encoder.fit_transform(df[column])
# Удаление строки "Price" из признаков (она является целевой переменной)
X = df.drop('Price', axis=1) # Все признаки, кроме цены
y = df['Price']
# Создание модели RandomForestRegressor
model = RandomForestRegressor()
model.fit(X, y)
# Определение важности признаков
feature_importances = model.feature_importances_
features = X.columns
# Визуализация важности признаков
plt.figure(figsize=(10, 8))
plt.barh(features, feature_importances)
plt.title('Feature Importance for Price Prediction')
plt.xlabel('Importance')
plt.ylabel('Features')
plt.show()
In [29]:
from sklearn.model_selection import train_test_split
# Разделение на признаки (X) и целевую переменную (y)
X = df.drop('Price', axis=1) # Все признаки, кроме цены
y = df['Price'] # Целевая переменная (цена)
# Сначала разбиваем данные на обучающую и промежуточную выборки (80% обучающих данных и 20% тестовых)
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
# Теперь делим временные данные (X_temp и y_temp) на контрольную (валидационную) и тестовую выборки (по 20% каждой)
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}')
print(f'Размер контрольной выборки: {X_val.shape}')
print(f'Размер тестовой выборки: {X_test.shape}')