Найти в Дзене
Один Rust не п...Rust

Продуктовая аналитика на Rust с ML

Зависимости (Cargo.toml) [dependencies] rusqlite = { version = "0.29", features = ["bundled"] } csv = "1.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rayon = "1.7" smartcore = "0.2" plotters = "0.3" ureq = "2.6" anyhow = "1.0" Основной код (main.rs) use anyhow::{Result, Context}; use csv::Reader; use rusqlite::{Connection, params}; use serde::{Deserialize, Serialize}; use smartcore::linalg::naive::dense_matrix::DenseMatrix; use smartcore::ensemble::gradient_boosting::GradientBoostingRegressor; use smartcore::cluster::kmeans::KMeans; use rayon::prelude::*; use plotters::prelude::*; use std::fs::File; use std::sync::Mutex; // Структура для данных о продажах #[derive(Debug, Serialize, Deserialize)] struct ProductData { month: f64, sales: f64, price: f64, user_rating: f64, user_id: i32, } // Структура для хранения результатов кластеризации #[derive(Debug)] struct UserCluster { user_id: i32, cluster: usize, } // Инициализация базы данных SQLite fn init_db() -
Оглавление
ML на RUST без заморочек
Один Rust не п...Rust

Способы реализации продуктовой аналитики (ML):

  1. Использование библиотеки tch-rs для работы с нейронными сетями Библиотека tch-rs предоставляет Rust-биндинги к PyTorch, что позволяет использовать возможности глубокого обучения.
    Подходит для обучения и запуска моделей нейронных сетей для задач классификации, регрессии и других аналитических задач.
  2. Применение фреймворка candle для задач ML candle — это фреймворк машинного обучения, полностью написанный на Rust.
    Поддерживает различные алгоритмы и модели, предоставляя удобный API для создания и обучения моделей, что полезно для аналитики данных.
  3. Использование фреймворка burn для глубокого обучения burn — еще один Rust-фреймворк для глубокого обучения, ориентированный на производительность и гибкость.
    Позволяет разрабатывать сложные модели с поддержкой ускорения на GPU.
  4. Интеграция с ort для запуска моделей ONNX ort — это Rust-биндинг к ONNX Runtime, который позволяет запускать модели, обученные на других платформах, в среде Rust.
    Удобен для интеграции готовых моделей в проекты продуктовой аналитики.
  5. Применение rust-bert для анализа текстов rust-bert — библиотека для работы с моделями BERT и другими трансформерными архитектурами на Rust.
    Используется для задач обработки естественного языка, например, анализа текстовых данных в аналитике.
  6. Создание собственных моделей с использованием базовых библиотек С помощью библиотеки ndarray можно работать с многомерными массивами и реализовывать собственные алгоритмы ML с нуля.
    Подходит для специфических задач, требующих высокой производительности или тонкой настройки.
  7. Использование Rust для ETL-процессов Rust идеален для создания быстрых и надежных процессов извлечения, трансформации и загрузки данных (ETL).
    Библиотеки для работы с базами данных и парсинга файлов помогают подготавливать данные для дальнейшего анализа.
  8. Интеграция с существующими инструментами аналитики Rust можно использовать для создания плагинов или расширений для платформ вроде Apache Spark или Hadoop через их API.
    Это позволяет встраивать преимущества Rust в крупные экосистемы аналитики данных.
  9. Разработка веб-сервисов для аналитики Фреймворки actix-web или rocket позволяют создавать веб-сервисы, предоставляющие аналитические данные или результаты ML через API.
    Полезно для интеграции аналитики в продукты или создания новых сервисов.
  10. Анализ данных в реальном времени Благодаря скорости и безопасности, Rust отлично подходит для обработки потоковых данных и предоставления мгновенных аналитических выводов.
    Используется для систем, требующих анализа в реальном времени.

Сбор данных из разных источников, обучение модели

  1. Сбор данных: Чтение данных из CSV-файлов, API и базы данных SQLite.
  2. Обработка данных: Очистка, нормализация, работа с пропущенными значениями и преобразование данных в формат, пригодный для ML.
  3. Машинное обучение:Обучение модели градиентного бустинга для предсказания продаж.
    Кластеризация пользователей с помощью алгоритма K-Means.
  4. Многопоточность: Параллельная обработка данных для повышения производительности.
  5. Хранение данных: Использование SQLite для сохранения промежуточных результатов и моделей.
  6. Визуализация: Генерация графиков с помощью библиотеки plotters.

Зависимости (Cargo.toml)

[dependencies]

rusqlite = { version = "0.29", features = ["bundled"] }

csv = "1.2"

serde = { version = "1.0", features = ["derive"] }

serde_json = "1.0"

rayon = "1.7"

smartcore = "0.2"

plotters = "0.3"

ureq = "2.6"

anyhow = "1.0"

Основной код (main.rs)

use anyhow::{Result, Context};

use csv::Reader;

use rusqlite::{Connection, params};

use serde::{Deserialize, Serialize};

use smartcore::linalg::naive::dense_matrix::DenseMatrix;

use smartcore::ensemble::gradient_boosting::GradientBoostingRegressor;

use smartcore::cluster::kmeans::KMeans;

use rayon::prelude::*;

use plotters::prelude::*;

use std::fs::File;

use std::sync::Mutex;

// Структура для данных о продажах

#[derive(Debug, Serialize, Deserialize)]

struct ProductData {

month: f64,

sales: f64,

price: f64,

user_rating: f64,

user_id: i32,

}

// Структура для хранения результатов кластеризации

#[derive(Debug)]

struct UserCluster {

user_id: i32,

cluster: usize,

}

// Инициализация базы данных SQLite

fn init_db() -> Result<Connection> {

let conn = Connection::open("product_analytics.db")?;

conn.execute(

"CREATE TABLE IF NOT EXISTS product_data (

id INTEGER PRIMARY KEY,

month REAL,

sales REAL,

price REAL,

user_rating REAL,

user_id INTEGER

)",

[],

)?;

conn.execute(

"CREATE TABLE IF NOT EXISTS predictions (

id INTEGER PRIMARY KEY,

month REAL,

predicted_sales REAL

)",

[],

)?;

Ok(conn)

}

// Сбор данных из CSV

fn collect_data_from_csv(path: &str) -> Result<Vec<ProductData>> {

let file = File::open(path)?;

let mut rdr = Reader::from_reader(file);

let mut data = Vec::new();

for result in rdr.deserialize() {

let record: ProductData = result?;

data.push(record);

}

Ok(data)

}

// Сохранение данных в SQLite

fn save_to_db(conn: &Connection, data: &[ProductData]) -> Result<()> {

let mut stmt = conn.prepare(

"INSERT INTO product_data (month, sales, price, user_rating, user_id) VALUES (?, ?, ?, ?, ?)"

)?;

for record in data {

stmt.execute(params![record.month, record.sales, record.price, record.user_rating, record.user_id])?;

}

Ok(())

}

// Обработка данных: нормализация

fn normalize_data(data: &[ProductData]) -> Vec<Vec<f64>> {

let sales: Vec<f64> = data.par_iter().map(|d| d.sales).collect();

let prices: Vec<f64> = data.par_iter().map(|d| d.price).collect();

let ratings: Vec<f64> = data.par_iter().map(|d| d.user_rating).collect();

let max_sales = sales.iter().fold(f64::MIN, |a, &b| a.max(b));

let max_price = prices.iter().fold(f64::MIN, |a, &b| a.max(b));

let max_rating = ratings.iter().fold(f64::MIN, |a, &b| a.max(b));

data.par_iter().map(|d| vec![

d.month,

d.sales / max_sales,

d.price / max_price,

d.user_rating / max_rating,

]).collect()

}

// Обучение модели градиентного бустинга

fn train_gradient_boosting(data: &[ProductData], normalized: Vec<Vec<f64>>) -> Result<GradientBoostingRegressor<f64>> {

let x: Vec<Vec<f64>> = normalized.iter().map(|row| vec![row[0], row[2], row[3]]).collect(); // month, price, rating

let y: Vec<f64> = data.iter().map(|d| d.sales).collect();

let x_matrix = DenseMatrix::from_2d_vec(&x);

let model = GradientBoostingRegressor::fit(&x_matrix, &y, Default::default())?;

Ok(model)

}

// Кластеризация пользователей

fn cluster_users(data: &[ProductData]) -> Result<Vec<UserCluster>> {

let features: Vec<Vec<f64>> = data.iter().map(|d| vec![d.user_rating, d.price]).collect();

let x_matrix = DenseMatrix::from_2d_vec(&features);

let kmeans = KMeans::fit(&x_matrix, &smartcore::cluster::kmeans::KMeansParameters::default().with_k(3))?;

let clusters = kmeans.predict(&x_matrix)?;

let result = data.iter().zip(clusters.iter()).map(|(d, &c)| UserCluster {

user_id: d.user_id,

cluster: c,

}).collect();

Ok(result)

}

// Прогнозирование и сохранение результатов

fn predict_and_save(model: &GradientBoostingRegressor<f64>, conn: &Connection, future_month: f64) -> Result<f64> {

let input = DenseMatrix::from_2d_vec(&vec![vec![future_month, 0.5, 0.8]]); // Пример нормализованных данных

let prediction = model.predict(&input)?[0];

conn.execute("INSERT INTO predictions (month, predicted_sales) VALUES (?, ?)", params![future_month, prediction])?;

Ok(prediction)

}

// Визуализация данных и предсказаний

fn visualize_data(data: &[ProductData], predictions: Vec<(f64, f64)>) -> Result<()> {

let root = BitMapBackend::new("sales_plot.png", (800, 600)).into_drawing_area();

root.fill(&WHITE)?;

let mut chart = ChartBuilder::on(&root)

.caption("Продажи продукта", ("sans-serif", 40).into_font())

.x_label_area_size(30)

.y_label_area_size(40)

.build_cartesian_2d(0f64..15f64, 0f64..2000f64)?;

chart.configure_mesh().draw()?;

// Реальные данные

chart.draw_series(LineSeries::new(

data.iter().map(|d| (d.month, d.sales)),

&BLUE,

))?.label("Реальные продажи").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));

// Предсказания

chart.draw_series(LineSeries::new(

predictions.iter().map(|&(m, s)| (m, s)),

&RED,

))?.label("Предсказанные продажи").legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));

chart.configure_series_labels().draw()?;

root.present()?;

Ok(())

}

fn main() -> Result<()> {

// Инициализация базы данных

let conn = init_db()?;

let conn = Mutex::new(conn);

// Сбор данных

let csv_data = collect_data_from_csv("sales_data.csv").context("Не удалось загрузить данные из CSV")?;

save_to_db(&conn.lock().unwrap(), &csv_data)?;

// Обработка данных

let normalized = normalize_data(&csv_data);

// Обучение модели градиентного бустинга

let model = train_gradient_boosting(&csv_data, normalized.clone())?;

// Кластеризация пользователей

let clusters = cluster_users(&csv_data)?;

println!("Кластеры пользователей: {:?}", clusters);

// Прогнозирование

let future_month = 13.0;

let prediction = predict_and_save(&model, &conn.lock().unwrap(), future_month)?;

println!("Предсказанные продажи на {} месяц: {}", future_month, prediction);

// Визуализация

let predictions = vec![(future_month, prediction)];

visualize_data(&csv_data, predictions)?;

Ok(())

}