ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 22.11.2023
Просмотров: 125
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Для начала мы прочитаем и обработаем данные с помощью pandas, которые мы представили в Разделе 2.2. Итак, вам нужно убедиться, что у вас установлены панды, прежде чем продолжить. К счастью, если вы читаете в Jupyter, мы можем установить панды, даже не выходя из ноутбука.
# If pandas is not installed, please uncomment the following line:
# !pip install pandas
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import gluon, autograd, init, np, npx
from mxnet.gluon import nn
import pandas as pd
npx.set_np()
Для удобства мы можем загрузить и кэшировать набор данных о жилье Kaggle, используя сценарий, который мы определили выше.
DATA_HUB['kaggle_house_train'] = ( #@save
DATA_URL + 'kaggle_house_pred_train.csv',
'585e9cc93e70b39160e7921475f9bcd7d31219ce')
DATA_HUB['kaggle_house_test'] = ( #@save
DATA_URL + 'kaggle_house_pred_test.csv',
'fa19780a7b011d9b009e8bff8e99922a8ee2eb90')
Мы используем pandas для загрузки двух файлов csv, содержащих данные для обучения и тестирования соответственно.
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))
Downloading ../data/kaggle_house_pred_train.csv from http://d2l-data.s3-accelerate.amazonaws.
,→com/kaggle_house_pred_train.csv...
Downloading ../data/kaggle_house_pred_test.csv from http://d2l-data.s3-accelerate.amazonaws.
,→com/kaggle_house_pred_test.csv...
Набор обучающих данных включает 1460 примеров, 80 функций и 1 метку, а тестовые данные содержат 1459 примеров и 80 функций.
print(train_data.shape)
print(test_data.shape)
(1460, 81)
(1459, 80)
Давайте посмотрим на первые четыре и последние две функции, а также на метку (SalePrice) из первых четырех примеров.
print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])
| Иденти фикатор | MSSub Class | MSЗони рование | ЛотФрон тальная | Тип продажи | Условия Продажи | Цена продажи |
0 | 1 | 60 | RL | 65.0 | WD | Normal | 208500 |
1 | 2 | 20 | RL | 80.0 | WD | Normal | 181500 |
2 | 3 | 60 | RL | 68.0 | WD | Normal | 223500 |
3 | 4 | 70 | RL | 60.0 | WD | Abnorml | 140000 |
Мы видим, что в каждом примере первая функция - это идентификатор. Это помогает модели идентифицировать каждый обучающий пример. Это удобно, но не несет никакой информации для целей прогнозирования. Следовательно, мы удаляем его из набора данных перед подачей данных в модель.
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
-
Предварительная обработка данных
Как было сказано выше, у нас есть большое разнообразие типов данных. Прежде чем мы сможем приступить к моделированию, нам нужно будет предварительно обработать данные. Начнем с числовых характеристик. Сначала мы применяем эвристику, заменяя все отсутствующие значения средним значением соответствующей функции. Затем, чтобы привести все функции к общему масштабу, мы стандартизируем данные, масштабируя функции до нулевого среднего и единичной дисперсии:
x ← (х - µ)/σ, (5.10.1)
Чтобы убедиться, что это действительно преобразует нашу функцию (переменную) таким образом, что она имеет нулевое среднее значение и единичную дисперсию, обратите внимание, что
E [(х-μ)/σ] = (µ − µ)/σ = 0 и что E [(x − µ)2] = (σ2 + µ2) -2μ2 + µ2 = σ2.
Наглядно, мы стандартизируем данные по двум причинам. Во-первых, это удобно для оптимизации. Во-вторых, поскольку мы априори не знаем, какие функции будут релевантными, мы не хотим штрафовать коэффициенты, назначенные одной функции, больше, чем любой другой.
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
all_features[numeric_features] = all_features[numeric_features].apply(
lambda x: (x - x.mean()) / (x.std()))
# После стандартизации данных все средства исчезнут, поэтому мы можем установить пропущенные значения до 0
all_features [numeric_features] = all_features [numeric_features] .fillna (0)
Далее мы имеем дело с дискретными значениями. Сюда входят такие функции, как «MSZoning». Мы заменяем их быстрым кодированием таким же образом, как мы ранее преобразовывали метки мультиклассов в векторы (см. Раздел 3.4.1). Например, «MSZoning» принимает значения «RL» и «RM». При отказе от функции «MSZoning» создаются две новые функции индикатора «MSZoning_RL» и «MSZoning_RM» со значениями, равными 0 или 1. Согласно однократному кодированию, если исходным значением «MSZoning» является «RL», то « MSZoning_RL »равно 1, а« MSZoning_RM »- 0. Пакет pandas делает это автоматически за нас.
# `Dummy_na = True` считает" na "(отсутствующее значение) допустимым значением функции, и
# создает для него функцию индикатора all_features = pd.get_dummies (all_features, dummy_na = True)
all_features.shape
(2919, 331)
Вы можете видеть, что это преобразование увеличивает количество функций с 79 до 331. Наконец, с помощью атрибута values мы можем извлечь формат NumPy из формата pandas и преобразовать его в формат тензорного представления для обучения.
n_train = train_data.shape [0]
train_features = np.array (all_features [: n_train] .values, dtype = np.float32)
test_features = np.array (all_features [n_train:]. values, dtype = np.float32)
train_labels = np.array (
train_data.SalePrice.values.reshape (-1, 1), dtype = np.float32)
- 1 2 3 4 5 6 7 8 9
Обучение
Для начала обучим линейную модель с квадратом потерь. Неудивительно, что наша линейная модель не приведет к победе в конкурсе, но она обеспечивает проверку работоспособности, чтобы увидеть, есть ли в данных значимая информация. Если здесь мы не можем сделать лучше, чем случайное угадывание, то есть большая вероятность, что у нас есть ошибка обработки данных. И если что-то сработает, линейная модель будет служить базой, давая нам некоторую интуицию о том, насколько простая модель приближается к лучшим моделям, о которых сообщают, что дает нам представление о том, какой выгоды мы должны ожидать от более привлекательных моделей.
loss = gluon.loss.L2Loss()
def get_net():
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize()
return net
В отношении цен на жилье, как и в случае цен на акции, мы больше заботимся об относительных количествах, чем об абсолютных. Таким образом, мы склонны больше заботиться об относительной ошибке (y − yˆ)/y, чем об абсолютной ошибке y - yˆ.
Например, если наш прогноз не соответствует 100 000 долларов США при оценке цены дома в сельской местности Огайо, где стоимость типичного дома составляет 125 000 долларов США, то мы, вероятно, делаем ужасную работу.
С другой стороны, если мы ошибемся на эту сумму в Лос-Альтос-Хиллз, Калифорния, это может представлять потрясающе точный прогноз (там средняя цена дома превышает 4 миллиона долларов США).
Один из способов решения этой проблемы - измерить расхождение в логарифмах оценок цен. Фактически, это также официальная мера погрешности, используемая конкурентами для оценки качества представленных материалов. Ведь малое значение δ для | log y - log yˆ | ≤ δ переводится в e−δ ≤ yˆ/y ≤ eδ. Это приводит к следующей среднеквадратической ошибке между логарифмом прогнозируемой цены и логарифмом цены этикетки:
(1/n ∑ni = 1 (log yi - log yˆi)2)1/2, (5.10.2)
def log_rmse(net, features, labels):
# Для дальнейшей стабилизации значения после логарифмирования установите значение меньше 1 как 1
clipped_preds = np.clip(net(features), 1, float('inf'))
return np.sqrt(2 * loss(np.log(clipped_preds), np.log(labels)).mean())
В отличие от предыдущих разделов, наши обучающие функции будут полагаться на оптимизатор Adam (мы опишем его более подробно позже). Основная привлекательность этого оптимизатора заключается в том, что, несмотря на то, что он не работает лучше (а иногда и хуже) при неограниченных ресурсах для оптимизации гиперпараметров, люди склонны обнаруживать, что он значительно менее чувствителен к начальной скорости обучения.
def train (net, train_features, train_labels, test_features, test_labels,
num_epochs, learning_rate, weight_decay, batch_size):
train_ls, test_ls = [], []
train_iter = d2l.load_array ((train_features, train_labels), batch_size)
# Здесь используется алгоритм оптимизации Адама
trainer = gluon.Trainer(net.collect_params(), 'adam', {
'learning_rate': learning_rate, 'wd': weight_decay})
for epoch in range(num_epochs):
for X, y in train_iter:
with autograd.record():
l = loss(net(X), y)
l.backward()
trainer.step(batch_size)
train_ls.append(log_rmse(net, train_features, train_labels))
if test_labels is not None:
test_ls.append(log_rmse(net, test_features, test_labels))
return train_ls, test_ls
-
Перекрестная проверка K-Fold
Как вы помните, мы представили K-кратную перекрестную проверку в разделе, где мы обсуждали, как работать с выбором модели (раздел 5.4). Мы применим это к выбору дизайна модели и корректировке гиперпараметров. Сначала нам нужна функция, которая возвращает i-ю кратность данных в K-кратной процедуре перекрестной проверки. Он продолжается путем вырезания i-го сегмента в качестве данных проверки и возврата остальных в качестве данных обучения. Обратите внимание, что это не самый эффективный способ обработки данных, и мы определенно сделали бы что-то более умное, если бы наш набор данных был значительно больше. Но эта дополнительная сложность может без надобности запутать наш код, поэтому мы можем спокойно опустить его здесь из-за простоты нашей проблемы.
def get_k_fold_data(k, i, X, y):
assert k > 1
fold_size = X.shape[0] // k
X_train, y_train = None, None
for j in range(k):
idx = slice(j * fold_size, (j + 1) * fold_size)
X_part, y_part = X[idx, :], y[idx]
if j == i:
X_valid, y_valid = X_part, y_part
elif X_train is None:
X_train, y_train = X_part, y_part
else:
X_train = np.concatenate([X_train, X_part], 0)
y_train = np.concatenate([y_train, y_part], 0)
return X_train, y_train, X_valid, y_valid
Средние значения ошибок обучения и проверки возвращаются, когда мы обучаем K раз в K-кратной перекрестной проверке.
def k_fold(k, X_train, y_train, num_epochs,
learning_rate, weight_decay, batch_size):
train_l_sum, valid_l_sum = 0, 0
for i in range(k):
data = get_k_fold_data(k, i, X_train, y_train)
net = get_net()
train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
weight_decay, batch_size)
train_l_sum += train_ls[-1]
valid_l_sum += valid_ls[-1]
if i == 0:
d2l.plot(list(range(1, num_epochs+1)), [train_ls, valid_ls],
xlabel='epoch', ylabel='rmse',
legend=['train', 'valid'], yscale='log')
print(f'fold {i + 1}, train log rmse {float(train_ls[-1]):f}, '
f'valid log rmse {float(valid_ls[-1]):f}')
return train_l_sum / k, valid_l_sum / k
-
Выбор модели
В этом примере мы выбираем ненастроенный набор гиперпараметров и оставляем читателю возможность улучшить модель. Поиск хорошего выбора может занять время, в зависимости от того, сколько переменных оптимизируется. При достаточно большом наборе данных и обычных гиперпараметрах K-кратная перекрестная проверка имеет тенденцию быть достаточно устойчивой к множественному тестированию. Однако, если мы попробуем