(Контекст) Компания по покупке и торговле криптовалютами Bitso запустила 15 января 2022 года конкурс, в котором нужно угадать цену биткоина на 7 марта того же года, и тот, кто угадает правильно или окажется ближе всего к цене, выиграет не больше и не меньше биткоина.
Чтобы не дать себе увлечься интуицией и, даже зная, что очень трудно или невозможно, в зависимости от того, кого вы спросите, угадать цену биткойна через месяц, я решил применить фреймворк Apple под названием CreateML для разработки модели машинного обучения, чтобы помочь мне, по крайней мере, иметь смутное представление о цене, которую он может иметь, и как повод использовать Swift в Machine Learning.
Хотя Python — очень хороший и полезный язык, правда в том, что Swift, как мне кажется, имеет большой потенциал, который довольно сильно растрачен, я думаю, что известность как «языка разработки приложений Apple» не помогает ему в других областях, как вы, возможно, знаете, с некоторых пор он имеет открытый исходный код и совместим с Windows и Linux, у него также есть бэкенд-фреймворк под названием Vapor, который довольно быстрый, асинхронный, простой в использовании, и из-за его игровой площадки очень легко начать тестирование и игру с кодом, как мы увидим ниже.
Swift также был частью исследований Google по его использованию в Machine Learning, поскольку они интегрировали его с Google Colab и TensorFlow, но я не решаюсь много говорить об этом, поскольку не тестировал его на этой платформе, но это дает доказательства его использования в области Data Science, Некоторые из его преимуществ заключаются в том, что он быстр, отлично управляет памятью, сильно типизирован, прост в изучении, может использоваться в качестве бэкенда, использует fluent как язык шаблонов в html, может использоваться для консоли, мобильных и настольных компьютеров, очень безопасен, поддерживается Apple, подметает, шваброй и моет посуду; талант есть, просто нужно его поддерживать хаха.
В любом случае, поскольку я впервые использовал Swift, мне пришлось прочитать и посмотреть несколько видеороликов с документацией, но ничего действительно сложного, я использовал библиотеку TabularData для обработки и небольшой очистки данных.
Этот видеоролик об исследовании и манипулировании данными очень помог мне понять, что я делаю. И, конечно, сайт hackingswift, который направил меня и дал мне идею.
Я загрузил данные с сайта Nasdaq, файл CSV с датами и ценами закрытия, которые я использовал для линейной регрессии.
В любом случае, без лишних разговоров, вот код, все сделано в Xcode Playground, который, если честно, если я заметил одну или две ошибки, или это из-за того, что мой MacBook 2015 года с intel, как у воина-викинга, а не m2, как сейчас, кажется, вызвал беспокойство, внезапно он не показывал мне результаты или как будто застрял, не застряв, странные вещи, но на самом деле редко (или не так мало).
// Primero importamos las librerías que utilizaremos
import CreateML
import TabularData
import Foundation
// -------------------------------------------------
// Instanciamos CSVReadingOptions, lo usaremos para convertir la fecha de String a Date.
var options = CSVReadingOptions()
// --------------------------------------------------
// Creamos la estrategía para convertir la fecha de String a Date, dependiendo el formato-
// en el que se encuentre en el archivo CSV, en mi caso era MM/DD/YYYY. 01/31/2022.
options.addDateParseStrategy(
Date.ParseStrategy(
format: "(month: .twoDigits)/(day: .twoDigits)/(year: .defaultDigits)",
locale: Locale(identifier: "en_US"),
timeZone: TimeZone(abbreviation: "CST")!
)
)
// --------------------------------------------------
// Aquí leemos los archivos CSV, debemos arrastrar los archivos a la sección Resources,
// de lado izquierdo en la barra de nuextro Xcode.
// En este caso son dos archivos, el que contiene los datos y un segundo que creé con fechas
// de prueba para ver los resultados.
let csvFile = Bundle.main.url(forResource: "HistoricalData", withExtension: "csv")!
let csvPred = Bundle.main.url(forResource: "prediction", withExtension: "csv")!
// --------------------------------------------------
// Creamos nuestro primer DataFrame que usaremos para hacer el modelo de Regresión Líneal
var dataFrame = try DataFrame (
contentsOfCSVFile: csvFile, // Colocamos la variable que contiene nuestro CSV.
columns: ["Fecha","Cerrar/último"], // Indicamos que columnas usaremos de nuestro CSV
types: ["Fecha": .date, "Cerrar/último": .double], // Indicamos el tipo de dato que contienen las columnas.
options: options // Cargamos nuestras opciones para leer correctamente las fechas.
)
// --------------------------------------------------
// Imprimimos nuestro DataFrame para conocer su estructura, como podemos observar
// la columna Fecha es de tipo Date y la columna Cierre es de tipo Double como indicamos
// en la configuración de arriba. Son los datos con los que entrenaremos nuestro modelo.
print(dataFrame)
//┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
//┃ ┃ Fecha ┃ Cierre ┃
//┃ ┃ <Date> ┃ <Double> ┃
//┡━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
//│ 0 │ 2022-01-30 06:00:00 +0000 │ 36,958.5 │
//│ 1 │ 2022-01-29 06:00:00 +0000 │ 38,040.5 │
//│ 2 │ 2022-01-28 06:00:00 +0000 │ 37,844.5 │
//│ 3 │ 2022-01-27 06:00:00 +0000 │ 37,151.3 │
//│ 4 │ 2022-01-26 06:00:00 +0000 │ 35,905.8 │
//│ 5 │ 2022-01-25 06:00:00 +0000 │ 36,391.9 │
//│ 6 │ 2022-01-24 06:00:00 +0000 │ 36,013.2 │
//│ 7 │ 2022-01-23 06:00:00 +0000 │ 35,095.6 │
//│ 8 │ 2022-01-22 06:00:00 +0000 │ 35,245.4 │
//│ 9 │ 2022-01-21 06:00:00 +0000 │ 36,303.9 │
//│ 10 │ 2022-01-20 06:00:00 +0000 │ 38,853.1 │
//│ 11 │ 2022-01-19 06:00:00 +0000 │ 41,929.2 │
//│ 12 │ 2022-01-18 06:00:00 +0000 │ 41,705.1 │
//│ 13 │ 2022-01-17 06:00:00 +0000 │ 42,026.6 │
//│ 14 │ 2022-01-16 06:00:00 +0000 │ 42,721.7 │
//│ 15 │ 2022-01-15 06:00:00 +0000 │ 43,069.7 │
//│ 16 │ 2022-01-14 06:00:00 +0000 │ 42,878.6 │
//│ 17 │ 2022-01-13 06:00:00 +0000 │ 42,747.6 │
//│ 18 │ 2022-01-12 06:00:00 +0000 │ 43,618.7 │
//│ 19 │ 2022-01-11 06:00:00 +0000 │ 42,576.5 │
//┢╍╍╍╍┷╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┷╍╍╍╍╍╍╍╍╍╍┪
//┇ ... ┇
//┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
// Lo mismo que arriba, pero solo para una sola columna.
var dfPred = try DataFrame(
contentsOfCSVFile: csvPred,
columns: ["Fecha"],
types: ["Fecha": .date],
options: options
)
// Las fechas para las que haremos las predicciones de los precios.
//┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
//┃ ┃ Fecha ┃
//┃ ┃ <Date> ┃
//┡━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
//│ 0 │ 2022-03-01 06:00:00 +0000 │
//│ 1 │ 2022-03-02 06:00:00 +0000 │
//│ 2 │ 2022-03-03 06:00:00 +0000 │
//│ 3 │ 2022-03-04 06:00:00 +0000 │
//│ 4 │ 2022-03-05 06:00:00 +0000 │
//│ 5 │ 2022-03-06 06:00:00 +0000 │
//│ 6 │ 2022-03-07 06:00:00 +0000 │<-- Fecha concurso Bitso
//│ 7 │ 2022-03-08 06:00:00 +0000 │
//│ 8 │ 2022-03-09 06:00:00 +0000 │
//│ 9 │ 2022-03-10 06:00:00 +0000 │
//│ 10 │ 2022-03-11 06:00:00 +0000 │
//│ 11 │ 2022-03-12 06:00:00 +0000 │
//└────┴───────────────────────────┘
// --------------------------------------------------
// Usamos la función renameColumn para cambiar el nombre de la columna, tiene muchas otras funciones útiles
// que me recuerda a Pandas para el manejo y transofrmación de datos, en este caso para que sea más simple la lectura de esa columna.
dataFrame.renameColumn("Cerrar/último", to: "Cierre")
// --------------------------------------------------
// Separamos los datos de entrenamiento y prueba
let (trainingData, testingData) = dataFrame.randomSplit(by: 0.8)
// --------------------------------------------------
// Al igual que con CSVReadingOptions, instanciamos ModelParameters para acceder y configurar
// propiedades para generar nuestro modelo.
var params = MLLinearRegressor.ModelParameters()
params.maxIterations = 10000 // Iteramos 10000 para mayor placer (exactitud).
// --------------------------------------------------
// Generamos nuestro modelo con MLLinearRegressor
let btcPricer = try MLLinearRegressor(
trainingData: trainingData.base, // Le pasamos nuestros datos de entrenamiento creados anteriormente.
targetColumn: "Cierre", // Colocamos el nombre de la columna de la que queremos las predicciones (output)
featureColumns: ["Fecha"], // Colocamos el dato que será de entrada (el segundo CSV en este caso), las fechas para que prediga el precio (Cierre)
parameters: params. // Colocamos la variable con los parametros establecidos en la sección anterior.
)
// --------------------------------------------------
// Aquí nos muestra la información de nuestro modelo y su nivel de exactitud
print(btcPricer.description)
//Parameters
//Max Iterations: 10000
//L1 Penalty: 0.0
//L2 Penalty: 0.01
//Step Size: 1.0
//Convergence Threshold: 0.01
//Feature Rescaling: true
//Performance on Training Data
//Max error: 27973.70
//Root mean squared error: 10217.46
//Performance on Validation Data
//Max error: 24645.20
//Root mean squared error: 10218.74
// --------------------------------------------------
// Basicamente lo mismo de arriba, pero resumido.
let evaluationMetrics = btcPricer.evaluation(on: testingData.base)
print(evaluationMetrics.rootMeanSquaredError)
print(evaluationMetrics.maximumError)
// --------------------------------------------------
// La metadata que contendrá nuestro modelo
let metadata = MLModelMetadata(
author: "RigelGC",
shortDescription: "Bitcoin Price Predictor 8000",
version: "1.0"
)
// --------------------------------------------------
// Aquí guardamos nuestro modelo de Machine Learning para hacer predicciones, lo podemos usar con Python
// con la librería CoreMLTools y hacer predicciones desde ahí.
try btcPricer.write(
to: URL(fileURLWithPath: "/Users/rigelgc/Downloads/btcPricer.mlmodel"), // La ruta donde se guardará nuestro archivo *.mlmodel
metadata: metadata // La metadata que generamos anteriormente.
)
// --------------------------------------------------
// Imprimimos nuestra predicción, mandamos llamar btcPricer.Predictions y dentro le pasamos nuestro segundo DataFrame
// Con los datos de entrada, en este caso solo una columna llamada Fechas con las fechas a las cuales quiero hacer la predicción.
print(try btcPricer.predictions(from: dfPred))
// Nos regresa el siguiente resultado para el segundo DataFrame
// con la columna Fecha y sus 12 fechas.
//┏━━━━━━━━━━━━━┓
//┃ Predictions ┃
//┃ <Double> ┃
//┡━━━━━━━━━━━━━┩
//│ 53,086.847 │
//│ 53,140.417 │
//│ 53,193.986 │
//│ 53,247.555 │
//│ 53,301.125 │
//│ 53,354.694 │
//│ 53,408.263 │ 2022-03-07 <-- Fecha concurso Bitso
//│ 53,461.832 │. Para esa Fecha ese es el precio que predice que tendrá.
//│ 53,515.402 │
//│ 53,568.971 │
//│ 53,622.54 │
//│ 53,676.11 │
//└─────────────┘
Теперь представьте, что у вас есть магазин, например, и вы хотите узнать, как будут продаваться определенные товары в течение какого-то месяца или части года, вы можете извлечь информацию из баз данных ваших торговых точек и применить этот же метод для прогнозирования.
Хотя верно, что в этой модели есть много возможностей для улучшения, в качестве первого знакомства с языком и фреймворками Apple она показалась мне очень интересной. Это правда, что он намного проще в использовании, чем TensorFlow или SKLearn или другие на Python, но в последнем автоматизация, на данный момент, проще для многих случаев использования.
В любом случае, я надеюсь, что это небольшое руководство было полезным, еще многому предстоит научиться, самым сложным было преобразование данных хаха и понимание некоторых ситуаций между DataFrame и MLDataTable, что было немного головной болью, но всегда очень интересно 😄.
Приветствую всех.
Bitso — лучшая платформа для приобретения криптовалют в Мексике на данный момент, я оставляю вам ссылку.