Импортозамещаем numpy, pandas, scipy и sklearn

от автора

Hidden text

Спойлер: это тизер. Конечно же, ни о каком импортозамещении речи нет. Просто мы хайпуем на возросшей волне популярности DA и DS, получаем фан, и при этом пытаемся утилизировать преимущества C++. No cringe, no fear.

О чем говорим?

Речь пойдет о библиотеках-аналогах numpy, pandas, scipy и sklearn на C++ (np, pd, scipy, sklearn соответственно). Эти проекты изначально задумывались как хорошее дополнение к портфолио, однако затем наступило всё более и более плотное вовлечение в процесс работы над ними, челенджи становились всё более и более существенными, и проект превратился в несколько отдельных проектов, содержащих десятки тысяч строк кода.

Предыстория

С момента написания моей прошлой статьи на Хабре прошло 6 лет. Со временем стало понятно, в какой плоскости стоит развиваться дальше бывалому программисту: интересно было бы связать свою карьеру с темой DA/DS, а точнее попробовать поразрабатывать инструменты для дата-аналитиков и датасайентистов.

Мне хотелось не только и не столько попробовать себя собственно в качестве датасайентиста, а более всего пощупать нутрянку многомерных массивов, реализовать слайсы, датафреймы, статистические методы и методы машинного обучения самостоятельно, ощутив на своей шкуре всю прелесть бесконечных челенджей разработчиков библиотек – борьбы за перформанс, юзабилити и функциональность. Потом опять перформанс, юзабилити и функциональность. Потом опять. Цикл “пока не надоест”. И все это на чистом C++.

Цели

Вы спросите: какова цель всего этого мероприятия? Отвечаю:

  • получить фан.

  • принести пользу пользователям и комьюнити.

  • и вообще, у самурая нет цели, есть только путь.

Принципы

  • Использовать оригинальный API соответствующих библиотек, так как миллионы пользователей уже к нему привыкли.

  • Не смотреть оригинальную имплементацию numpy, pandas и т.д. и не использовать идеи оттуда. Все с чистого листа, мы же самураи.

  • Не использовать сторонние библиотеки без крайней на это необходимости, все велосипеды руками (либо ногами).

  • Перформанс, перформанс, перформанс. У нас, у самураев C++, есть возможность затьюнить код так хорошо, как только можно, и этой возможностью нужно пользоваться.

Как и что имплементировать?

Итак, API у нас уже есть. А что же мы делаем в плане имплементации? Очень просто:

  1. Открываем блокнотик любого дата сайентиста. Например, https://github.com/adityakumar529/Coursera_Capstone/blob/master/KNN.ipynb

  2. Идем в каждую ячейку последовательно, сверху вниз, и пытаемся заимплементить соответствующую фичу в верхнеуровневой библиотеке sklearn.

  3. Заимплементили? Мы молодцы. Теперь оказывается, что чего-то нехватает в scipy.

  4. Теперь в pandas.

  5. Теперь в numpy.

  6. If (your grade <= junior developer) {

    goto 2;

    } else {

    // think more. What if implement the most popular features all at once?

    goto 7;

    }

  7. Имплементим сразу много.

  8. goto 2 while not tired, otherwise break

Мы молодцы!

Что уже сделано?

Numpy:

Pandas:

  • Датафреймы с операциями над ними

  • Series с операциями над ними

Scipy:

  • Модальные значения в массивах и датафреймах

Sklearn:

  • KNN на массивах и датафреймах

  • Метрики

  • Методы препроцессинга датасетов

Что в планах?

  • Допиливать sklearn и остальные библиотеки до победного (как минимум до полного имплемента сheatsheet-ов и как максимум для покрытия самых популярных сценариев датасайентистов)

  • Библиотека-аналог pytorch и/или tensorflow. Или что-то совсем другое, но по DL

  • Performance. Рукописные оптимизации под SSE, AVX2, AVX512.

А что же с перформансом?

Не всё так радужно, но мы работаем над этим.

Рассмотрим следующий пример на python (читатель, конечно же, узнал метод Монте-Карло для вычисления числа “пи”):

import numpy as np  size = 100000000  rx = np.random.rand(size) ry = np.random.rand(size)  dist = rx * rx + ry * ry  inside = (dist[dist<1]).size  print ("PI=", 4 * inside / size)

Делаем замеры:

$ time python monte_carlo.py PI= 3.14185536  real 0m2.108s user 0m2.055s sys 0m0.525s

Пример для нашей имплементации:

#include <iostream>  #include <np/Array.hpp>   int main(int, char **) {       using namespace np;       static const constexpr Size size = 100000000;       auto rx = random::rand(size);      auto ry = random::rand(size);       auto dist = rx * rx + ry * ry;       auto inside = (dist["dist<1"]).size();       std::cout << "PI=" << 4 * static_cast<double>(inside) / size;       return 0;  }

Запускаем:

$ time ./monte_carlo  PI=3.14152  real0m2.871s user0m12.610s sys    0m1.184s

Читерство? Читерство. У нас используется OpenMP (поэтому и user time такой) + встроенная векторизация для AVX2, чего нельзя сказать о «ванильном» numpy. Короче говоря, есть над чем работать.

Хотите еще примеров? Их есть у меня!

Пример по мотивам https://github.com/adityakumar529/Coursera_Capstone/blob/master/KNN.ipynb

#include <sklearn/metrics/f1_score.hpp> #include <sklearn/model_selection/train_test_split.hpp> #include <sklearn/neighbors/KNeighborsClassifier.hpp> #include <sklearn/preprocessing/StandardScaler.hpp>  int main(int, char **) {     using namespace pd;     using namespace sklearn::model_selection;     using namespace sklearn::neighbors;     using namespace sklearn::preprocessing;     using namespace sklearn::metrics;      auto data = read_csv("https://raw.githubusercontent.com/adityakumar529/Coursera_Capstone/master/diabetes.csv");     const char *non_zero[] = {"Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI"};     for (const auto &column: non_zero) {         data[column] = data[column].replace(0L, np::NaN);         auto mean = data[column].mean(true);         data[column] = data[column].replace(np::NaN, mean);     }      auto X = data.iloc(":", "0:8");     auto y = data.iloc(":", "8");     auto [X_train, X_test, y_train, y_test] = train_test_split({.X = X, .y = y, .test_size = 0.2, .random_state = 42});      auto sc_X = StandardScaler{};     X_train = sc_X.fit_transform(X_train);     X_test = sc_X.transform(X_test);      auto classifier = KNeighborsClassifier<pd::DataFrame>{{.n_neighbors = 13,                                                            .p = 2,                                                            .metric = sklearn::metrics::DistanceMetricType::kEuclidean}};     classifier.fit(X_train, y_train);     auto y_pred = classifier.predict(X_test);     std::cout << "Prediction: " << y_pred << std::endl;     auto cm = confusion_matrix({.y_true = y_test, .y_pred = y_pred});     std::cout << cm << std::endl;     std::cout << f1_score({.y_true = y_test, .y_pred = y_pred}) << std::endl;     std::cout << accuracy_score(y_test, y_pred) << std::endl;      return 0; }

Вывод примера:

$ ./neighbors_diabetes Prediction: 0 00 10 20 30 41 ... 1491 1500 1510 1520 1531 154 rows x 1 columns  [[85 15]  [19 35]] 0.673077 0.779221

Про перформанс скромно умолчим.

Еще примеры здесь: https://github.com/mgorshkov/sklearn/tree/main/samples

Заключение

Мы сделали краткий обзор библиотек np, pd, scipy, sklearn.

Присоединяйтесь к разработке!

Для желающих поконтрибьютить начинающих разрабов проекты будут хорошим, а главное, совершенно бесплатным, приложением к вашему портфолио, а для желающих все больше и больше фич и их кастомизации дата сайентистов – может быть станут и рабочим инструментом.

Если есть заинтересовавшиеся поконтрибьютить, обращайтесь в личку. Если есть желающие заюзать библиотеку датасайентисты – тоже обращайтесь, кастомизируем проект под ваши нужды.

И еще: кому нужно обучить или зафайнтьюнить свою модель на GPU – обращайтесь. Дам поюзать свою GPU в обмен на возможность ознакомиться с вашим проектом.

Ссылки

C++ numpy-like template-based array implementation: https://github.com/mgorshkov/np

Methods from pandas library on top of NP library: https://github.com/mgorshkov/pd

Scientific methods on top of NP library: https://github.com/mgorshkov/scipy

ML Methods from scikit-learn library: https://github.com/mgorshkov/sklearn

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Как вам мои библиотеки?

25.86% Вау! Круто!15
44.83% Прикольно26
29.31% Отстой17

Проголосовали 58 пользователей. Воздержались 28 пользователей.

ссылка на оригинал статьи https://habr.com/ru/articles/752762/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *