Feature Spec interface
Перевод https://tensorflow.rstudio.com/guide/tfdatasets/feature_spec/
В этом руководстве будут рассмотрены основы использования интерфейса feature_spec()
пакета tfdatasets
. Перед прочтением полезно ознакомиться с R interface to TensorFlow Dataset API.
feature_spec()
в R представляет собой дружественный интерфейс к модулю tf.feature_column
в Python, который позволяет задавать преобразования и представления столбцов при работе с табличными данными. Реализация в R выполнена в едином стиле с пакетом recipes
, краткий обзор возможностей которого был рассмотрен в публикации Инфраструктура для обучения моделей на R: rsample и recipes.
Мы будем использовать набор данных hearts
, загрузив его при помощи data(hearts)
.
library(tfdatasets)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
data(hearts)
head(hearts)
## # A tibble: 6 x 14
## age sex cp trestbps chol fbs restecg thalach exang oldpeak slope
## <int> <int> <int> <int> <int> <int> <int> <int> <int> <dbl> <int>
## 1 63 1 1 145 233 1 2 150 0 2.3 3
## 2 67 1 4 160 286 0 2 108 1 1.5 2
## 3 67 1 4 120 229 0 2 129 1 2.6 2
## 4 37 1 3 130 250 0 0 187 0 3.5 3
## 5 41 0 2 130 204 0 2 172 0 1.4 1
## 6 56 1 2 120 236 0 0 178 0 0.8 1
## # ... with 3 more variables: ca <int>, thal <chr>, target <int>
Мы хотим при помощи Keras обучить модель для предсказания целевой переменной, но сначала нужно подготовить данные. Требуется преобразовать категориальные переменные в некоторый набор признаков; как правило, нужно также выполнить нормализацию всех количественных переменных.
Интерфейс feature_spec()
работает с таблицами (data.frame
) или наборами данных tfdatasets
.
ids_train <- sample.int(nrow(hearts),
size = 0.75 * nrow(hearts))
hearts_train <- hearts[ids_train, ]
hearts_test <- hearts[-ids_train, ]
Сперва создадим спецификацию признаков:
spec <- feature_spec(hearts_train, target ~ .)
spec
## -- Feature Spec ---------------------------------------------------------------------------------
## A feature_spec with 0 steps.
## Fitted: FALSE
## -- Steps ----------------------------------------------------------------------------------------
## -- Dense features -------------------------------------------------------------------------------
## Feature spec must be fitted before we can detect the dense features.
class(spec)
## [1] "FeatureSpec" "R6"
После создания спецификации (объект класса "FeatureSpec"
) нужно задать типы переменных. Это реализуется посредством добавления “шагов” к спецификации (“рецепту”):
spec <- spec %>%
step_numeric_column(
all_numeric(), -cp, -restecg, -exang, -sex, -fbs,
normalizer_fn = scaler_standard()
) %>%
step_categorical_column_with_vocabulary_list(thal)
Для определения типов переменных доступны следующие “шаги”:
step_numeric_column()
для количественных переменных. Параметрnormalizer_fn
позволяет задать функцию для преобразования данных, работающую в графе вычислений TensorFlow (то есть она должна состоят из операторов TensorFlow);step_categorical_column_with_vocabulary_list()
для категориальных переменных с фиксированным набором значений. Если не задаватьvocabulary_list
, в качестве списка будут использованы найденные в наборе данных уникальные значения;step_categorical_column_with_hash_bucket()
для категориальных переменных с использованием хеширования;step_categorical_column_with_identity()
для целочисленного кодирования категориальных переменных (label encoding);step_categorical_column_with_vocabulary_file()
- аналогstep_categorical_column_with_vocabulary_list()
для случая, когда набор возможных значений хранится в файле.
Также можно использовать селекторы:
starts_with()
,ends_with()
,matches()
и другие изtidyselect
;all_numeric()
для выбора всех количественных переменных;all_nominal()
для выбора всех категориальных переменных;has_type("float32")
для выбора на основе типа данных TensorFlow.
Готовый “рецепт” выглядит следующим образом:
spec
## -- Feature Spec ---------------------------------------------------------------------------------
## A feature_spec with 8 steps.
## Fitted: FALSE
## -- Steps ----------------------------------------------------------------------------------------
## StepCategoricalColumnWithVocabularyList: thal
## StepNumericColumn: age, trestbps, chol, thalach, oldpeak, slope, ca
## -- Dense features -------------------------------------------------------------------------------
## Feature spec must be fitted before we can detect the dense features.
После указания типов данных можно добавить необходимые преобразования, например, выполнить биннинг количественной переменной age
:
spec <- spec %>%
step_bucketized_column(age,
boundaries = c(18, 25, 30, 35, 40,
45, 50, 55, 60, 65))
Также можно указать способ представления категориальных переменных:
spec <- spec %>%
step_indicator_column(thal) %>%
step_embedding_column(thal, dimension = 2)
Взаимодействия между переменными добавляются при помощи step_crossed_column()
:
spec <- spec %>%
step_crossed_column(thal_and_age = c(thal, bucketized_age),
hash_bucket_size = 1000) %>%
step_indicator_column(thal_and_age)
Отметим, что thal_and_age
является категориальной переменной, поэтому требуется задать ее преобразование в числовой вид. bucketized_age
- имя по умолчанию, заданное для результата применения step_bucketized_column
к переменной age
.
“Рецепт” может быть задан путем объединения в цепочку всех “шагов”:
spec <- feature_spec(hearts_train, target ~ .) %>%
step_numeric_column(
all_numeric(), -cp, -restecg, -exang, -sex, -fbs,
normalizer_fn = scaler_standard()
) %>%
step_categorical_column_with_vocabulary_list(thal) %>%
step_bucketized_column(age,
boundaries = c(18, 25, 30, 35, 40,
45, 50, 55, 60, 65)) %>%
step_indicator_column(thal) %>%
step_embedding_column(thal, dimension = 2) %>%
step_crossed_column(c(thal, bucketized_age),
hash_bucket_size = 10) %>%
step_indicator_column(crossed_thal_bucketized_age)
После создания “рецепта” нужно выполнить оценку параметров заданных в нем преобразований, например, составить список значений категориальных переменных или найти среднее значение и стандартное отклонение для нормализации. Оценка параметров выполняется на всем наборе данных, использованном при создании “рецепта” или переданном в вызов функции fit()
.
spec_prep <- fit(spec)
After preparing we can see the list of dense features that were defined:
str(spec_prep$dense_features())
## List of 11
## $ age :NumericColumn(key='age', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x00000000634198C8>)
## $ trestbps :NumericColumn(key='trestbps', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x0000000063419950>)
## $ chol :NumericColumn(key='chol', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x0000000063419598>)
## $ thalach :NumericColumn(key='thalach', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x00000000634199D8>)
## $ oldpeak :NumericColumn(key='oldpeak', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x0000000063419A60>)
## $ slope :NumericColumn(key='slope', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x0000000063419730>)
## $ ca :NumericColumn(key='ca', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x0000000063419510>)
## $ bucketized_age :BucketizedColumn(source_column=NumericColumn(key='age', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x00000000634198C8>), boundaries=(18.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0))
## $ indicator_thal :IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='thal', vocabulary_list=('1', '2', 'fixed', 'normal', 'reversible'), dtype=tf.string, default_value=-1, num_oov_buckets=0))
## $ embedding_thal :EmbeddingColumn(categorical_column=VocabularyListCategoricalColumn(key='thal', vocabulary_list=('1', '2', 'fixed', 'normal', 'reversible'), dtype=tf.string, default_value=-1, num_oov_buckets=0), dimension=2, combiner='mean', initializer=<tensorflow.python.ops.init_ops.TruncatedNormal>, ckpt_to_load_from=None, tensor_name_in_ckpt=None, max_norm=None, trainable=True)
## $ indicator_crossed_thal_bucketized_age:IndicatorColumn(categorical_column=CrossedColumn(keys=(VocabularyListCategoricalColumn(key='thal', vocabulary_list=('1', '2', 'fixed', 'normal', 'reversible'), dtype=tf.string, default_value=-1, num_oov_buckets=0), BucketizedColumn(source_column=NumericColumn(key='age', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=<function make_python_function.<locals>.python_function at 0x00000000634198C8>), boundaries=(18.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0))), hash_bucket_size=10.0, hash_key=None))
Теперь мы можем создать подходящую модель в Keras. Для этого используем специальный слой layer_dense_features
, который умеет обрабатывать признаки, созданные согласно “рецепту”. Также используется новый входной слой layer_input_from_dataset
для подачи в модель данных из таблицы или набора данных tfdatasets
.
library(keras)
input <- layer_input_from_dataset(hearts_train %>% select(-target))
output <- input %>%
layer_dense_features(dense_features(spec_prep)) %>%
layer_dense(units = 32, activation = "relu") %>%
layer_dense(units = 1, activation = "sigmoid")
model <- keras_model(input, output)
model %>% compile(
loss = loss_binary_crossentropy,
optimizer = "adam",
metrics = "binary_accuracy"
)
Обучение модели:
history <- model %>%
fit(
x = hearts_train %>% select(-target),
y = hearts_train$target,
epochs = 15,
validation_split = 0.2
)
plot(history)
Выполним предсказания для тестовых данных и посчитаем AUC в качестве метрики качества:
hearts_test$pred <- predict(model, hearts_test)
Metrics::auc(hearts_test$target, hearts_test$pred)
## [1] 0.8956602
Комментариев нет:
Отправить комментарий