Результат эксперимента по созданию интеллектуального решения бизнес-аналитики на базе бесплатных сервисов Google.

Многие из нас привыкли думать, что бизнес-аналитика - это то, что используют крупные компании и что создается с помощью инструментов, которые дороги и часто трудны в освоении (хотя есть приятные исключения, такие как Метабаза и Суперсет). В своей статье я хочу показать, что практически каждый может использовать возможности Business Intelligence и даже добавить к нему прогнозную аналитику с помощью общедоступных и бесплатных онлайн-инструментов, таких как Google Colab и Google Data Studio. Развертывание базы данных не требуется. Все данные для анализа и визуализации мы будем хранить в Google Таблицах.

Мы реализуем модель машинного обучения в Google Colab и на основе истории продаж продуктов сможем прогнозировать будущие продажи на несколько месяцев и визуализировать наш прогноз в Google Data Studio.

Мы будем использовать набор данных с информацией о списке продуктов и историей продаж за 12 месяцев для каждого продукта.

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

Загрузить данные

Мы считаем, что все операции делаем в Google Colab. Прежде всего мы воспользуемся модулем kaggle для загрузки необходимого набора данных. Более подробно о модуле и о том, как получить Kaggle API Token, вы можете прочитать по этой ссылке.

Описание набора данных: https://www.kaggle.com/c/online-sales/data.

!pip install kaggle

Поскольку мы используем Google Colab, мы подключимся к Google Drive, чтобы скопировать учетные данные Kaggle.

from google.colab import drive
drive.mount(‘/content/drive/’)

Установите рабочий каталог с сохраненными учетными данными (в нашем случае каталог называется «Colab Notebooks»).

import os
os.chdir(“/content/drive/My Drive/Colab Notebooks”)

Скопируйте учетные данные для Kaggle API.

import os
os.chdir(“/content/drive/My Drive/Colab Notebooks”)

Загрузите набор данных.

!kaggle competitions download -c online-sales

Загрузите набор данных в память и замените нулевые значения нулями.

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
df = pd.read_csv(“TrainingDataset.csv”)
df = df.replace(np.nan, 0, regex=True)

Теперь мы можем предварительно просмотреть наш набор данных.

Мы разделим наш набор данных на обучающую часть (на которой мы будем обучать нашу модель) и тестовую часть (на которой мы будем проверять правильность нашей модели).

from sklearn.model_selection import train_test_split
df_train, df_test = train_test_split(df, test_size=0.2)
print(df_train.shape)
print(df_test.shape)

Исследовательский анализ данных

Давайте визуализируем наши данные. Покажем динамику изменения цен на 10 случайных товаров.

import random
indexes = random.sample(range(len(df)), 10)
df_plot = pd.DataFrame()
for i in indexes:
  df_plot[“product_”+str(i)] = df.iloc[i, 0:12]
df_plot.plot();

Как видим, в большинстве случаев продажи в течение года снижаются.

Подготовить данные

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

Во-первых, мы разделим характеристики продукта и информацию о результатах за месяц.

y_train_real = df_train.iloc[:, 0:12].values
print(y_train_real.shape)
y_test_real = df_test.iloc[:, 0:12].values
print(y_test_real.shape)
x_train_real = df_train.iloc[:, 12:].values
x_test_real = df_test.iloc[:, 12:].values
print(x_train_real.shape)
print(x_test_real.shape)

Масштабируйте значения в одном диапазоне для более точных прогнозов.

from sklearn.preprocessing import MinMaxScaler
#scale datasets
x_scaler = MinMaxScaler()
x_scaler = x_scaler.fit(x_train_real)
x_train = x_scaler.transform(x_train_real)
x_test = x_scaler.transform(x_test_real)
y_scaler = MinMaxScaler()
y_scaler = y_scaler.fit(y_train_real)
y_train = y_scaler.transform(y_train_real)
y_test = y_scaler.transform(y_test_real)

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

Здесь мы создаем списки для обучающих и тестовых данных, каждый список будет содержать 12 трехмерных массивов numpy. Второе измерение для каждого массива будет представлять временные шаги и постепенно увеличивается на 1.

x_train_series = []
x_test_series = []
for k in range(len(y_train[0])):
  x_train_series.append(np.zeros((x_train.shape[0], k+1, x_train.shape[1]+1)))
for k in range(len(y_test[0])):
  x_test_series.append(np.zeros((x_test.shape[0], k+1, x_test.shape[1]+1)))

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

for k in range(len(y_train[0])):
  for i in range(len(x_train)):
    for j in range(k + 1):
      shifted_index = j - 1
      if shifted_index < 0:
        x_train_series[k][i, j] = np.append(x_train[i], 0)
      else:
        x_train_series[k][i, j] = np.append(x_train[i], y_train[i, shifted_index])

Такое же преобразование временных шагов для тестовых данных.

for k in range(len(y_test[0])):
  for i in range(len(x_test)):
    for j in range(k + 1):
      shifted_index = j - 1
      if shifted_index < 0:
        x_test_series[k][i, j] = np.append(x_test[i], 0)
      else:
        x_test_series[k][i, j] = np.append(x_test[i], y_test[i, shifted_index])

Составьте 12 списков с информацией о результатах для TimeSerie, для каждого продукта.

y_train_series = []
y_test_series = []
for k in range(len(y_train[0])):
  y_train_series.append(np.zeros((len(y_train), 1)))
  y_test_series.append(np.zeros((len(y_test), 1)))
 
  
for k in range(len(y_train[0])):
  y_train_series[k] = y_train[:, k].reshape(-1, 1)
  y_test_series[k] = y_test[:, k].reshape(-1, 1)

Построение нейронной сети LSTM

Мы будем использовать сеть с долговременной краткосрочной памятью (LSTM) Рекуррентной нейронной сети (RNN). Вы можете прочитать больше об этих типах NN здесь:

Http://colah.github.io/posts/2015-08-Understanding-LSTMs/

Мы используем фреймворк Keras для глубокого обучения. Наша модель состоит только из одного слоя LSTM с 256 единицами, одного плотного слоя с 128 единицами и плотно связанного выходного слоя с одним нейроном. Мы также добавили один слой Dropout, чтобы избежать переобучения. Модель остается простой и быстрой, но при этом позволяет делать полезные прогнозы.

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
model = Sequential()
model.add(LSTM(256, input_shape=(None, x_train.shape[1]+1)))
model.add(Dropout(0.5))
model.add(Dense(128, activation = "relu"))
model.add(Dense(1))
model.summary()

model.compile(loss='mse', optimizer='rmsprop')

Обучите нашу модель:

for i in range(len(x_train_series)):
  print(i)
  model.fit(x_train_series[i], y_train_series[i], epochs=10, validation_split=0.2)

Оцените модель для прогнозирования результата через несколько месяцев.

for i in range(len(x_test_series)):
  accr = model.evaluate(x_test_series[i], y_test_series[i])
  print("Predicting outcome after {} months. MSE:".format(i), accr)

Функция прогнозирования результатов

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

def predictor(features, history, future):
  '''
  features: list of product features
  history: list with outcome per month
  future: int, number of months to predict outcome
  '''
  if future == 0:
    return history  
  
  p_serie = np.zeros((1, len(history), len(features)+1))  
  
  for j in range(len(history)):
    shifted_index = j - 1
    if shifted_index < 0:
      p_serie[0, j] = np.append(features, 0)
    else:
      p_serie[0, j] = np.append(features, history[shifted_index])
      
  prediction = model.predict(p_serie)    
  
  history.append(prediction[0][0])
  future -= 1  
  
  return predictor(features, history, future)

Мы протестируем нашу функцию на случайном продукте n. Создадим два списка. Первый - с историей результатов за первые m месяцев, второй - с характеристиками продукта.

import random
n = random.choice(range(len(x_test)-1))
m = 6
future = 6
features = x_test[n].tolist()
history = y_test[n, 0:m].tolist()

Постройте результаты прогноза по сравнению с реальными данными

prediction = predictor(features, history, future)
plt.plot(y_scaler.inverse_transform([prediction])[0])
plt.plot(y_scaler.inverse_transform([y_test[n, :m+future]])[0])
plt.title('Predicted and real outcome')
plt.legend(['predicted', 'real'], loc='upper left')
axes = plt.gca()
plt.show()

Как видим, это достаточно точно показало общую тенденцию изменения продаж. Неплохой результат для сравнительно простой модели.

Отображение прогнозов в Google Data Studio

Теперь, когда у нас есть прогнозируемые данные, мы можем отобразить их в Google Data Studio, решении Google Business Intelligence. Одним из преимуществ этого инструмента является то, что его можно бесплатно использовать для создания настраиваемых отчетов и информационных панелей.

Google Data Studio может подключать несколько источников данных для отчетов. Google Таблицы как источник данных подходят для наших целей. Мы сохраним наши прогнозы в виде таблицы Google, и Google Data Studio отобразит данные из нее на панели инструментов. Таким образом, мы можем легко интегрировать Google Colaboratory и Data Studio.

Я не буду подробно объяснять функциональность Google Data Studio. Вы можете узнать об этом в официальной документации https://developers.google.com/datastudio/.

Мы возьмем три случайных продукта, сохраним прогнозы и историю результатов для каждого. Чтобы сохранить наши данные в Google Spreadsheet, мы будем использовать библиотеку gspread.

Нам понадобится клиентский ключ для записи в Google Spreadsheet. Как получить ключ описано здесь https://gspread.readthedocs.io/en/latest/oauth2.html.

!pip install — upgrade oauth2client gspread

Подключитесь к Google Таблицам.

import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('spreadkey.json', scope)
gc = gspread.authorize(credentials)

Составьте списки с реальной и прогнозируемой историей результатов для трех случайных продуктов. В целях тестирования мы используем данные из тестового набора данных, но в реальном сценарии вы можете вставить любые изменения функций продукта в Google Таблицы, загрузить данные из Google Таблиц и сделать прогноз.

real_data = []
predicted_data = []
for i in range(3):
  n = random.choice(range(len(x_test)-1))
  m = 6
  future = 6
  features = x_test[n].tolist()
  history = y_test[n, 0:m].tolist()
  prediction = predictor(features, history, future)
  predicted_data.append(y_scaler.inverse_transform([prediction])[0])
  real_data.append(y_scaler.inverse_transform([y_test[n, :m+future]])[0])

Откройте Google Sheet для сохранения реальных и прогнозируемых данных. У нас есть два листа: «реальный» для реальных данных, «прогнозируемый» для прогнозируемых данных.

ws = gc.open('TrainingDataset2')
ws_predicted = ws.worksheet("predicted")
ws_real = ws.worksheet("real")

Запишите наши реальные и прогнозируемые данные в Google Таблицы. Мы будем писать, начиная со второй строки, оставляя первую строку для имен столбцов (Product1, Product2, Product3).

for j in range(len(real_data)):
  for i in range(len(real_data[0])):
    ws_predicted.update_cell(i+2, j+1, float(predicted_data[j][i]))
    ws_real.update_cell(i+2, j+1, float(real_data[j][i]))
    
    
for i in range(len(real_data[0])):    
    # add index column
    ws_predicted.update_cell(i+2, len(real_data)+1, i)
    ws_real.update_cell(i+2, len(real_data)+1, i)

Просмотрите наши данные в Google Таблицах

ws_real.get_all_records()[6:11]

Поскольку у нас есть Google Таблицы, заполненные реальным и прогнозируемым результатом, теперь мы можем подключить Google Таблицы в качестве источника данных в Google Data Studio.

В Google Data Studio создайте новую панель управления и создайте для нее источник данных. Вы найдете Google Таблицы в списке источников. Добавьте свою таблицу Google в качестве источника данных.

На основе данных из «прогнозируемых» и «реальных» рабочих листов мы можем построить диаграммы, показывающие изменение результатов.

Вот и все! Теперь у вас есть панель управления на базе искусственного интеллекта, на которой отображаются прогнозы будущих результатов!

Вывод

Основная идея этой статьи заключается в том, что бизнес-аналитика даже с некоторыми функциями искусственного интеллекта более доступна, чем мы думаем. Вы можете создавать расширенную аналитику, встраивать предложенные графики в аналитические отчеты и иметь представление как о текущей ситуации, так и о ближайшем будущем. Все изменения, которые вы хотите проверить, можно быстро вставить в Google Таблицы, прогнозируемые последствия будут рассчитаны в Google Colab и показаны в Google Data Studio.

По этой ссылке вы можете найти Блокнот Google Colab со всем описанным кодом.