Оглавление

Метод наименьших квадратов (МНК) в две строчки на Python, scipy, matplotlib

Построение гипотез по методу наименьших квадратов — это, пожалуй, простейшая и наиболее распространённая задача машинного обучения и построения прогнозов.

Здесь я приведу полезные и наиболее употребительные сниппеты для Python. Однако, я хотел бы сделать эту заметку чуть-чуть более полезной, что просто сниппет. Предлагаю решить практическую задачу.

Постановка задачи

Я написал расширение для браузера Chrome, позволяющее слушать радио. Я слежу за статистикой установок и имею данные по количеству пользователей. Накопив определённую статистику, я хочу получить ответы на два простых вопроса:

Чтобы решить эту задачу нам нужна модель. Давайте исходить из того, что зависимость числ пользователей от дня — полиномиальная.

Решение

Переберём пять гипотез:

Вот код:

#!/usr/bin/python
# coding: utf8

import scipy as sp
import matplotlib.pyplot as plt
from scipy.optimize import fsolve

# читаем данные
data = sp.genfromtxt("data.tsv", delimiter="\t")
#print(data[:10]) # часть данных можно напечатать, чтобы убедиться, что всё в порядке

# берём срезы: первую и вторую колонку нашего файла
x = data[:,0]
y = data[:,1]

# настраиваем детали отрисовки графиков
plt.figure(figsize=(8, 6))
plt.title("Installations")
plt.xlabel("Days")
plt.ylabel("Installations")
#plt.xticks([...], [...]) # можно назначить свои тики
plt.autoscale(tight=True)

# рисуем исходные точки
plt.scatter(x, y)

legend = []
# аргументы для построения графиков моделей: исходный интервал + 60 дней
fx = sp.linspace(x[0], x[-1] + 60, 1000)
for d in range(1, 6):
    # получаем параметры модели для полинома степени d
    fp, residuals, rank, sv, rcond = sp.polyfit(x, y, d, full=True)
    #print("Параметры модели: %s" % fp1)
    # функция-полином, если её напечатать, то увидите математическое выражение
    f = sp.poly1d(fp)
    #print(f)
    # рисуем график модельной функции
    plt.plot(fx, f(fx), linewidth=2)
    legend.append("d=%i" % f.order)
    f2 = f - 1000 # из полинома можно вычитать
    t = fsolve(f2, x[-1]) # ищем решение уравнения f2(x)=0, отплясывая от точки x[-1]
    print "Полином %d-й степени:" % f.order
    print "- Мы достигнем 1000 установок через %d дней" % (t[0] - x[-1])
    print "- Через 60 дней у нас будет %d установок" % f(x[-1] + 60)
plt.legend(legend, loc="upper left")
plt.grid()
plt.savefig('data.png', dpi=50)
plt.show()

А вот результат:

Полином 1-й степени:
- Мы достигнем 1000 установок через 462 дней
- Через 60 дней у нас будет 561 установок
Полином 2-й степени:
- Мы достигнем 1000 установок через 368 дней
- Через 60 дней у нас будет 579 установок
Полином 3-й степени:
- Мы достигнем 1000 установок через 166 дней
- Через 60 дней у нас будет 660 установок
Полином 4-й степени:
- Мы достигнем 1000 установок через 57 дней
- Через 60 дней у нас будет 1021 установок
Полином 5-й степени:
- Мы достигнем 1000 установок через 28 дней
- Через 60 дней у нас будет 1692 установок

Мы так же можем взглянуть на графики, построенные с помощью matplotlib.pyplot:

График, построенный с помощью Python matplotlib.pyplot

Здесь хорошо видны примеры и переученности (overfitting) и недоученности (underfitting). Видно, что наиболее реалистичны кривые первой и второй степени. Результаты же, полученные на кривых четвёртой и пятой степеней, скорее всего, обманчивы.