Недавно я играл с машинным обучением на различных облачных платформах, таких как AWS, Google и Azure. В этой статье мы рассмотрим популярное соревнование Kaggle по предсказанию выживания титанических пассажиров. Мы будем использовать SageMaker для решения этой задачи и в процессе изучим основы платформы SageMaker.
Для начала загрузим данные обучения с сайта Kaggle https://www.kaggle.com/c/titanic/data. У него есть два файла, а именно train.csv, содержащий данные обучения, и test.csv для окончательных прогнозов.
Исследовательский анализ данных
Давайте загрузим данные с помощью Pandas и распечатаем пропущенные значения.
train_data = pd.read_csv('train.csv') test_data = pd.read_csv('test.csv') print(train_data.isnull().sum()) print(train_data.head()) PassengerId 0 Survived 0 Pclass 0 Name 0 Sex 0 Age 177 SibSp 0 Parch 0 Ticket 0 Fare 0 Cabin 687 Embarked 2 dtype: int64 Name Sex Age SibSp \ 0 Braund, Mr. Owen Harris male 22.0 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 2 Heikkinen, Miss. Laina female 26.0 0 3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 4 Allen, Mr. William Henry male 35.0 0 Parch Ticket Fare Cabin Embarked 0 0 A/5 21171 7.2500 NaN S 1 0 PC 17599 71.2833 C85 C 2 0 STON/O2. 3101282 7.9250 NaN S 3 0 113803 53.1000 C123 S 4 0 373450 8.0500 NaN S
Мы видим, что есть несколько пропущенных значений для возраста, каюты и посадки. Также обратите внимание, что возраст и стоимость проезда - это значения с плавающей запятой, которые нам нужно преобразовать в целые числа. Для Cabin он начинается с категории, за которой следует номер, поэтому нам нужно избавиться от конечных чисел. Есть несколько функций, которые не имеют отношения к выводу, например имя, идентификатор пассажира и билет, которые мы можем просто отбросить. Теперь, когда у нас есть базовое представление о данных, давайте посмотрим, как мы можем теперь выполнить проектирование функций.
Разработка функций
Для начала избавимся от ненужных функций.
# remove irrelevant feature data train_data.drop(labels=['Name', 'PassengerId', 'Ticket'], axis=1, inplace=True)
В embarked всего 2 недостающих записи, лучше отбросить эти строки, а не заполнять их, так как это не окажет значительного влияния на вывод.
# drop NaN rows for embarked train_data = train_data.dropna(subset=['Embarked'])
Для возраста 177 пропущенных значений, поэтому лучше заменить их средним значением и округлить все значения до целых чисел.
# replace age NaN with mean age mean_age = train_data['Age'].mean() train_data['Age'] = train_data['Age'].fillna(mean_age) # round age train_data['Age'] = train_data['Age'].apply(lambda x : int(x))
Для номера каюты оставим номер и сохраним только категорию. Кроме того, отсутствующие значения заменяются самой большой категорией в наборе данных, которая называется "C".
# extract cabin category train_data['Cabin'] = train_data['Cabin'].apply(lambda x : str(x)[0]) # replace cabin NaN with maximum 'S' train_data['Cabin'] = train_data['Cabin'].apply(lambda x : 'C' if x == 'n' else x)
Округлить тариф до ближайшего целого числа для обработки.
# round fare train_data['Fare'] = train_data['Fare'].apply(lambda x : int(x))
Возраст, каюта и место посадки - это буквенно-цифровые значения, поэтому нам нужно применить кодировку метки для преобразования в целые числа.
# label encode sex, cabin and embarked label_encoder = LabelEncoder() train_data['Sex'] = label_encoder.fit_transform(train_data['Sex']) train_data['Cabin'] = label_encoder.fit_transform(train_data['Cabin']) train_data['Embarked'] = label_encoder.fit_transform(train_data['Embarked'])
Еще одна вещь, которую нам нужно сделать перед сохранением данных, - это переместить целевой столбец на первое место, поскольку это требуется для алгоритма SageMaker XGBoost.
# save and them drop the column survived = train_data['Survived'] train_data.drop(labels=['Survived'], axis=1, inplace=True) # insert target as first column train_data.insert(0, 'Survived', survived)
Наконец, разделите набор данных на обучение, проверку и тестирование и сохраните локально в разных файлах CSV.
train_xgboost, validation_xgboost, test_xgboost = np.split(train_data.sample(frac=1, random_state=1729), [int(0.7 * len(train_data)), int(0.9 * len(train_data))]) # remove header as it is not required by XGBoost train_xgboost.to_csv('train_xgboost.csv', header=False, index=False) validation_xgboost.to_csv('validation_xgboost.csv', header=False, index=False) test_xgboost.to_csv('test_xgboost.csv', header=False, index=False)
Вот и все, теперь мы готовы пройти обучение модели.
Обучение модели
Прежде чем мы начнем, убедитесь, что учетные данные AWS настроены с соответствующими ролями пользователей, которые разрешают доступ к SageMaker и S3.
cat ~/.aws/credentials [default] aws_access_key_id = <your access key id here> aws_secret_access_key = <your secret access key here>
Создайте сеанс SageMaker и загрузите обучающие, проверочные и тестовые CSV-файлы в S3.
sagemaker_session = sagemaker.Session() train_path = sagemaker_session.upload_data(path='train_xgboost.csv', key_prefix='dataset') validation_path = sagemaker_session.upload_data(path='validation_xgboost.csv', key_prefix='dataset') test_path = sagemaker_session.upload_data(path='test.csv', key_prefix='test')
Получите образ контейнера XGBoost.
container = get_image_uri(boto3.Session().region_name, 'xgboost', repo_version='0.90-1')
Создавайте обучающие и проверочные каналы для обучения.
s3_input_train = sagemaker.s3_input(s3_data=train_path, content_type='csv') s3_input_validation = sagemaker.s3_input(s3_data=validation_path, content_type='csv')
Создайте оценщик XGBoost и установите гиперпараметры. Мы используем спотовый инстанс AWS, чтобы сэкономить деньги. Замените роль той, которую вы создали в начале. Также обратите внимание на сегмент и префикс, который используется для указания выходного сегмента для созданной модели.
bucket = 'sagemaker-us-east-1-756448110530' prefix = 'dataset' estimator = sagemaker.estimator.Estimator( container, 'AmazonSageMaker-ExecutionRole-20190815T111389', train_instance_count=1, train_instance_type='ml.m4.2xlarge', output_path='s3://{}/{}/output'.format(bucket, prefix), sagemaker_session=sagemaker_session, train_use_spot_instances=True, train_max_run=120, train_max_wait=180, ) estimator.set_hyperparameters(eta=0.1, objective='binary:logistic', num_round=25, eval_metric='accuracy')
И, наконец, обучите модель.
estimator.fit({ 'train': s3_input_train, 'validation': s3_input_validation })
Посмотрите в журнал на предмет достигнутой точности и вашей экономии с помощью спотового экземпляра. Здесь мы достигли точности проверки 84%, что не идеально, но подходит для этого руководства по демонстрации SageMaker.
[24]#011train-error:0.101286#011validation-error:0.157303#011train-accuracy:0.898714#011validation-accuracy:0.842697 Training seconds: 47 Billable seconds: 17 Managed Spot Training savings: 63.8%
После успешного завершения обучения модель сохраняется в s3: // ‹имя вашего сегмента› / dataset / output / sagemaker-xgboost- ‹отметка времени› / output / model.tar.gz. Это сжатый файл модели с маринованным питоном. В следующем разделе мы увидим, как мы можем использовать эту модель для прогнозирования на локальном компьютере.
Прогноз
Начните с распаковки модели и загрузите ее с помощью pickle. Убедитесь, что вы используете версию XGBoost 0.90 на момент написания этой статьи, которая поддерживается SageMaker. В случае несовпадения версий загрузка модели может завершиться ошибкой.
model = pickle.loads(open('xgboost-model', 'rb').read())
Помните, что у нас есть тестовые данные, сохраненные в файле test.csv. Нам нужно загрузить этот файл и применить те же шаги по проектированию функций, которые мы выполнили выше. В рамках этого урока позвольте мне повторить здесь те же шаги.
# remove irrelevant feature data test_data.drop(labels=['Name', 'Ticket'], axis=1, inplace=True) # extract cabin number test_data['Cabin'] = test_data['Cabin'].apply(lambda x : str(x)[0]) # replace age NaN with mean age mean_age = test_data['Age'].mean() test_data['Age'] = test_data['Age'].fillna(mean_age) # replace fare NaN with mean fare mean_fare = test_data['Fare'].mean() test_data['Fare'] = test_data['Fare'].fillna(mean_age) # round age test_data['Age'] = test_data['Age'].apply(lambda x : int(x)) # round fare test_data['Fare'] = test_data['Fare'].apply(lambda x : int(x)) # label encode sex, cabin and embarked label_encoder = LabelEncoder() test_data['Sex'] = label_encoder.fit_transform(test_data['Sex']) test_data['Cabin'] = label_encoder.fit_transform(test_data['Cabin']) test_data['Embarked'] = label_encoder.fit_transform(test_data['Embarked'])
Для прогнозирования нам нужны входные данные в определенном формате, который XGBoost ожидает, следовательно, скрывает.
test_X = test_data.as_matrix(columns=['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Cabin', 'Embarked']) test_X = xgboost.DMatrix(test_X)
А теперь пора делать прогнозы.
predictions = model.predict(test_X)
Если вы напечатаете прогноз на этом этапе, это будет массив с числами вероятности, которые нам нужно преобразовать либо в 1 для выживших, либо в 0 для мертвых. Мы будем использовать 0,7 в качестве порога, чтобы решить это.
def transform(val): if val > 0.7: return 1 else: return 0 predictions = list(map(transform, predictions))
Наконец, создайте файл отправки, который вы можете загрузить в Kaggle.
submission = pd.DataFrame({ 'PassengerId': test_data['PassengerId'], 'Survived': predictions }) submission.to_csv("submission.csv", index=False)
Отлично, вот и все,
Надеюсь, у вас есть базовый рабочий процесс использования AWS SageMaker для задачи классификации. Чтобы увидеть полный исходный код, посетите мой сайт на github https://github.com/mngaonkar/kaggle-titanic и не стесняйтесь повторно использовать код.
Продолжайте кодировать!