443 KiB
1-й Датасет: Pima Indians Diabetes Database¶
https://www.kaggle.com/datasets/uciml/pima-indians-diabetes-database
Этот набор данных получен Национальным институтом диабета, болезней органов пищеварения и почек. Цель набора данных - диагностически предсказать, есть ли у пациента диабет, на основе определенных диагностических измерений, включенных в набор данных. При отборе этих случаев из более обширной базы данных было наложено несколько ограничений. В частности, все пациенты здесь - женщины не моложе 21 года индейского происхождения Пима.
- Из описания датасета очевидно, что объектами иследования являются женьщины индейци пима.
- Атрибуты объектов: Pregnancies,Glucose,BloodPressure,SkinThickness,Insulin,BMI,DiabetesPedigreeFunction,Age,Outcome
- Очевидная цель этого датасета - научиться предсказывать диабет.
В качестве примера бизнес-целей можно привести:
- Повышение качества жизни пациентов. Цель технического проекта: Разработать интерфейс для модели, который будет предоставлять пациентам персонализированные рекомендации по профилактике и лечению диабета на основе их индивидуальных рисков, определенных моделью.
- Повышение эффективности скрининга диабета. Цель технического проекта: Разработать и обучить модель машинного обучения с точностью предсказания не менее 85% для автоматизированного скрининга диабета на основе данных датасета "Диабет у индейцев Пима".
- Снижение медицинских расходов. Цель технического проекта: Оптимизировать модель прогнозирования таким образом, чтобы минимизировать количество ложноотрицательных результатов (пациенты с диабетом, которые не были выявлены), что позволит снизить затраты на лечение осложнений.
import pandas as pd
df = pd.read_csv(".//static//csv//diabetes.csv", sep=",")
print('количество колонок: ' + str(df.columns.size))
print('колонки: ' + ', '.join(df.columns))
df.info()
df.head()
Получение сведений о пропущенных данных¶
Типы пропущенных данных:
- None - представление пустых данных в Python
- NaN - представление пустых данных в Pandas
- '' - пустая строка
# Количество пустых значений признаков
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}")
Судя по статистике выше, пустые значения отсутсвуют. Проверим датасет на выбросы:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv(".//static//csv//diabetes.csv")
# Выбираем числовые столбцы
numeric_columns = ['Pregnancies', 'Glucose', 'BloodPressure']
# Выбираем столбцы для анализа
columns_to_check = ['Pregnancies', 'Glucose', 'BloodPressure']
# Функция для подсчета выбросов
def count_outliers(df, columns):
outliers_count = {}
for col in columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Считаем количество выбросов
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
outliers_count[col] = len(outliers)
return outliers_count
# Подсчитываем выбросы
outliers_count = count_outliers(df, columns_to_check)
# Выводим количество выбросов для каждого столбца
for col, count in outliers_count.items():
print(f"Количество выбросов в столбце '{col}': {count}")
# Создаем гистограммы
plt.figure(figsize=(15, 10))
for i, col in enumerate(numeric_columns, 1):
plt.subplot(2, 3, i)
sns.histplot(df[col], kde=True)
plt.title(f'Histogram of {col}')
plt.tight_layout()
plt.show()
В принципе, количество выбросов для солбцов 'Pregnancies' и 'Glucose' не так критично, что нельзя сказать про столбец 'BloodPressure'. Сделаем очистку от выбросов для данного столбца:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Выбираем столбцы для очистки
columns_to_clean = ['BloodPressure']
# Функция для удаления выбросов
def remove_outliers(df, columns):
for col in columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Удаляем строки, содержащие выбросы
df = df[(df[col] >= lower_bound) & (df[col] <= upper_bound)]
return df
# Удаляем выбросы
df_cleaned = remove_outliers(df, columns_to_clean)
# Выводим количество удаленных строк
print(f"Количество удаленных строк: {len(df) - len(df_cleaned)}")
df = df_cleaned
# Выбираем столбцы для анализа
columns_to_check = ['BloodPressure']
# Функция для подсчета выбросов
def count_outliers(df, columns):
outliers_count = {}
for col in columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Считаем количество выбросов
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
outliers_count[col] = len(outliers)
return outliers_count
# Подсчитываем выбросы
outliers_count = count_outliers(df, columns_to_check)
# Выводим количество выбросов для каждого столбца
for col, count in outliers_count.items():
print(f"Количество выбросов в столбце '{col}': {count}")
# Создаем гистограммы для очищенных данных
plt.figure(figsize=(15, 6))
# Гистограмма для relative_velocity
plt.subplot(1, 2, 1)
sns.histplot(df_cleaned['BloodPressure'], kde=True)
plt.title('Histogram of Blood Pressure (Cleaned)')
plt.xlabel('Blood Pressure')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()
Судя по данным на диаграмме выше, количество выбросов значительно сократилось и не превышает допустимые диапозоны. Теперь можно приступить к разбиению датасета на выборки:
import pandas as pd
from sklearn.model_selection import train_test_split
# Разделение на признаки (X) и целевую переменную (y)
X = df.drop('Outcome', axis=1) # Признаки
y = df['Outcome'] # Целевая переменная
# Разбиение на обучающую и оставшуюся часть (контрольная + тестовая)
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("Размер обучающей выборки:", X_train.shape[0])
print("Размер контрольной выборки:", X_val.shape[0])
print("Размер тестовой выборки:", X_test.shape[0])
from sklearn.model_selection import train_test_split
# Разделение на признаки (X) и целевую переменную (y)
X = df.drop('Outcome', axis=1) # Признаки
y = df['Outcome'] # Целевая переменная
# Разбиение на обучающую и оставшуюся часть (контрольная + тестовая)
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42, stratify=y)
# Разбиение оставшейся части на контрольную и тестовую выборки
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp)
# Функция для проверки сбалансированности выборок
def check_balance(y_train, y_val, y_test):
print("Сбалансированность обучающей выборки:")
print(y_train.value_counts(normalize=True))
print("\nСбалансированность контрольной выборки:")
print(y_val.value_counts(normalize=True))
print("\nСбалансированность тестовой выборки:")
print(y_test.value_counts(normalize=True))
# Проверка сбалансированности
check_balance(y_train, y_val, y_test)
По данным выше можно понять, что выборки сбалансиированы относительно. Воспользуемся приращением данных методом выборки с избытком (oversampling)
import pandas as pd
from sklearn.model_selection import train_test_split
from imblearn.over_sampling import SMOTE
# Разделение на признаки (X) и целевую переменную (y)
X = df.drop('Outcome', axis=1) # Признаки
y = df['Outcome'] # Целевая переменная
# Разбиение на обучающую и оставшуюся часть (контрольная + тестовая)
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42, stratify=y)
# Разбиение оставшейся части на контрольную и тестовую выборки
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp)
# Применение SMOTE для балансировки обучающей выборки
smote = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)
# Функция для проверки сбалансированности выборок
def check_balance(y_train, y_val, y_test):
print("Сбалансированность обучающей выборки:")
print(y_train.value_counts(normalize=True))
print("\nСбалансированность контрольной выборки:")
print(y_val.value_counts(normalize=True))
print("\nСбалансированность тестовой выборки:")
print(y_test.value_counts(normalize=True))
# Проверка сбалансированности после SMOTE
print("Сбалансированность обучающей выборки после SMOTE:")
print(y_train_resampled.value_counts(normalize=True))
# Проверка сбалансированности контрольной и тестовой выборок
check_balance(y_train_resampled, y_val, y_test)
Выборка сбалансирована
2-й Датасет: Starbucks Stock Price Dataset 📊🍵🧋🔥¶
Starbucks Corporation - всемирно известная сеть кофеен, основанная в 1971 году в Сиэтле, штат Вашингтон, Джерри Болдуином, Зевом Сиглом и Гордоном Боукером. Начав со скромного магазина, торгующего высококачественными кофейными зернами и оборудованием, Starbucks превратилась в одну из крупнейших в мире сетей кофеен с тысячами магазинов по всему миру. Известная своим кофе высшего сорта, инновационными напитками и уникальным обслуживанием клиентов, Starbucks стала культурной иконой кофейной индустрии.
Этот набор данных предоставляет исчерпывающую информацию об изменениях цен на акции Starbucks за последние 25 лет. Он включает в себя важные столбцы, такие как дата, цена открытия, самая высокая цена дня, самая низкая цена дня, цена закрытия, скорректированная цена закрытия и объем торгов.
Эти данные бесценны для проведения исторического анализа, прогнозирования динамики акций в будущем и понимания рыночных тенденций, связанных с акциями Starbucks.
- Из описания датасета очевидно, что объектами иследования являются записи о динамике цены акций.
- Атрибуты объектов: Date,Open,High,Low,Close,Adj Close,Volume
- Очевидная цель этого датасета - научиться предсказывать цены на акции.
В качестве примера бизнес-целей можно привести:
- Предсказание будущих цен акций: Использовать исторические данные для прогнозирования будущих цен акций Starbucks.
- Анализ волатильности: Оценка волатильности акций на основе исторических данных, что поможет принять более информированные решения для инвестиций.
- Оптимизация торговых стратегий: Разработка стратегий для покупки и продажи акций на основе определённых индикаторов или паттернов поведения цен.
import pandas as pd
df = pd.read_csv(".//static//csv//sd.csv", sep=",")
print('количество колонок: ' + str(df.columns.size))
print('колонки: ' + ', '.join(df.columns))
df.info()
df.head()
Получение сведений о пропущенных данных¶
Типы пропущенных данных:
- None - представление пустых данных в Python
- NaN - представление пустых данных в Pandas
- '' - пустая строка
# Количество пустых значений признаков
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}")
Судя по статистике выше, пустые значения отсутсвуют. Проверим датасет на выбросы:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv(".//static//csv//sd.csv")
# Выбираем числовые столбцы
numeric_columns = ['Open','High','Low','Close','Adj Close']
# Выбираем столбцы для анализа
columns_to_check = ['Open','High','Low','Close','Adj Close']
# Функция для подсчета выбросов
def count_outliers(df, columns):
outliers_count = {}
for col in columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Считаем количество выбросов
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
outliers_count[col] = len(outliers)
return outliers_count
# Подсчитываем выбросы
outliers_count = count_outliers(df, columns_to_check)
# Выводим количество выбросов для каждого столбца
for col, count in outliers_count.items():
print(f"Количество выбросов в столбце '{col}': {count}")
# Создаем гистограммы
plt.figure(figsize=(15, 10))
for i, col in enumerate(numeric_columns, 1):
plt.subplot(2, 3, i)
sns.histplot(df[col], kde=True)
plt.title(f'Histogram of {col}')
plt.tight_layout()
plt.show()
Судя по диаграммам, количетв выбросов либо полностью отсутсвует, либо имеется в пределах допустимых значений. Теперь можно приступить к разбиению датасета на выборки, но теперь используем прописанные реализации методов приращения данных:
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
label_encoder = LabelEncoder()
# Функция для применения oversampling
def apply_oversampling(X, y):
oversampler = RandomOverSampler(random_state=42)
X_resampled, y_resampled = oversampler.fit_resample(X, y)
return X_resampled, y_resampled
# Функция для применения undersampling
def apply_undersampling(X, y):
undersampler = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = undersampler.fit_resample(X, y)
return X_resampled, y_resampled
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,
):
"""
Splits a Pandas dataframe into three subsets (train, val, and test)
following fractional ratios provided by the user, where each subset is
stratified by the values in a specific column (that is, each subset has
the same relative frequency of the values in the column). It performs this
splitting by running train_test_split() twice.
Parameters
----------
df_input : Pandas dataframe
Input dataframe to be split.
stratify_colname : str
The name of the column that will be used for stratification. Usually
this column would be for the label.
frac_train : float
frac_val : float
frac_test : float
The ratios with which the dataframe will be split into train, val, and
test data. The values should be expressed as float fractions and should
sum to 1.0.
random_state : int, None, or RandomStateInstance
Value to be passed to train_test_split().
Returns
-------
df_train, df_val, df_test :
Dataframes containing the three splits.
"""
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
data = df[["Volume", "High", "Low"]].copy()
data["Volume_Grouped"] = pd.cut(data["Volume"], bins=50, labels=False)
interval_counts = data["Volume_Grouped"].value_counts().sort_index()
min_samples_per_interval = 5
for interval, count in interval_counts.items():
if count < min_samples_per_interval:
data.loc[data["Volume_Grouped"] == interval, "Volume_Grouped"] = -1
df_coffee_train, df_coffee_val, df_coffee_test = split_stratified_into_train_val_test(
data, stratify_colname="Volume_Grouped", frac_train=0.60, frac_val=0.20, frac_test=0.20)
print("Обучающая выборка: ", df_coffee_train.shape)
print(df_coffee_train["Volume_Grouped"].value_counts())
X_resampled, y_resampled = apply_oversampling(df_coffee_train, df_coffee_train["Volume_Grouped"])
df_coffee_train_adasyn = pd.DataFrame(X_resampled)
print("Обучающая выборка после oversampling: ", df_coffee_train_adasyn.shape)
print(df_coffee_train_adasyn["Volume_Grouped"].value_counts())
print("Контрольная выборка: ", df_coffee_val.shape)
print(df_coffee_val["Volume_Grouped"].value_counts())
print("Тестовая выборка: ", df_coffee_test.shape)
print(df_coffee_test["Volume_Grouped"].value_counts())
Выборка сбалансирована
3-й Датасет: Supermarket store branches sales analysis¶
Супермаркет - это магазин самообслуживания, предлагающий широкий ассортимент продуктов питания, напитков и товаров для дома, организованный по разделам. Этот магазин больше и имеет более широкий выбор, чем предыдущие продуктовые магазины, но меньше по размеру и более ограничен в ассортименте товаров, чем гипермаркет или рынок больших коробок. Однако в повседневном использовании в США термин "продуктовый магазин" является синонимом слова "супермаркет" и не используется для обозначения других типов магазинов, торгующих продуктами.
- Из описания датасета очевидно, что объектами иследования являются магазины.
- Атрибуты объектов: Store ID,Store_Area,Items_Available,Daily_Customer_Count,Store_Sales
- Очевидная цель этого датасета - научиться предсказывать объем продаж на основе таких характеристик, как площадь магазина и другие факторы.
В качестве примера бизнес-целей можно привести:
- Оптимизация работы магазинов. Это может включать выявление тех характеристик магазинов (например, площадь, местоположение), которые наиболее сильно влияют на уровень продаж, и разработку стратегий для повышения этих продаж на основе этих факторов.
- Другая возможная цель заключается в расширении или перемещении магазинов, где данные могут использоваться для принятия решений о выборе местоположений, оптимальном использовании пространства и планировке магазинов для максимизации продаж.
- Также может быть целью управление запасами и ресурсами, поскольку понимание того, как площадь магазина влияет на объем продаж, поможет лучше управлять запасами и распределением ресурсов.
import pandas as pd
df = pd.read_csv(".//static//csv//Stores.csv", sep=",")
print('количество колонок: ' + str(df.columns.size))
print('колонки: ' + ', '.join(df.columns))
df.info()
df.head()
Получение сведений о пропущенных данных¶
Типы пропущенных данных:
- None - представление пустых данных в Python
- NaN - представление пустых данных в Pandas
- '' - пустая строка
# Количество пустых значений признаков
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}")
Судя по статистике выше, пустые значения отсутсвуют. Проверим датасет на выбросы:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv(".//static//csv//Stores.csv")
# Выбираем числовые столбцы
numeric_columns = ['Store_Area','Items_Available','Daily_Customer_Count','Store_Sales']
# Выбираем столбцы для анализа
columns_to_check = ['Store_Area','Items_Available','Daily_Customer_Count','Store_Sales']
# Функция для подсчета выбросов
def count_outliers(df, columns):
outliers_count = {}
for col in columns:
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Считаем количество выбросов
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
outliers_count[col] = len(outliers)
return outliers_count
# Подсчитываем выбросы
outliers_count = count_outliers(df, columns_to_check)
# Выводим количество выбросов для каждого столбца
for col, count in outliers_count.items():
print(f"Количество выбросов в столбце '{col}': {count}")
# Создаем гистограммы
plt.figure(figsize=(15, 10))
for i, col in enumerate(numeric_columns, 1):
plt.subplot(2, 3, i)
sns.histplot(df[col], kde=True)
plt.title(f'Histogram of {col}')
plt.tight_layout()
plt.show()
Судя по диаграммам, количетв выбросов либо полностью отсутсвует, либо имеется в пределах допустимых значений. Теперь можно приступить к разбиению датасета на выборки:
data = df[["Store_Sales", "Store_Area", "Daily_Customer_Count"]].copy()
data["Sales_Grouped"] = pd.cut(data["Store_Sales"], bins=6, labels=False)
interval_counts = data["Sales_Grouped"].value_counts().sort_index()
min_samples_per_interval = 10
for interval, count in interval_counts.items():
if count < min_samples_per_interval:
data.loc[data["Sales_Grouped"] == interval, "Sales_Grouped"] = -1
df_shop_train, df_shop_val, df_shop_test = split_stratified_into_train_val_test(
data, stratify_colname="Sales_Grouped", frac_train=0.60, frac_val=0.20, frac_test=0.20)
print("Обучающая выборка: ", df_shop_train.shape)
print(df_shop_train["Sales_Grouped"].value_counts())
X_resampled, y_resampled = apply_oversampling(df_shop_train, df_shop_train["Sales_Grouped"])
df_shop_train_adasyn = pd.DataFrame(X_resampled)
print("Обучающая выборка после oversampling: ", df_shop_train_adasyn.shape)
print(df_shop_train_adasyn["Sales_Grouped"].value_counts())
print("Контрольная выборка: ", df_shop_val.shape)
print(df_shop_val["Sales_Grouped"].value_counts())
print("Тестовая выборка: ", df_shop_test.shape)
print(df_shop_test["Sales_Grouped"].value_counts())
Выборка сбалансирована