986 KiB
- Продажи домов
- Данные о населении
- Набор данных для анализа и прогнозирования сердечного приступа
Продажа домов
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")
Столбцы для русских:
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: Площадь участка соседних домов
Проблемная область: Прогнозирование стоимости недвижимости в зависимости от характеристик дома.
print(df.info, "\n")
Объектом наблюдения является - Недвижимость
Атрибуты - содержит набор информации о продаже дома, такие как:
цену продажи, дата продажи, количество спален, ванных комнат, общую площадь дома, площадь участка, местоположение.
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()
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()
Связь между объектами есть. Цена связана почти со всеми характиристиками дома.
Например на графике номер один показана зависимоость между ценой и размером дома.
А на графике номер 2 показа зависимость состояния домов с годами.
Примеры бизнес целей
- Прогнозирование стоимости недвижимости на основе характиристик дома.
- Наблюдение за изменениями характиристик дома с годами.
Эффект для бизнеса: Оценка и оптимизация цен, Оценка и планирование затрат, выявление тенденции на рынке, стратегия планирования.
Цели технического проекта
- Для первой цели:
- Для второй цели:
Код ниже нужен для определения проблем данных
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)
Из полученных данных выяснилось:
Примеры решения проблем для набора данных
Оценка качества данных
1. Информативность. Набор данных предоставляет достаточную информацию для анализа цен на недвижимость. 2. Степень покрытия. Набор данных затрагивает только один райно, не включая информацию о других райнов. 3. Соответствие реальным данным. Данные вполне кажутся реальными, не считая некоторых редких выбросов. 4. Согласованность меток. Метки состояние и оценка вида, имеют четкие значения.Разбиение данных на обучающую, контрольную и тестовую выборки
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]} строк")
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, "тестовой")
Oversampling и undersampling
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())
Оценка сбалансированности выборок
Оценка необходимости аугментации данных
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, "тестовой")
Поскольку все выборки демонстрируют одинаковое распределение целевого признака и сбалансированное распределение значений, применение методов аугментации не требуется.
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())
В этом исследование данные не сбалансированы, поэтому требуется аугментация.
Данные о населении
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')
Объектом наблюдения является страны и информация о их наслении.
Атрибуты объекта: Страна, Население, Годовое изменение, NetChange, Плотность, Площадь суши, Мигранты, Fert.Rate, Средний возраст, UrbanPop%, Доля в мире;
Связь между объектами: имеется связь между атрибутами, например между Коэффициент фертильности и Плотностю населения.
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()
В регионах с низкой плотностью населения рождаемость значительно варьируется, в то время как в регионах с плотностью более 400 чел./км² наблюдается более стабильная и высокая рождаемость.
Бизнес-цели
- Бизнес-цель: Определение наилучших стран для выхода на рынок товаров и услуг, связанных с материнством и детством.
Эффект для бизнеса: Возможность выбора стран с высоким уровнем рождаемости и значительным числом молодых семей для запуска маркетинговых кампаний и открытия новых филиалов.
- Цели технического проекта:
- Построить модель для определения стран с высоким потенциалом развития рынка товаров для детей и матерей.
- Входные признаки: Плотность населения, Уровень рождаемости, Средний возраст, Доля городского населения.
- Целевой признак: Страна с высоким или низким потенциалом для выхода на рынок.
- Бизнес-цель: Оптимизация стратегий миграционной политики. Эффект для бизнеса: Компании, предоставляющие услуги в области миграции, найма и адаптации, могут использовать эти данные для выбора мест, где их услуги будут наиболее востребованы.
- Цели технического проекта:
- Построить модель, определяющую страны с наибольшим оттоком мигрантов и прогнозировать влияние миграции на рынок труда.
- Входные признаки: Годовое изменение населения, Плотность населения, Доля городского населения.
- Целевой признак: Уровень чистой миграции.
- Бизнес-цель: Определение экономического потенциала стран на основе плотности населения и уровня урбанизации. Эффект для бизнеса: Компании могут определить страны с высоким уровнем урбанизации и значительной плотностью населения для открытия новых офисов, производств или филиалов.
- Цели технического проекта:
- Создать модель для ранжирования стран по их экономическому потенциалу на основе демографических данных.
- Входные признаки: Плотность населения, Уровень урбанизации, Средний возраст, Доля городского населения.
- Целевой признак: Оценка экономического потенциала.
Поиск проблем
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()
Из матрицы корреляции можно сделать выводы отностительно зависимости между атрибутами и выявит наиболее бесполезные их них. Признаки с низкими корреляциями, такие как Density (P/Km²), Population 2020, и World Share, могут содержать шум или не являться значимыми для текущей задачи демографического анализа. Это не обязательно означает, что эти переменные всегда шумны, но в контексте анализа они могут оказаться несущественными.
Проведем анализа остаточных ошибок, чтобы убедиться в том, что выше упомянутые атрибуты действиельно бесполезны в данном контексе.
По итогу вышло больше количество шумов
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}")
Определяем смещение. Если разница между средним и медианным значениями существенна, это может указывать на смещение. В данном случаем имеется смещение.
# Приведение столбцов к числовым значениям
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)' не обнаружено.")
Тут я хочу выявить просачивание данных. Для этого хочу сравнить прирост населения и количество мигрантов с численности населения в 2020 году. Логично, если они окажутся больше общий численности населения это окажется странным. В данном случае все оказалось нормально и не какие данные не просачились.
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("Выбросы заменены медианными значениями.")
Решили проблему с выбрасами
Оценка качества набора данных:
Информативность: Набор данных содержит информацию о населении стран мира на 2020 год, включая демографические показатели, такие как плотность населения, прирост населения, уровень урбанизации и другие. Колонки достаточно подробные и содержат ключевые метрики.
Степень покрытия: В наборе данных представлены 235 стран и зависимых территорий, что охватывает практически весь мир. Это достаточно полный охват для анализа глобального населения.
Соответствие реальным данным: Данные взяты из показателей 2020 года.
Согласованность меток: Имена колонок не всегда очевидны (например, "Density (P/Km²)", "World Share"). Также данные представлены в разных форматах, что требует предобработки, так как числовые значения сохранены как строки.
Устранение проблемы пропущенных данных
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()} пропущенных значений осталось")
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]} строк")
# Проверка распределения целевой переменной в обучающей, валидационной и тестовой выборках
print("Распределение в обучающей выборке:\n", y_train.describe())
print("Распределение в валидационной выборке:\n", y_val.describe())
print("Распределение в тестовой выборке:\n", y_test.describe())
Дисбаланс данных:
В обучающей выборке среднее значение численности населения составляет около 48 миллионов, однако максимальное значение достигает 1.44 миллиарда, что указывает на значительный разброс данных. Стандартное отклонение в обучающей выборке очень велико (188 миллионов), что указывает на присутствие значительного числа стран с огромным населением (например, Китай и Индия), наряду с малонаселёнными странами. В валидационной и тестовой выборках также наблюдается высокий разброс, хотя их максимальные значения намного ниже (212 и 331 миллионов соответственно).
Методы приращения данных могут быть полезный, поэтому я ими воспользуюсь
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]} строк")
3 Датасет - Данные о миллионерах
df3 = pd.read_csv("..//static//csv//Forbes Billionaires.csv", index_col="Rank ")
print(df3.columns, "\n")
Основные столбцы: Rank: Ранг миллиардера Name: Имя миллиардера Networth: Состояние миллиардера (в миллиардах долларов) Age: Возраст миллиардера Country: Страна проживания миллиардера Source: Основной источник дохода Industry: Отрасль, к которой относится основная деятельность миллиардера
Проблемная область
Данный набор данных относится к анализу благосостояния, его распределению по возрастам, странам и отраслям. Проблемная область связана с миллионерами и с изучением неравенства богатства, выявлением тенденций в источниках доходов и влиянии различных факторов на накопление капитала.
Анализ содержимого
- Объекты наблюдения: Миллиардеры
- Атрибуты объектов: Ранг, имя, состояние, возраст, страна, источник дохода, отрасль
- Связи между объектами: Можно выявить связи между возрастом и состоянием, страной проживания и источником дохода, а также отраслью и уровнем благосостояния.
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()
Тут для наглядности вывел графики зависимостей
Примеры бизнес-целей
- Бизнес может использовать эти данные для анализа того, какие отрасли являются наиболее прибыльными и перспективными.
- Компании могут использовать эти данные для анализа возрастных моделей накопления капитала, что помогает лучше планировать инвестиции и маркетинг.
- Бизнес может понять, какие страны являются наиболее подходящими для инвестиций и предпринимательства.
Цели технического проекта
Вход: Данные по состоянию и источникам доходов.
Целевой признак: Отрасль, состояние.Вход: Данные по возрасту и состоянию.
Целевой признак: Возраст, состояние.Вход: Данные по странам и состоянию.
Целевой признак: Страна, состояние.
Выявляем проблемы(и решаем их)
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)
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)
Хотел проверить смещение. В данном случае имеется смещение по регионам или отраслям. Но думаю это особенность данного датасета, а не самих данных.
# 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
Проверка оценки информативности. Тут все нормально
# Проверка на согласованность категорий
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()
Для оценки покрытия мы смотрим на то, насколько разнообразны данные по странам, отраслям и возрастам.
Устранение проблемы пропущенных данных
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
Разбиение набора данных на обучающую, контрольную и тестовую выборки
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)
Оценка сбалансированности выборок
# Проверка распределения целевого признака по выборкам
train_dist = y_train.describe()
val_dist = y_val.describe()
test_dist = y_test.describe()
train_dist, val_dist, test_dist
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)